[ease: 2/3] Use small pixbuf cache in Image instead of ImageElement.
- From: Nate Stedman <natesm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [ease: 2/3] Use small pixbuf cache in Image instead of ImageElement.
- Date: Sun, 28 Nov 2010 20:51:32 +0000 (UTC)
commit 9749650ce4b37c8631126c56d522f3d71ae05cfd
Author: Nate Stedman <natesm gmail com>
Date: Sun Nov 28 15:38:23 2010 -0500
Use small pixbuf cache in Image instead of ImageElement.
* ImageElement uses Image instead of rolling its own
* Image privately caches a small copy of pixbufs for quick
Cairo rendering.
* Big performance gains when moving things around on slides
with image backgrounds.
ease-core/ease-background.vala | 9 ++-
ease-core/ease-cairo-actor.vala | 2 +-
ease-core/ease-document.vala | 2 +-
ease-core/ease-element.vala | 30 +++------
ease-core/ease-image-element.vala | 51 +++-----------
ease-core/ease-image.vala | 135 ++++++++++++++++++++++++++++---------
ease-core/ease-pdf-actor.vala | 2 +-
ease-core/ease-pdf-element.vala | 7 +-
ease-core/ease-shape-element.vala | 7 +-
ease-core/ease-slide.vala | 45 ++++---------
ease-core/ease-text-element.vala | 3 +-
ease-core/ease-theme.vala | 8 +-
ease-core/ease-video-element.vala | 3 +-
ease/ease-slide-actor.vala | 4 +-
ease/ease-slide-button-panel.vala | 2 +-
ease/ease-welcome-actor.vala | 2 +-
16 files changed, 165 insertions(+), 147 deletions(-)
---
diff --git a/ease-core/ease-background.vala b/ease-core/ease-background.vala
index 56f61ed..6e90c0a 100644
--- a/ease-core/ease-background.vala
+++ b/ease-core/ease-background.vala
@@ -146,7 +146,8 @@ public class Ease.Background : GLib.Object
* @param height The height of the rendering.
* @param path The base path to any possible media files.
*/
- public void set_cairo(Cairo.Context cr, int width, int height, string path)
+ public void set_cairo(Cairo.Context cr, int width, int height, string path,
+ bool use_small)
{
switch (background_type)
{
@@ -157,7 +158,7 @@ public class Ease.Background : GLib.Object
gradient.set_cairo(cr, width, height);
break;
case BackgroundType.IMAGE:
- image.set_cairo(cr, width, height, path);
+ image.set_cairo(cr, width, height, path, use_small);
break;
}
}
@@ -171,10 +172,10 @@ public class Ease.Background : GLib.Object
* @param path The base path to any possible media files.
*/
public void cairo_render(Cairo.Context cr, int width, int height,
- string path) throws GLib.Error
+ string path, bool use_small) throws GLib.Error
{
cr.save();
- set_cairo(cr, width, height, path);
+ set_cairo(cr, width, height, path, use_small);
cr.rectangle(0, 0, width, height);
cr.fill();
cr.restore();
diff --git a/ease-core/ease-cairo-actor.vala b/ease-core/ease-cairo-actor.vala
index 78a1c6d..11c9b6f 100644
--- a/ease-core/ease-cairo-actor.vala
+++ b/ease-core/ease-cairo-actor.vala
@@ -46,7 +46,7 @@ public class Ease.CairoActor : Actor
var cr = tex.create();
try
{
- element.cairo_render(cr);
+ element.cairo_render(cr, false);
}
catch (Error e)
{
diff --git a/ease-core/ease-document.vala b/ease-core/ease-document.vala
index 4549465..1500cc4 100644
--- a/ease-core/ease-document.vala
+++ b/ease-core/ease-document.vala
@@ -499,7 +499,7 @@ public class Ease.Document : GLib.Object, UndoSource
foreach (var itr in slides)
{
slides.get(itr, COL_SLIDE, out s);
- s.cairo_render(context);
+ s.cairo_render(context, false);
context.show_page();
}
diff --git a/ease-core/ease-element.vala b/ease-core/ease-element.vala
index 9777a50..cc28080 100644
--- a/ease-core/ease-element.vala
+++ b/ease-core/ease-element.vala
@@ -182,27 +182,15 @@ public abstract class Ease.Element : GLib.Object, UndoSource
* Renders this Element to a CairoContext.
*
* @param context The context to render to.
- */
- public abstract void cairo_render(Cairo.Context context) throws Error;
-
- /**
- * Renders this Element to a thumbnail-sized CairoContext. The ability to
- * override this method in subclasses allows for optimizations to be
- * performed, preventing slowdown.
- *
- * Especially when dragging Elements around, thumbnails are rapidly redrawn.
- * If an Element subclass uses any potentially large media files, it is a
- * good idea to override this method, cache a low resolution version of the
- * file, and draw with that.
- *
- * If not overriden, this method will simply call { link cairo_render}.
- *
- * @param context The context to render to.
- */
- public virtual void cairo_render_small(Cairo.Context context) throws Error
- {
- cairo_render(context);
- }
+ * @param use_small Especially when dragging Elements around, thumbnails
+ * can be rapidly redrawn. If an Element subclass uses any potentially large
+ * media files, it is a good idea to cache a low resolution version of the
+ * file, and draw with that. For example { link Image} provides this
+ * ability automatically, and it is used in { link Background} (not actually
+ * an Element subclass) and { link ImageElement}.
+ */
+ public abstract void cairo_render(Cairo.Context context,
+ bool use_small) throws Error;
/**
* Instructs subclasses to free any cached data for Cairo rendering.
diff --git a/ease-core/ease-image-element.vala b/ease-core/ease-image-element.vala
index b661bc8..247ff34 100644
--- a/ease-core/ease-image-element.vala
+++ b/ease-core/ease-image-element.vala
@@ -22,34 +22,21 @@
public class Ease.ImageElement : MediaElement
{
private const string UI_FILE_PATH = "inspector-element-image.ui";
- private const int CACHE_SIZE = 100;
-
- private Gdk.Pixbuf small_cache
- {
- get
- {
- if (small_cache_l != null) return small_cache_l;
- var filename = Path.build_path("/", parent.parent.path, filename);
- return small_cache_l = new Gdk.Pixbuf.from_file_at_size(filename,
- CACHE_SIZE,
- CACHE_SIZE);
- }
- set { small_cache_l = value; }
- }
- private Gdk.Pixbuf small_cache_l;
/**
- * Create a new element.
+ * The Image represented by the ImageElement.
*/
- public ImageElement()
+ private Image image;
+
+ construct
{
- signals();
+ image = new Image();
}
public override void signals()
{
base.signals();
- notify["filename"].connect(() => small_cache_l = null);
+ notify["filename"].connect(() => image.filename = filename);
}
internal ImageElement.from_json(Json.Object obj)
@@ -64,7 +51,7 @@ public class Ease.ImageElement : MediaElement
public override void cairo_free_cache()
{
- small_cache = null;
+ image.notify["filename"](null);
}
public override Gtk.Widget inspector_widget()
@@ -135,28 +122,12 @@ public class Ease.ImageElement : MediaElement
/**
* Renders an image Element with Cairo.
*/
- public override void cairo_render(Cairo.Context context) throws Error
- {
- var filename = Path.build_path("/", parent.parent.path, filename);
-
- // load the image
- var pixbuf = new Gdk.Pixbuf.from_file_at_scale(filename,
- (int)width,
- (int)height,
- false);
-
- Gdk.cairo_set_source_pixbuf(context, pixbuf, 0, 0);
- context.rectangle(0, 0, width, height);
- context.fill();
- }
-
- public override void cairo_render_small(Cairo.Context context) throws Error
+ public override void cairo_render(Cairo.Context context,
+ bool use_small) throws Error
{
- var scaled = small_cache.scale_simple((int)width, (int)height,
- Gdk.InterpType.NEAREST);
- Gdk.cairo_set_source_pixbuf(context, scaled, 0, 0);
+ image.set_cairo(context, (int)width, (int)height,
+ parent.parent.path, use_small);
context.rectangle(0, 0, width, height);
- context.scale(40, 40);
context.fill();
}
}
diff --git a/ease-core/ease-image.vala b/ease-core/ease-image.vala
index e0f6eeb..da074b7 100644
--- a/ease-core/ease-image.vala
+++ b/ease-core/ease-image.vala
@@ -33,62 +33,114 @@ public class Ease.Image : GLib.Object
internal ImageFillType fill { get; set; default = ImageFillType.STRETCH; }
/**
+ * The width of the image. This is used internally and is not always valid.
+ */
+ private int img_width;
+
+ /**
+ * The height of the image. This is used internally and is not always valid.
+ */
+ private int img_height;
+
+ /**
+ * Invalidate the cache when the background image changes.
+ */
+ construct
+ {
+ notify["filename"].connect(() => small_cache = null );
+ }
+
+ /**
* Sets up a CairoContext to render this image.
*
* @param cr The context to set up.
* @param width The width of the rendering.
* @param height The height of the rendering.
* @param path The base path to any possible media files.
+ * @param use_small Whether or not to use the small cached version of the
+ * image instead of loading a full sized version.
*/
- public void set_cairo(Cairo.Context cr, int width, int height, string path)
+ public void set_cairo(Cairo.Context cr, int width, int height, string path,
+ bool use_small)
{
+ // TODO: clean this method up, it's bad but it works
try
{
+ // build the full path to the image
string full = Path.build_filename(path, filename);
+
+ // if the small cache isn't loaded, load it
+ if (use_small && small_cache == null)
+ {
+ // load the image at full size to get its width and height
+ var pixbuf = new Gdk.Pixbuf.from_file(full);
+ img_width = pixbuf.width;
+ img_height = pixbuf.height;
+
+ // store the image as a small cached version
+ var h = (int)((float)pixbuf.height / pixbuf.width * CACHE_SIZE);
+ small_cache = pixbuf.scale_simple(CACHE_SIZE, h,
+ Gdk.InterpType.BILINEAR);
+ }
+
+ // use more efficient/low quality interpolation for small previews
+ var interpolation = use_small
+ ? Gdk.InterpType.NEAREST
+ : Gdk.InterpType.BILINEAR;
+
+ // which sized image should be used?
Gdk.Pixbuf pixbuf;
+ if (use_small) pixbuf = small_cache;
+ else pixbuf = new Gdk.Pixbuf.from_file(full);
+
+ // set up the cairo context appropriately for the fill type
switch (fill)
{
- case ImageFillType.STRETCH:
- pixbuf = new Gdk.Pixbuf.from_file_at_scale(full,
- width,
- height,
- false);
- Gdk.cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
+ case ImageFillType.STRETCH:
+ Gdk.cairo_set_source_pixbuf(
+ cr,
+ pixbuf.scale_simple(width, height, interpolation),
+ 0, 0);
break;
+
case ImageFillType.ASPECT:
- pixbuf = new Gdk.Pixbuf.from_file(full);
-
- // get the aspect ratio of both image and drawing area
- var this_aspect = (float)width / height;
+ // get the aspect ratio of the image
+ var img_aspect = ((float)pixbuf.width) / pixbuf.height;
+ var ctx_aspect = ((float)width) / height;
- // set the pixbuf as source
- Gdk.Pixbuf out_pixbuf;
- if (this_aspect > 1) // set the image's height
+ // determine the width and height of pixbuf
+ int px_width, px_height, px_x, px_y;
+ if (ctx_aspect < img_aspect)
{
- out_pixbuf = pixbuf.scale_simple(
- width, (int)(height * this_aspect),
- Gdk.InterpType.BILINEAR);
- Gdk.cairo_set_source_pixbuf(
- cr, out_pixbuf,
- 0,
- (height - out_pixbuf.height) / 2);
+ px_width = (int)(height * (img_aspect));
+ px_height = height;
+ px_x = (width - px_width) / 2;
+ px_y = 0;
}
- else // set the image's width
+ else
{
- out_pixbuf = pixbuf.scale_simple(
- (int)(width / this_aspect), height,
- Gdk.InterpType.BILINEAR);
- Gdk.cairo_set_source_pixbuf(
- cr, out_pixbuf,
- (width - out_pixbuf.width) / 2,
- 0);
+ px_width = width;
+ px_height = (int)(width * (1 / img_aspect));
+ px_x = 0;
+ px_y = (height - px_height) / 2;
}
+
+ // scale and set source
+ Gdk.cairo_set_source_pixbuf(
+ cr,
+ pixbuf.scale_simple(px_width, px_height, interpolation),
+ px_x, px_y);
break;
+
case ImageFillType.ORIGINAL:
- pixbuf = new Gdk.Pixbuf.from_file(full);
+ if (use_small)
+ {
+ pixbuf = small_cache.scale_simple(img_width, img_height,
+ interpolation);
+ }
Gdk.cairo_set_source_pixbuf(cr, pixbuf,
- (width - pixbuf.width) / 2,
- (height - pixbuf.height) / 2);
+ (width - img_width) / 2,
+ (height - img_height) / 2);
break;
}
@@ -98,6 +150,25 @@ public class Ease.Image : GLib.Object
critical("Error rendering image background: %s", e.message);
}
}
+
+ /**
+ * The size of the small copy of the image kept loaded at all times.
+ */
+ private const int CACHE_SIZE = 100;
+
+ /**
+ * A small copy of the image that is kept loaded at all times. This image
+ * is used in the sidebar to keep rendering times fast. Because the sidebar
+ * uses Cairo rendering, the entire slide is redrawn when anything is
+ * changed. The process of loading and rendering large images is slow, so
+ * this made simple tasks such as dragging an image around slow on slides
+ * with image backgrounds.
+ *
+ * As the small cache is used only for Cairo rendering and requires
+ * knowledge of the image's Document's extracted path, it is set manually
+ * in the { link set_cairo} method.
+ */
+ private Gdk.Pixbuf small_cache;
}
internal enum Ease.ImageFillType
diff --git a/ease-core/ease-pdf-actor.vala b/ease-core/ease-pdf-actor.vala
index 83b6e2a..4888f57 100644
--- a/ease-core/ease-pdf-actor.vala
+++ b/ease-core/ease-pdf-actor.vala
@@ -90,7 +90,7 @@ public class Ease.PdfActor : Actor
texture.clear();
var cr = texture.create();
pdf_element.background.cairo_render(cr, (int)width, (int)height,
- element.parent.parent.path);
+ element.parent.parent.path, false);
page.render(cr);
}
}
diff --git a/ease-core/ease-pdf-element.vala b/ease-core/ease-pdf-element.vala
index a96170b..d61f56a 100644
--- a/ease-core/ease-pdf-element.vala
+++ b/ease-core/ease-pdf-element.vala
@@ -90,7 +90,7 @@ public class Ease.PdfElement : MediaElement
var surface = new Cairo.ImageSurface(Cairo.Format.ARGB32,
(int)width, (int)height);
var cr = new Cairo.Context(surface);
- cairo_render(cr);
+ cairo_render(cr, false);
var path = Path.build_filename(dir, exporter.render_index.to_string());
surface.write_to_png(path);
@@ -114,11 +114,12 @@ public class Ease.PdfElement : MediaElement
"\" alt=\"PDF\" />";
}
- public override void cairo_render(Cairo.Context context) throws Error
+ public override void cairo_render(Cairo.Context context,
+ bool use_small) throws Error
{
// render the background
background.cairo_render(context, (int)width, (int)height,
- parent.parent.path);
+ parent.parent.path, use_small);
// get the current page
var page = pdf_doc.get_page(displayed_page);
diff --git a/ease-core/ease-shape-element.vala b/ease-core/ease-shape-element.vala
index a24a0fa..597df97 100644
--- a/ease-core/ease-shape-element.vala
+++ b/ease-core/ease-shape-element.vala
@@ -89,7 +89,7 @@ public class Ease.ShapeElement : CairoElement
var surface = new Cairo.ImageSurface(Cairo.Format.ARGB32,
(int)width, (int)height);
var cr = new Cairo.Context(surface);
- cairo_render(cr);
+ cairo_render(cr, false);
var path = Path.build_filename(dir, exporter.render_index.to_string());
surface.write_to_png(path);
@@ -158,9 +158,10 @@ public class Ease.ShapeElement : CairoElement
*
* @param cr The context to render to.
*/
- public override void cairo_render(Cairo.Context cr)
+ public override void cairo_render(Cairo.Context cr, bool use_small)
{
- background.set_cairo(cr, (int)width, (int)height, parent.parent.path);
+ background.set_cairo(cr, (int)width, (int)height, parent.parent.path,
+ use_small);
switch (shape_type)
{
diff --git a/ease-core/ease-slide.vala b/ease-core/ease-slide.vala
index eb55230..b9ba72e 100644
--- a/ease-core/ease-slide.vala
+++ b/ease-core/ease-slide.vala
@@ -504,55 +504,34 @@ public class Ease.Slide : GLib.Object, UndoSource
*
* @param context The Cairo.Context to draw to.
*/
- public void cairo_render(Cairo.Context context) throws GLib.Error
+ public void cairo_render(Cairo.Context context,
+ bool use_small) throws GLib.Error
{
if (parent == null)
throw new GLib.Error(0, 0, "Slide must have a parent document");
- cairo_render_sized(context, parent.width, parent.height);
+ cairo_render_sized(context, parent.width, parent.height, use_small);
}
/**
- * Draws the Slide to a thumbnail-sized Cairo.Context. Will call
- * { link Element.cairo_render_small} instead of
- * { link Element.cairo_render}.
- *
- * @param context The Cairo.Context to draw to.
- */
- public void cairo_render_small(Cairo.Context context)
- {
- context.save();
- cairo_render_background(context, parent.width, parent.height);
- context.restore();
-
- foreach (var e in elements)
- {
- context.save();
- context.translate(e.x, e.y);
- e.cairo_render_small(context);
- context.restore();
- }
- }
-
- /**
- * Draws the { link Slide} to a Cairo.Context at a specified size.
+ * Draws the slide with Cairo at a specified size.
*
* @param context The Cairo.Context to draw to.
* @param w The width to render at.
* @param h The height to render at.
*/
- public void cairo_render_sized(Cairo.Context context,
- int w, int h) throws GLib.Error
+ public void cairo_render_sized(Cairo.Context context, int w, int h,
+ bool use_small) throws GLib.Error
{
context.save();
- cairo_render_background(context, w, h);
+ cairo_render_background(context, w, h, use_small);
context.restore();
foreach (var e in elements)
{
context.save();
context.translate(e.x, e.y);
- e.cairo_render(context);
+ e.cairo_render(context, use_small);
context.restore();
}
}
@@ -565,10 +544,12 @@ public class Ease.Slide : GLib.Object, UndoSource
* @param h The height to render at.
*/
public void cairo_render_background(Cairo.Context cr,
- int w, int h) throws GLib.Error
+ int w, int h,
+ bool use_small) throws GLib.Error
{
background.cairo_render(cr, w, h,
- parent == null ? theme.path : parent.path);
+ parent == null ? theme.path : parent.path,
+ use_small);
}
/**
@@ -607,7 +588,7 @@ public class Ease.Slide : GLib.Object, UndoSource
var surface = new Cairo.ImageSurface(Cairo.Format.ARGB32,
(int)width, (int)height);
var cr = new Cairo.Context(surface);
- cairo_render(cr);
+ cairo_render(cr, false);
var path = Path.build_filename(
dir, exporter.render_index.to_string());
diff --git a/ease-core/ease-text-element.vala b/ease-core/ease-text-element.vala
index 57f9492..f138403 100644
--- a/ease-core/ease-text-element.vala
+++ b/ease-core/ease-text-element.vala
@@ -234,7 +234,8 @@ public class Ease.TextElement : Element
/**
* Renders a text Element with Cairo.
*/
- public override void cairo_render(Cairo.Context context) throws Error
+ public override void cairo_render(Cairo.Context context,
+ bool use_small) throws Error
{
var t = display_text;
diff --git a/ease-core/ease-theme.vala b/ease-core/ease-theme.vala
index 0a52d78..c30e6ee 100644
--- a/ease-core/ease-theme.vala
+++ b/ease-core/ease-theme.vala
@@ -66,10 +66,10 @@ public class Ease.Theme : GLib.Object
public const string S_IDENTIFIER = "slide-identifier";
// background types
- private const string BACKGROUND_TYPE = "background-type";
- private const string BACKGROUND_TYPE_COLOR = "background-type-color";
- private const string BACKGROUND_TYPE_GRADIENT = "background-type-gradient";
- private const string BACKGROUND_TYPE_IMAGE = "background-type-image";
+ internal const string BACKGROUND_TYPE = "background-type";
+ internal const string BACKGROUND_TYPE_COLOR = "background-type-color";
+ internal const string BACKGROUND_TYPE_GRADIENT = "background-type-gradient";
+ internal const string BACKGROUND_TYPE_IMAGE = "background-type-image";
public const string BACKGROUND = "background";
// text content types
diff --git a/ease-core/ease-video-element.vala b/ease-core/ease-video-element.vala
index 7abbf4c..1ad67cf 100644
--- a/ease-core/ease-video-element.vala
+++ b/ease-core/ease-video-element.vala
@@ -209,7 +209,8 @@ public class Ease.VideoElement : MediaElement
} while (combo.model.iter_next(ref itr));
}
- public override void cairo_render(Cairo.Context context) throws Error
+ public override void cairo_render(Cairo.Context context,
+ bool use_small) throws Error
{
// TODO: something with video frames?
}
diff --git a/ease/ease-slide-actor.vala b/ease/ease-slide-actor.vala
index fbcf088..e264d48 100644
--- a/ease/ease-slide-actor.vala
+++ b/ease/ease-slide-actor.vala
@@ -312,8 +312,10 @@ internal class Ease.SlideActor : Clutter.Group
// render the background
try
{
+ background.clear();
var cr = background.create();
- slide.cairo_render_background(cr, (int)width_px, (int)height_px);
+ slide.cairo_render_background(cr, (int)width_px,
+ (int)height_px, false);
}
catch (GLib.Error e)
{
diff --git a/ease/ease-slide-button-panel.vala b/ease/ease-slide-button-panel.vala
index 2394225..39a27a2 100644
--- a/ease/ease-slide-button-panel.vala
+++ b/ease/ease-slide-button-panel.vala
@@ -188,7 +188,7 @@ internal class Ease.SlideButtonPanel : Gtk.ScrolledWindow
try
{
- slide.cairo_render_small(context);
+ slide.cairo_render(context, width < 100);
}
catch (GLib.Error e)
{
diff --git a/ease/ease-welcome-actor.vala b/ease/ease-welcome-actor.vala
index 5a1250c..a54899e 100644
--- a/ease/ease-welcome-actor.vala
+++ b/ease/ease-welcome-actor.vala
@@ -156,7 +156,7 @@ internal class Ease.WelcomeActor : Clutter.Group
try
{
var slide = create_slide(w, h);
- slide.cairo_render_sized(slide_actor.create(), w, h);
+ slide.cairo_render_sized(slide_actor.create(), w, h, false);
}
catch (GLib.Error e)
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]