[f-spot: 2/40] nuke the old AsyncPixbufLoader, replace by ImageLoader
- From: Stephane Delcroix <sdelcroix src gnome org>
- To: svn-commits-list gnome org
- Subject: [f-spot: 2/40] nuke the old AsyncPixbufLoader, replace by ImageLoader
- Date: Wed, 24 Jun 2009 09:47:52 +0000 (UTC)
commit c127a1649a4618e986f1093c309bc031e889f88a
Author: Stephane Delcroix <stephane delcroix org>
Date: Wed Jun 17 16:09:47 2009 +0200
nuke the old AsyncPixbufLoader, replace by ImageLoader
the new ImageLoader inherits from PixbufLoader and, as such, is single-usage only. It makes it more easy to use.
some FIXME left: fix the CompletePixbuf () in PhotoImageView, load the thumbnail first, handle orientation in ImageView widget
src/AsyncPixbufLoader.cs | 440 -----------------------------------
src/Core.cs | 2 +-
src/ImageLoader.cs | 557 +++++++++++++++++++++++++++++++++++++++++++++
src/Makefile.am | 2 +-
src/PhotoImageView.cs | 24 ++-
src/PhotoLoader.cs | 1 +
src/ThumbnailGenerator.cs | 2 +-
7 files changed, 578 insertions(+), 450 deletions(-)
---
diff --git a/src/Core.cs b/src/Core.cs
index 2bb905b..fa2dcfa 100644
--- a/src/Core.cs
+++ b/src/Core.cs
@@ -273,7 +273,7 @@ namespace FSpot {
if (toplevels.Count == 0) {
Banshee.Kernel.Scheduler.Dispose ();
Core.Database.Dispose ();
- PixbufLoader.Cleanup ();
+ global::PixbufLoader.Cleanup ();
Gtk.Application.Quit ();
System.Environment.Exit (0);
}
diff --git a/src/ImageLoader.cs b/src/ImageLoader.cs
new file mode 100644
index 0000000..7a9a388
--- /dev/null
+++ b/src/ImageLoader.cs
@@ -0,0 +1,557 @@
+//
+// Fspot.ImageLoader.cs
+//
+// Author(s)
+// Larry Ewing <lewing novell com>
+// Stephane Delcroix <sdelcroix novell com>
+//
+// This is free softwae. See COPYING fro details
+//
+
+using Gtk;
+using System;
+using System.IO;
+using System.Runtime.Remoting.Messaging;
+using FSpot.Platform;
+using FSpot.Utils;
+
+namespace FSpot {
+ public class AreaPreparedEventArgs : EventArgs
+ {
+ bool reduced_resolution;
+
+ public bool ReducedResolution {
+ get { return reduced_resolution; }
+ }
+
+ public AreaPreparedEventArgs (bool reduced_resolution) : base ()
+ {
+ this.reduced_resolution = reduced_resolution;
+ }
+ }
+
+ public class AreaUpdatedEventArgs : EventArgs
+ {
+ Gdk.Rectangle area;
+ public Gdk.Rectangle Area {
+ get { return area; }
+ }
+
+ public AreaUpdatedEventArgs (Gdk.Rectangle area) : base ()
+ {
+ this.area = area;
+ }
+ }
+
+ public class ImageLoader : Gdk.PixbufLoader
+ {
+#region public api
+ public ImageLoader () : base ()
+ {
+ }
+
+ public void Load (Uri uri)
+ {
+ using (ImageFile image_file = ImageFile.Create (uri)) {
+ image_stream = image_file.PixbufStream ();
+ }
+ image_stream.BeginRead (buffer, 0, count, HandleReadDone, null);
+ loading = true;
+ }
+
+ new public event EventHandler<AreaUpdatedEventArgs> AreaUpdated;
+ new public event EventHandler<AreaPreparedEventArgs> AreaPrepared;
+ public event EventHandler Completed;
+
+ bool loading = false;
+ public bool Loading {
+ get { return loading; }
+ }
+
+ bool prepared = false;
+ public bool Prepared {
+ get { return prepared; }
+ }
+#endregion
+
+#region event handlers
+ protected override void OnAreaPrepared ()
+ {
+ base.OnAreaPrepared ();
+ prepared = true;
+ EventHandler<AreaPreparedEventArgs> eh = AreaPrepared;
+ if (eh != null)
+ eh (this, new AreaPreparedEventArgs (false));
+ }
+
+ protected override void OnAreaUpdated (int x, int y, int width, int height)
+ {
+ base.OnAreaUpdated (x, y, width, height);
+ EventHandler<AreaUpdatedEventArgs> eh = AreaUpdated;
+ if (eh != null)
+ eh (this, new AreaUpdatedEventArgs (new Gdk.Rectangle (x, y, width, height)));
+ }
+
+ protected virtual void OnCompleted ()
+ {
+ loading = false;
+ EventHandler eh = Completed;
+ if (eh != null)
+ eh (this, EventArgs.Empty);
+ Close ();
+ }
+#endregion
+
+#region private stuffs
+ System.IO.Stream image_stream;
+ const int count = 1 << 16;
+
+ byte [] buffer = new byte [count];
+
+ void HandleReadDone (IAsyncResult ar)
+ {
+ int byte_read = image_stream.EndRead (ar);
+ if (byte_read == 0) {
+ image_stream.Close ();
+ OnCompleted ();
+ return;
+ }
+ Gtk.Application.Invoke (this, new ReadDoneEventArgs (byte_read), HandleReadDoneInMainLoop);
+ }
+
+ void HandleReadDoneInMainLoop (object sender, EventArgs e)
+ {
+ ReadDoneEventArgs rdea = e as ReadDoneEventArgs;
+ int byte_read = rdea.ByteRead;
+
+ if (Write (buffer, (ulong)byte_read)) {
+ image_stream.BeginRead (buffer, 0, count, HandleReadDone, null);
+ } else
+ OnWriteError ();
+ }
+
+ class ReadDoneEventArgs : EventArgs
+ {
+ int byte_read;
+ public int ByteRead {
+ get { return byte_read; }
+ }
+
+ public ReadDoneEventArgs (int byte_read) : base ()
+ {
+ this.byte_read = byte_read;
+ }
+
+ }
+
+ void OnWriteError ()
+ {
+ Console.WriteLine ("error while feeding the pixbufloader!");
+ }
+#endregion
+//
+// StreamWrapper stream;
+// Gdk.PixbufLoader loader;
+// Uri uri;
+// bool area_prepared = false;
+// bool done_reading = false;
+// Gdk.Pixbuf pixbuf;
+// Gdk.Pixbuf thumb;
+// PixbufOrientation orientation;
+//
+// private Gdk.AreaUpdatedHandler au;
+// private System.EventHandler ap;
+// private System.EventHandler ev;
+//
+// byte [] buffer = new byte [1 << 16];
+//
+// public event EventHandler<AreaUpdatedEventArgs> AreaUpdated;
+// public event EventHandler<AreaPreparedEventArgs> AreaPrepared;
+// public event System.EventHandler Done;
+//
+// // If the photo we just loaded has an out of date
+// // thumbnail save a new one
+// bool validate_thumbnail = true;
+//
+// // Limit pass control back to the main loop after
+// // chunk_timeout miliseconds.
+// int chunk_timeout = 75;
+//
+// Delay delay;
+// IAsyncResult result;
+//
+// Gdk.Rectangle damage;
+//
+// public AsyncPixbufLoader ()
+// {
+// delay = new Delay (0, new GLib.IdleHandler (AsyncRead));
+// ap = new System.EventHandler (HandleAreaPrepared);
+// au = new Gdk.AreaUpdatedHandler (HandleAreaUpdated);
+// ev = new System.EventHandler (HandleClosed);
+// }
+//
+// public bool Loading
+// {
+// get { return ! done_reading; }
+// }
+//
+// public bool Prepared
+// {
+// get { return area_prepared; }
+// }
+//
+// public Gdk.Pixbuf Pixbuf {
+// get { return pixbuf; }
+// }
+//
+// public Gdk.PixbufLoader Loader {
+// get { return loader; }
+// }
+//
+// private void FileLoad (ImageFile img)
+// {
+// pixbuf = img.Load ();
+// done_reading = true;
+// if (Done != null)
+// Done (this, System.EventArgs.Empty);
+// }
+//
+// public void Load (Uri uri)
+// {
+// this.uri = uri;
+//
+// delay.Stop ();
+//
+// if (!done_reading)
+// Close ();
+//
+// done_reading = false;
+// area_prepared = false;
+// damage = Gdk.Rectangle.Zero;
+//
+// using (ImageFile img = ImageFile.Create (uri)) {
+// orientation = Accelerometer.GetViewOrientation (img.Orientation);
+//
+// try {
+// PixbufOrientation thumb_orientation = Accelerometer.GetViewOrientation (PixbufOrientation.TopLeft);
+// thumb = ThumbnailFactory.LoadThumbnail (uri);
+// thumb = PixbufUtils.TransformOrientation (thumb, thumb_orientation);
+//
+// if (FSpot.ColorManagement.IsEnabled && !thumb.HasAlpha) {
+// if (img.GetProfile () == null)
+// FSpot.ColorManagement.PhotoImageView.Transform = FSpot.ColorManagement.StandardTransform ();
+// else
+// FSpot.ColorManagement.PhotoImageView.Transform = FSpot.ColorManagement.CreateTransform (thumb, img.GetProfile ());
+// }
+// else
+// FSpot.ColorManagement.PhotoImageView.Transform = null;
+// } catch (System.Exception e) {
+// if (!(e is GLib.GException))
+// Log.DebugException (e);
+// }
+//
+// System.IO.Stream nstream = img.PixbufStream ();
+// if (nstream == null) {
+// FileLoad (img);
+// return;
+// } else
+// stream = new StreamWrapper (nstream);
+//
+// loader = new Gdk.PixbufLoader ();
+// loader.AreaPrepared += ap;
+// loader.AreaUpdated += au;
+// loader.Closed += ev;
+//
+// if (AreaPrepared != null && thumb != null) {
+// pixbuf = thumb;
+// AreaPrepared (this, new AreaPreparedEventArgs (true));
+// }
+//
+// ThumbnailGenerator.Default.PushBlock ();
+// //AsyncIORead (null);
+// if (nstream is IOChannel) {
+// ((IOChannel)nstream).DataReady += IOChannelRead;
+// } else
+// delay.Start ();
+// }
+//
+// }
+//
+// private void LoadToAreaPrepared ()
+// {
+// while (!area_prepared && delay.IsPending)
+// Application.RunIteration ();
+// }
+//
+// public void LoadToDone ()
+// {
+// while (!done_reading && delay.IsPending)
+// Application.RunIteration ();
+// }
+//
+// private void Close () {
+// ThumbnailGenerator.Default.PopBlock ();
+//
+// try {
+// result = null;
+//
+// delay.Stop ();
+// if (loader != null) {
+// loader.AreaPrepared -= ap;
+// loader.AreaUpdated -= au;
+// // this can throw exceptions
+// loader.Close ();
+// }
+// } catch (System.Exception) {
+// //System.Console.WriteLine (e.ToString ());
+// if (pixbuf != null)
+// pixbuf.Dispose ();
+//
+// pixbuf = null;
+// } finally {
+// if (loader != null) {
+// loader.Closed -= ev;
+// loader.Dispose ();
+// }
+//
+// loader = null;
+//
+// if (stream != null)
+// stream.Close ();
+//
+// stream = null;
+// }
+// }
+//
+// private void UpdateListeners ()
+// {
+// Gdk.Rectangle area = damage;
+//
+// if (pixbuf != null && loader.Pixbuf != null && loader.Pixbuf != pixbuf && damage != Gdk.Rectangle.Zero)
+// area = PixbufUtils.TransformAndCopy (loader.Pixbuf, pixbuf, orientation, damage);
+//
+// if (area.Width != 0 && area.Height != 0 && AreaUpdated != null)
+// AreaUpdated (this, new AreaUpdatedEventArgs (area));
+//
+// //System.Console.WriteLine ("orig {0} tform {1}", damage.ToString (), area.ToString ());
+// damage = Gdk.Rectangle.Zero;
+// }
+//
+// private class StreamWrapper {
+// private delegate int ReadDelegate (byte [] buffer, int offset, int count);
+// System.IO.Stream stream;
+//
+// public System.IO.Stream Stream {
+// get { return stream; }
+// }
+//
+// public StreamWrapper (System.IO.Stream stream)
+// {
+// this.stream = stream;
+// }
+//
+// public int Read (byte[] buffer, int offset, int count)
+// {
+// return stream.Read (buffer, offset, count);
+// }
+//
+// public IAsyncResult BeginRead (byte [] buffer, int offset, int count, AsyncCallback cb, object state)
+// {
+// ReadDelegate del = new ReadDelegate (Read);
+// return del.BeginInvoke (buffer, offset, count, cb, state);
+// }
+//
+// public int EndRead (IAsyncResult result)
+// {
+// AsyncResult art = result as AsyncResult;
+// ReadDelegate del = art.AsyncDelegate as ReadDelegate;
+// int i = del.EndInvoke (result);
+// return i;
+// }
+//
+// public void Close ()
+// {
+// stream.Close ();
+// }
+// }
+//
+// private void IOChannelRead (object sender, DataReadEventArgs args)
+// {
+// //Console.WriteLine ("IO read {0}", args.Condition);
+//
+// if ( (System.IO.Stream)sender == stream.Stream)
+// args.Continue = AsyncRead ();
+// else {
+// args.Continue = false;
+// stream.Close ();
+// }
+//
+// return;
+// }
+//
+// private bool AsyncIORead ()
+// {
+// try {
+// if (result == null) {
+// //System.Console.WriteLine ("start read");
+// result = stream.BeginRead (buffer, 0, buffer.Length, AsyncIOEnd, stream);
+// } else {
+// //Console.WriteLine ("not done");
+// UpdateListeners ();
+// }
+// } catch (System.Exception e) {
+// System.Console.WriteLine ("In read got {0}", e);
+// }
+//
+// if (done_reading)
+// delay.Stop ();
+//
+// return ! done_reading;
+// }
+//
+// private void AsyncIOEnd (IAsyncResult iar)
+// {
+// //System.Console.WriteLine ("ioended");
+// if (stream == (StreamWrapper)iar.AsyncState)
+// Gtk.Application.Invoke (ReadDone);
+// }
+//
+// public void ReadDone (object sender, System.EventArgs args)
+// {
+// if (result == null)
+// return;
+//
+// int len = 0;
+// try {
+// len = stream.EndRead (result);
+// //System.Console.WriteLine ("read {0} bytes", len);
+// loader.Write (buffer, (ulong)len);
+// } catch (System.ObjectDisposedException od) {
+// System.Console.WriteLine ("error in endread {0}", od);
+// //delay.Start ();
+// len = -1;
+// } catch (GLib.GException e) {
+// System.Console.WriteLine (e.ToString ());
+// pixbuf = null;
+// len = -1;
+// }
+// result = null;
+//
+// if (len <= 0) {
+// if (loader.Pixbuf == null) {
+// if (pixbuf != null)
+// pixbuf.Dispose ();
+//
+// pixbuf = null;
+// }
+//
+// UpdateListeners ();
+// done_reading = true;
+// Close ();
+// return;
+// }
+// }
+//
+// private bool AsyncRead ()
+// {
+//#if false
+// return AsyncIORead ();
+//#else
+// return NormalRead ();
+//#endif
+// }
+//
+// private bool NormalRead ()
+// {
+// System.DateTime start_time = System.DateTime.Now;
+// System.TimeSpan span = start_time - start_time;
+//
+// do {
+// span = System.DateTime.Now - start_time;
+//
+// int len;
+// try {
+// len = stream.Read (buffer, 0, buffer.Length);
+// loader.Write (buffer, (ulong)len);
+// } catch (Exception) {
+// len = -1;
+// }
+//
+// if (len <= 0) {
+// if (loader.Pixbuf == null) {
+// if (pixbuf != null)
+// pixbuf.Dispose ();
+//
+// pixbuf = null;
+// }
+//
+// UpdateListeners ();
+// done_reading = true;
+// Close ();
+// return false;
+// }
+// } while (!done_reading && span.TotalMilliseconds <= chunk_timeout);
+//
+// UpdateListeners ();
+// return true;
+// }
+//
+// private void HandleAreaPrepared (object sender, System.EventArgs args)
+// {
+// pixbuf = PixbufUtils.TransformOrientation (loader.Pixbuf, orientation, false);
+//
+// if (thumb != null && pixbuf != null)
+// thumb.Composite (pixbuf, 0, 0,
+// pixbuf.Width, pixbuf.Height,
+// 0.0, 0.0,
+// pixbuf.Width/(double)thumb.Width, pixbuf.Height/(double)thumb.Height,
+// Gdk.InterpType.Bilinear, 0xff);
+//
+// if (thumb != null)
+// if (!ThumbnailFactory.ThumbnailIsValid (thumb, uri))
+// FSpot.ThumbnailGenerator.Default.Request (uri, 0, 256, 256);
+//
+// area_prepared = true;
+// if (AreaUpdated != null)
+// AreaPrepared (this, new AreaPreparedEventArgs (false));
+//
+// if (thumb != null)
+// thumb.Dispose ();
+// thumb = null;
+// }
+//
+// private void HandleAreaUpdated (object sender, Gdk.AreaUpdatedArgs args)
+// {
+// Gdk.Rectangle area = new Gdk.Rectangle (args.X, args.Y, args.Width, args.Height);
+//
+// if (damage.Width == 0 || damage.Height == 0)
+// damage = area;
+// else
+// damage = area.Union (damage);
+// }
+//
+// private void HandleClosed (object sender, System.EventArgs args)
+// {
+// // FIXME This should probably queue the
+// // thumbnail regeneration to a worker thread
+// if (validate_thumbnail && done_reading && pixbuf != null) {
+// PhotoLoader.ValidateThumbnail (uri, pixbuf);
+// }
+//
+// if (Done != null)
+// Done (this, System.EventArgs.Empty);
+//
+// ThumbnailGenerator.Default.PopBlock ();
+// }
+//
+// public void Dispose ()
+// {
+// Close ();
+//
+// if (pixbuf != null)
+// pixbuf.Dispose ();
+// }
+ }
+}
+
+
diff --git a/src/Makefile.am b/src/Makefile.am
index 5b41601..11fbcd4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -107,7 +107,6 @@ NULL_PLATFORM_CSDISTFILES = \
$(srcdir)/Platform/Null/WebProxy.cs
F_SPOT_CSDISTFILES = \
- $(srcdir)/AsyncPixbufLoader.cs \
$(srcdir)/BlockProcessor.cs \
$(srcdir)/BitConverter.cs \
$(srcdir)/PhotoArray.cs \
@@ -170,6 +169,7 @@ F_SPOT_CSDISTFILES = \
$(srcdir)/GroupSelector.cs \
$(srcdir)/Accelerometer.cs \
$(srcdir)/Histogram.cs \
+ $(srcdir)/ImageLoader.cs \
$(srcdir)/ImportBackend.cs \
$(srcdir)/ImportCommand.cs \
$(srcdir)/InfoOverlay.cs \
diff --git a/src/PhotoImageView.cs b/src/PhotoImageView.cs
index 4a06136..0df8535 100644
--- a/src/PhotoImageView.cs
+++ b/src/PhotoImageView.cs
@@ -37,12 +37,13 @@ namespace FSpot.Widgets {
FSpot.ColorManagement.PhotoImageView = this;
}
+// ImageLoader loader;
public PhotoImageView (BrowsablePointer item)
{
- loader = new FSpot.AsyncPixbufLoader ();
- loader.AreaUpdated += HandlePixbufAreaUpdated;
- loader.AreaPrepared += HandlePixbufPrepared;
- loader.Done += HandleDone;
+// loader = new ImageLoader ();
+// loader.AreaUpdated += HandlePixbufAreaUpdated;
+// loader.AreaPrepared += HandlePixbufPrepared;
+// loader.Completed += HandleDone;
FSpot.ColorManagement.PhotoImageView = this;
Transform = FSpot.ColorManagement.StandardTransform (); //for preview windows
@@ -74,7 +75,9 @@ namespace FSpot.Widgets {
public Gdk.Pixbuf CompletePixbuf ()
{
- loader.LoadToDone ();
+ //FIXME: this should be an async call
+// while (loader.Loading)
+// Gtk.Application.RunIteration ();
return this.Pixbuf;
}
@@ -131,6 +134,7 @@ namespace FSpot.Widgets {
private void HandlePixbufPrepared (object sender, AreaPreparedEventArgs args)
{
+ ImageLoader loader = sender as ImageLoader;
if (!ShowProgress)
return;
@@ -146,6 +150,8 @@ namespace FSpot.Widgets {
private void HandleDone (object sender, System.EventArgs args)
{
+Log.Warning ("PhotoImageView: loading DONE");
+ ImageLoader loader = sender as ImageLoader;
// FIXME the error hander here needs to provide proper information and we should
// pass the state and the write exception in the args
Gdk.Pixbuf prev = this.Pixbuf;
@@ -206,7 +212,6 @@ namespace FSpot.Widgets {
}
}
- FSpot.AsyncPixbufLoader loader;
private void LoadErrorImage (System.Exception e)
{
@@ -254,6 +259,11 @@ namespace FSpot.Widgets {
try {
if (Item.IsValid) {
System.Uri uri = Item.Current.DefaultVersionUri;
+Log.Warning ("PhotoImageView: Loader.Load");
+ ImageLoader loader = new ImageLoader ();
+ loader.AreaUpdated += HandlePixbufAreaUpdated;
+ loader.AreaPrepared += HandlePixbufPrepared;
+ loader.Completed += HandleDone;
loader.Load (uri);
} else
LoadErrorImage (null);
@@ -391,7 +401,7 @@ namespace FSpot.Widgets {
{
//loader.AreaUpdated -= HandlePixbufAreaUpdated;
//loader.AreaPrepared -= HandlePixbufPrepared;
- loader.Dispose ();
+ //loader.Dispose ();
}
}
}
diff --git a/src/PhotoLoader.cs b/src/PhotoLoader.cs
index 34d0e1b..9ccb62e 100644
--- a/src/PhotoLoader.cs
+++ b/src/PhotoLoader.cs
@@ -4,6 +4,7 @@ using FSpot.Platform;
using FSpot.Utils;
namespace FSpot {
+ [Obsolete ("nuke or rename this")]
public class PhotoLoader {
public PhotoQuery query;
diff --git a/src/ThumbnailGenerator.cs b/src/ThumbnailGenerator.cs
index 12d15a5..9e9b127 100644
--- a/src/ThumbnailGenerator.cs
+++ b/src/ThumbnailGenerator.cs
@@ -13,7 +13,7 @@ using FSpot.Utils;
using FSpot.Platform;
namespace FSpot {
- public class ThumbnailGenerator : PixbufLoader {
+ public class ThumbnailGenerator : global::PixbufLoader {
static public ThumbnailGenerator Default = new ThumbnailGenerator ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]