Commit 8f35cba8 authored by Jim Nelson's avatar Jim Nelson

Fixed scaled load-and-decode to properly scale images which are re-oriented...

Fixed scaled load-and-decode to properly scale images which are re-oriented and/or have a crop.  Assertions in 
the code guarantee that the pixbuf should not be rescaled once it leaves the pipeline.
parent 4153a882
...@@ -94,8 +94,8 @@ public struct Box { ...@@ -94,8 +94,8 @@ public struct Box {
double x_scale, y_scale; double x_scale, y_scale;
get_dimensions().get_scale_factors(scaled, out x_scale, out y_scale); get_dimensions().get_scale_factors(scaled, out x_scale, out y_scale);
int l = (int) Math.round(left * x_scale); int l = (int) Math.round((double) left * x_scale);
int t = (int) Math.round(top * y_scale); int t = (int) Math.round((double) top * y_scale);
// fix-up to match the scaled dimensions // fix-up to match the scaled dimensions
int r = l + scaled.width - 1; int r = l + scaled.width - 1;
...@@ -107,15 +107,15 @@ public struct Box { ...@@ -107,15 +107,15 @@ public struct Box {
return box; return box;
} }
public Box get_scaled_proportional(Dimensions orig, Dimensions scaled) { public Box get_scaled_similar(Dimensions original, Dimensions scaled) {
double x_scale, y_scale; double x_scale, y_scale;
orig.get_scale_factors(scaled, out x_scale, out y_scale); original.get_scale_factors(scaled, out x_scale, out y_scale);
int l = (int) Math.round(left * x_scale);
int t = (int) Math.round(top * y_scale);
int r = (int) Math.round(right * x_scale);
int b = (int) Math.round(bottom * y_scale);
int l = (int) Math.round((double) left * x_scale);
int t = (int) Math.round((double) top * y_scale);
int r = (int) Math.round((double) right * x_scale);
int b = (int) Math.round((double) bottom * y_scale);
// catch rounding errors // catch rounding errors
if (r >= scaled.width) if (r >= scaled.width)
r = scaled.width - 1; r = scaled.width - 1;
...@@ -314,7 +314,7 @@ public struct Box { ...@@ -314,7 +314,7 @@ public struct Box {
} }
public string to_string() { public string to_string() {
return "%d,%d %d,%d".printf(left, top, right, bottom); return "%d,%d %d,%d (%s)".printf(left, top, right, bottom, get_dimensions().to_string());
} }
private static bool in_zone(double pos, int zone) { private static bool in_zone(double pos, int zone) {
......
...@@ -131,7 +131,7 @@ class SlideshowPage : SinglePhotoPage { ...@@ -131,7 +131,7 @@ class SlideshowPage : SinglePhotoPage {
base.switched_to(); base.switched_to();
// since the canvas might not be ready at this point, start with screen-sized photo // since the canvas might not be ready at this point, start with screen-sized photo
set_pixbuf(thumbnail.get_photo().get_pixbuf(TransformablePhoto.SCREEN)); set_pixbuf(thumbnail.get_photo().get_pixbuf(Scaling.for_screen()));
// start the auto-advance timer // start the auto-advance timer
Timeout.add(CHECK_ADVANCE_MSEC, auto_advance); Timeout.add(CHECK_ADVANCE_MSEC, auto_advance);
...@@ -159,7 +159,7 @@ class SlideshowPage : SinglePhotoPage { ...@@ -159,7 +159,7 @@ class SlideshowPage : SinglePhotoPage {
return false; return false;
Thumbnail next = (Thumbnail) controller.get_next_item(thumbnail); Thumbnail next = (Thumbnail) controller.get_next_item(thumbnail);
next_pixbuf = next.get_photo().get_pixbuf(get_canvas_scale()); next_pixbuf = next.get_photo().get_pixbuf(get_canvas_scaling());
return false; return false;
} }
...@@ -192,7 +192,7 @@ class SlideshowPage : SinglePhotoPage { ...@@ -192,7 +192,7 @@ class SlideshowPage : SinglePhotoPage {
Gdk.Pixbuf pixbuf = next_pixbuf; Gdk.Pixbuf pixbuf = next_pixbuf;
if (pixbuf == null) { if (pixbuf == null) {
warning("Slideshow prefetch was not ready"); warning("Slideshow prefetch was not ready");
pixbuf = thumbnail.get_photo().get_pixbuf(get_canvas_scale()); next_pixbuf = thumbnail.get_photo().get_pixbuf(get_canvas_scaling());
} }
set_pixbuf(pixbuf); set_pixbuf(pixbuf);
...@@ -212,7 +212,7 @@ class SlideshowPage : SinglePhotoPage { ...@@ -212,7 +212,7 @@ class SlideshowPage : SinglePhotoPage {
this.thumbnail = thumbnail; this.thumbnail = thumbnail;
// start with blown-up preview // start with blown-up preview
set_pixbuf(thumbnail.get_photo().get_preview_pixbuf(get_canvas_scale())); set_pixbuf(thumbnail.get_photo().get_preview_pixbuf(get_canvas_scaling()));
// schedule improvement to real photo // schedule improvement to real photo
Idle.add(on_improvement); Idle.add(on_improvement);
...@@ -225,7 +225,7 @@ class SlideshowPage : SinglePhotoPage { ...@@ -225,7 +225,7 @@ class SlideshowPage : SinglePhotoPage {
} }
private bool on_improvement() { private bool on_improvement() {
set_pixbuf(thumbnail.get_photo().get_pixbuf(get_canvas_scale())); set_pixbuf(thumbnail.get_photo().get_pixbuf(get_canvas_scaling()));
return false; return false;
} }
...@@ -655,7 +655,7 @@ public class CollectionPage : CheckerboardPage { ...@@ -655,7 +655,7 @@ public class CollectionPage : CheckerboardPage {
// set up icon using the "first" photo, although Sets are not ordered // set up icon using the "first" photo, although Sets are not ordered
if (icon == null) if (icon == null)
icon = photo.get_preview_pixbuf(AppWindow.DND_ICON_SCALE); icon = photo.get_preview_pixbuf(Scaling.for_best_fit(AppWindow.DND_ICON_SCALE));
debug("Prepared %s for export", file.get_path()); debug("Prepared %s for export", file.get_path());
} }
......
...@@ -100,15 +100,10 @@ public class ThemeLoader { ...@@ -100,15 +100,10 @@ public class ThemeLoader {
return into; return into;
} }
public static Gdk.Pixbuf load_icon(string source_file) { public static Gdk.Pixbuf load_icon(string source_basename) {
populate_theme_params(); populate_theme_params();
Gdk.Pixbuf loaded_pixbuf = null; Gdk.Pixbuf loaded_pixbuf = Resources.get_icon(source_basename, 0);
try {
loaded_pixbuf = new Gdk.Pixbuf.from_file(source_file);
} catch (Error e) {
error("ThemeLoader: load_icon: couldn't read icon data from disk");
}
/* Sweep through the icon image data loaded from disk and determine how many /* Sweep through the icon image data loaded from disk and determine how many
unique colors are in it. We do this with the aid of a HashSet. */ unique colors are in it. We do this with the aid of a HashSet. */
...@@ -210,7 +205,7 @@ public class RGBHistogramManipulator : Gtk.DrawingArea { ...@@ -210,7 +205,7 @@ public class RGBHistogramManipulator : Gtk.DrawingArea {
private RGBHistogram histogram = null; private RGBHistogram histogram = null;
private int left_nub_position = 0; private int left_nub_position = 0;
private int right_nub_position = 255; private int right_nub_position = 255;
private Gdk.Pixbuf nub_pixbuf = ThemeLoader.load_icon("icons/drag_nub.png"); private Gdk.Pixbuf nub_pixbuf = ThemeLoader.load_icon("drag_nub.png");
private bool is_left_nub_tracking = false; private bool is_left_nub_tracking = false;
private bool is_right_nub_tracking = false; private bool is_right_nub_tracking = false;
private int track_start_x = 0; private int track_start_x = 0;
......
...@@ -61,7 +61,16 @@ public struct Dimensions { ...@@ -61,7 +61,16 @@ public struct Dimensions {
public string to_string() { public string to_string() {
return "%dx%d".printf(width, height); return "%dx%d".printf(width, height);
} }
public bool equals(Dimensions dim) {
return (width == dim.width && height == dim.height);
}
// sometimes a pixel or two is okay
public bool approx_equals(Dimensions dim, int fudge = 1) {
return (width - dim.width).abs() <= fudge && (height - dim.height).abs() <= fudge;
}
public Dimensions get_scaled(int scale) { public Dimensions get_scaled(int scale) {
assert(scale > 0); assert(scale > 0);
...@@ -100,11 +109,11 @@ public struct Dimensions { ...@@ -100,11 +109,11 @@ public struct Dimensions {
// TODO: Surely this can be done by examining dimensions to avoid double calculations. // TODO: Surely this can be done by examining dimensions to avoid double calculations.
scaled.width = viewport.width; scaled.width = viewport.width;
double ratio = (double) viewport.width / (double) width; double ratio = (double) viewport.width / (double) width;
scaled.height = (int) ((double) height * ratio); scaled.height = (int) Math.round((double) height * ratio);
if (scaled.height > viewport.height) { if (scaled.height > viewport.height) {
scaled.height = viewport.height; scaled.height = viewport.height;
ratio = (double) viewport.height / (double) height; ratio = (double) viewport.height / (double) height;
scaled.width = (int) ((double) width * ratio); scaled.width = (int) Math.round((double) width * ratio);
} }
assert(scaled.height <= viewport.height); assert(scaled.height <= viewport.height);
...@@ -118,14 +127,25 @@ public struct Dimensions { ...@@ -118,14 +127,25 @@ public struct Dimensions {
get_scale_factors(scaled, out x_scale, out y_scale); get_scale_factors(scaled, out x_scale, out y_scale);
Gdk.Rectangle scaled_rect = Gdk.Rectangle(); Gdk.Rectangle scaled_rect = Gdk.Rectangle();
scaled_rect.x = (int) (rect.x * x_scale); scaled_rect.x = (int) Math.round((double) rect.x * x_scale);
scaled_rect.y = (int) (rect.y * y_scale); scaled_rect.y = (int) Math.round((double) rect.y * y_scale);
scaled_rect.width = (int) (rect.width * x_scale); scaled_rect.width = (int) Math.round((double) rect.width * x_scale);
scaled_rect.height = (int) (rect.height * y_scale); scaled_rect.height = (int) Math.round((double) rect.height * y_scale);
return scaled_rect; return scaled_rect;
} }
// Returns the current dimensions scaled in a similar proportion as the two suppled dimensions
public Dimensions get_scaled_similar(Dimensions original, Dimensions scaled) {
double x_scale, y_scale;
original.get_scale_factors(scaled, out x_scale, out y_scale);
double scale = double.min(x_scale, y_scale);
return Dimensions((int) Math.round((double) width * scale),
(int) Math.round((double) height * scale));
}
public Dimensions get_scaled_by_width(int scale) { public Dimensions get_scaled_by_width(int scale) {
double ratio = (double) scale / (double) width; double ratio = (double) scale / (double) width;
...@@ -159,3 +179,137 @@ public struct Dimensions { ...@@ -159,3 +179,137 @@ public struct Dimensions {
} }
} }
public struct Scaling {
private const int NO_SCALE = 0;
private const int SCREEN = -1;
private ScaleConstraint constraint;
private int scale;
private Dimensions viewport;
private Scaling(ScaleConstraint constraint, int scale, Dimensions viewport) {
this.constraint = constraint;
this.scale = scale;
this.viewport = viewport;
}
public static Scaling for_original() {
return Scaling(ScaleConstraint.ORIGINAL, NO_SCALE, Dimensions());
}
public static Scaling for_screen() {
return Scaling(ScaleConstraint.DIMENSIONS, SCREEN, Dimensions());
}
public static Scaling for_best_fit(int pixels) {
assert(pixels > 0);
return Scaling(ScaleConstraint.DIMENSIONS, pixels, Dimensions());
}
public static Scaling for_viewport(Dimensions viewport) {
assert(viewport.has_area());
return Scaling(ScaleConstraint.DIMENSIONS, NO_SCALE, viewport);
}
public static Scaling for_widget(Gtk.Widget widget) {
Dimensions viewport = Dimensions.for_allocation(widget.allocation);
assert(viewport.has_area());
return Scaling(ScaleConstraint.DIMENSIONS, NO_SCALE, viewport);
}
private static int get_screen_scale() {
Gdk.Screen screen = AppWindow.get_instance().window.get_screen();
return int.max(screen.get_width(), screen.get_height());
}
private int scale_to_pixels() {
if (scale == SCREEN)
return get_screen_scale();
return (scale >= 0) ? scale : 0;
}
public bool is_unscaled() {
return constraint == ScaleConstraint.ORIGINAL;
}
public bool is_best_fit(Dimensions original, out int pixels) {
if (constraint == ScaleConstraint.ORIGINAL || scale == NO_SCALE)
return false;
pixels = scale_to_pixels();
assert(pixels > 0);
return true;
}
public bool is_best_fit_dimensions(Dimensions original, out Dimensions scaled) {
int pixels;
if (!is_best_fit(original, out pixels))
return false;
scaled = original.get_scaled(pixels);
return true;
}
public bool is_for_viewport(Dimensions original, out Dimensions scaled) {
if (constraint == ScaleConstraint.ORIGINAL || scale != NO_SCALE)
return false;
assert(viewport.has_area());
scaled = original.get_scaled_proportional(viewport);
return true;
}
public Dimensions get_scaled_dimensions(Dimensions original) {
if (is_unscaled())
return original;
Dimensions scaled;
if (is_best_fit_dimensions(original, out scaled))
return scaled;
bool is_viewport = is_for_viewport(original, out scaled);
assert(is_viewport);
return scaled;
}
public Gdk.Pixbuf perform_on_pixbuf(Gdk.Pixbuf pixbuf, Gdk.InterpType interp) {
if (is_unscaled())
return pixbuf;
Dimensions pixbuf_dim = Dimensions.for_pixbuf(pixbuf);
int pixels;
if (is_best_fit(pixbuf_dim, out pixels))
return scale_pixbuf(pixbuf, pixels, interp);
Dimensions scaled;
bool is_viewport = is_for_viewport(pixbuf_dim, out scaled);
assert(is_viewport);
return resize_pixbuf(pixbuf, scaled, interp);
}
public string to_string() {
if (constraint == ScaleConstraint.ORIGINAL)
return "scaling: UNSCALED";
else if (scale != NO_SCALE)
return "scaling: best-fit (%d pixels)".printf(scale_to_pixels());
else
return "scaling: viewport %s".printf(viewport.to_string());
}
public bool equals(Scaling scaling) {
return (constraint == scaling.constraint) && (scale == scaling.scale)
&& viewport.equals(scaling.viewport);
}
}
...@@ -359,7 +359,7 @@ public abstract class EditingTool { ...@@ -359,7 +359,7 @@ public abstract class EditingTool {
// //
// Note this this method doesn't need to be returning the "proper" pixbuf on-the-fly (i.e. // Note this this method doesn't need to be returning the "proper" pixbuf on-the-fly (i.e.
// a pixbuf with unsaved tool edits in it). That can be handled in the paint() virtual method. // a pixbuf with unsaved tool edits in it). That can be handled in the paint() virtual method.
public virtual Gdk.Pixbuf? get_display_pixbuf(TransformablePhoto photo) { public virtual Gdk.Pixbuf? get_display_pixbuf(Scaling scaling, TransformablePhoto photo) {
return null; return null;
} }
...@@ -467,7 +467,7 @@ public class CropTool : EditingTool { ...@@ -467,7 +467,7 @@ public class CropTool : EditingTool {
// scale the crop to the scaled photo's size ... the scaled crop is maintained in // scale the crop to the scaled photo's size ... the scaled crop is maintained in
// coordinates not relative to photo's position on canvas // coordinates not relative to photo's position on canvas
scaled_crop = crop.get_scaled_proportional(uncropped_dim, scaled_crop = crop.get_scaled_similar(uncropped_dim,
Dimensions.for_rectangle(canvas.get_scaled_pixbuf_position())); Dimensions.for_rectangle(canvas.get_scaled_pixbuf_position()));
base.activate(canvas); base.activate(canvas);
...@@ -489,11 +489,11 @@ public class CropTool : EditingTool { ...@@ -489,11 +489,11 @@ public class CropTool : EditingTool {
return crop_tool_window; return crop_tool_window;
} }
public override Gdk.Pixbuf? get_display_pixbuf(TransformablePhoto photo) { public override Gdk.Pixbuf? get_display_pixbuf(Scaling scaling, TransformablePhoto photo) {
// show the uncropped photo for editing, but return null if no crop so the current pixbuf // show the uncropped photo for editing, but return null if no crop so the current pixbuf
// is used // is used
return photo.has_crop() ? photo.get_pixbuf(TransformablePhoto.SCREEN, return photo.has_crop() ? photo.get_pixbuf(scaling, TransformablePhoto.Exception.CROP)
TransformablePhoto.Exception.CROP) : null; : null;
} }
private void prepare_gc(Gdk.GC default_gc, Gdk.Drawable drawable) { private void prepare_gc(Gdk.GC default_gc, Gdk.Drawable drawable) {
...@@ -531,10 +531,10 @@ public class CropTool : EditingTool { ...@@ -531,10 +531,10 @@ public class CropTool : EditingTool {
Dimensions uncropped_dim = canvas.get_photo().get_uncropped_dimensions(); Dimensions uncropped_dim = canvas.get_photo().get_uncropped_dimensions();
// rescale to full crop // rescale to full crop
Box crop = scaled_crop.get_scaled_proportional(old_dim, uncropped_dim); Box crop = scaled_crop.get_scaled_similar(old_dim, uncropped_dim);
// rescale back to new size // rescale back to new size
scaled_crop = crop.get_scaled_proportional(uncropped_dim, new_dim); scaled_crop = crop.get_scaled_similar(uncropped_dim, new_dim);
prepare_visuals(scaled); prepare_visuals(scaled);
} }
...@@ -600,7 +600,7 @@ public class CropTool : EditingTool { ...@@ -600,7 +600,7 @@ public class CropTool : EditingTool {
private void on_crop_apply() { private void on_crop_apply() {
// up-scale scaled crop to photo's dimensions // up-scale scaled crop to photo's dimensions
Box crop = scaled_crop.get_scaled_proportional( Box crop = scaled_crop.get_scaled_similar(
Dimensions.for_rectangle(canvas.get_scaled_pixbuf_position()), Dimensions.for_rectangle(canvas.get_scaled_pixbuf_position()),
canvas.get_photo().get_uncropped_dimensions()); canvas.get_photo().get_uncropped_dimensions());
...@@ -1448,8 +1448,8 @@ public class AdjustTool : EditingTool { ...@@ -1448,8 +1448,8 @@ public class AdjustTool : EditingTool {
canvas.paint_pixbuf(draw_to_pixbuf); canvas.paint_pixbuf(draw_to_pixbuf);
} }
public override Gdk.Pixbuf? get_display_pixbuf(TransformablePhoto photo) { public override Gdk.Pixbuf? get_display_pixbuf(Scaling scaling, TransformablePhoto photo) {
return photo.get_pixbuf(TransformablePhoto.SCREEN, TransformablePhoto.Exception.ADJUST); return photo.get_pixbuf(scaling, TransformablePhoto.Exception.ADJUST);
} }
private void on_cancel() { private void on_cancel() {
......
...@@ -19,7 +19,7 @@ public class DirectoryItem : LayoutItem, EventSource { ...@@ -19,7 +19,7 @@ public class DirectoryItem : LayoutItem, EventSource {
assert(photo_id.is_valid()); assert(photo_id.is_valid());
LibraryPhoto photo = LibraryPhoto.fetch(photo_id); LibraryPhoto photo = LibraryPhoto.fetch(photo_id);
Gdk.Pixbuf pixbuf = photo.get_preview_pixbuf(SCALE); Gdk.Pixbuf pixbuf = photo.get_preview_pixbuf(Scaling.for_best_fit(SCALE));
set_image(pixbuf); set_image(pixbuf);
} }
......
...@@ -843,7 +843,7 @@ public class ImportQueuePage : SinglePhotoPage { ...@@ -843,7 +843,7 @@ public class ImportQueuePage : SinglePhotoPage {
} }
private void on_imported(LibraryPhoto photo) { private void on_imported(LibraryPhoto photo) {
set_pixbuf(photo.get_pixbuf(get_canvas_scale())); set_pixbuf(photo.get_pixbuf(get_canvas_scaling()));
progress_bytes += photo.get_filesize(); progress_bytes += photo.get_filesize();
double pct = (progress_bytes <= total_bytes) ? (double) progress_bytes / (double) total_bytes double pct = (progress_bytes <= total_bytes) ? (double) progress_bytes / (double) total_bytes
......
...@@ -226,6 +226,10 @@ public enum Orientation { ...@@ -226,6 +226,10 @@ public enum Orientation {
return dim; return dim;
} }
} }
public Dimensions derotate_dimensions(Dimensions dim) {
return rotate_dimensions(dim);
}
public Gdk.Pixbuf rotate_pixbuf(owned Gdk.Pixbuf pixbuf) { public Gdk.Pixbuf rotate_pixbuf(owned Gdk.Pixbuf pixbuf) {
switch (this) { switch (this) {
...@@ -401,6 +405,7 @@ public enum Orientation { ...@@ -401,6 +405,7 @@ public enum Orientation {
return derotated; return derotated;
} }
// space is the unrotated dimensions the point is rotating with
public Box rotate_box(Dimensions space, Box box) { public Box rotate_box(Dimensions space, Box box) {
Gdk.Point top_left, bottom_right; Gdk.Point top_left, bottom_right;
box.get_points(out top_left, out bottom_right); box.get_points(out top_left, out bottom_right);
...@@ -411,6 +416,7 @@ public enum Orientation { ...@@ -411,6 +416,7 @@ public enum Orientation {
return Box.from_points(top_left, bottom_right); return Box.from_points(top_left, bottom_right);
} }
// space is the unrotated dimensions the point is return to
public Box derotate_box(Dimensions space, Box box) { public Box derotate_box(Dimensions space, Box box) {
Gdk.Point top_left, bottom_right; Gdk.Point top_left, bottom_right;
box.get_points(out top_left, out bottom_right); box.get_points(out top_left, out bottom_right);
......
...@@ -1260,8 +1260,8 @@ public abstract class SinglePhotoPage : Page { ...@@ -1260,8 +1260,8 @@ public abstract class SinglePhotoPage : Page {
return pixmap_dim; return pixmap_dim;
} }
public int get_canvas_scale() { public Scaling get_canvas_scaling() {
return int.max(canvas.allocation.width, canvas.allocation.height); return Scaling.for_widget(viewport);
} }
public Gdk.Pixbuf? get_unscaled_pixbuf() { public Gdk.Pixbuf? get_unscaled_pixbuf() {
...@@ -1378,7 +1378,7 @@ public abstract class SinglePhotoPage : Page { ...@@ -1378,7 +1378,7 @@ public abstract class SinglePhotoPage : Page {
// rescale if canvas rescaled or better quality is requested // rescale if canvas rescaled or better quality is requested
if (scaled == null || interp != repaint_interp) { if (scaled == null || interp != repaint_interp) {
scaled = unscaled.scale_simple(scaled_pos.width, scaled_pos.height, repaint_interp); scaled = resize_pixbuf(unscaled, Dimensions.for_rectangle(scaled_pos), repaint_interp);
UpdateReason reason = UpdateReason.RESIZED_CANVAS; UpdateReason reason = UpdateReason.RESIZED_CANVAS;
if (new_photo) if (new_photo)
......
This diff is collapsed.
...@@ -184,7 +184,7 @@ public abstract class EditingHostPage : SinglePhotoPage { ...@@ -184,7 +184,7 @@ public abstract class EditingHostPage : SinglePhotoPage {
private void quick_update_pixbuf() { private void quick_update_pixbuf() {
// throw a resized large thumbnail up to get an image on the screen quickly, // throw a resized large thumbnail up to get an image on the screen quickly,
// and when ready decode and display the full image // and when ready decode and display the full image
set_pixbuf(photo.get_preview_pixbuf(get_canvas_scale()), false); set_pixbuf(photo.get_preview_pixbuf(get_canvas_scaling()), false);
Idle.add(update_pixbuf); Idle.add(update_pixbuf);
} }
...@@ -192,7 +192,7 @@ public abstract class EditingHostPage : SinglePhotoPage { ...@@ -192,7 +192,7 @@ public abstract class EditingHostPage : SinglePhotoPage {
#if MEASURE_PIPELINE #if MEASURE_PIPELINE
Timer timer = new Timer(); Timer timer = new Timer();
#endif #endif
set_pixbuf(photo.get_pixbuf(get_canvas_scale()), false); set_pixbuf(photo.get_pixbuf(get_canvas_scaling()), false);
#if MEASURE_PIPELINE #if MEASURE_PIPELINE
debug("UPDATE_PIXBUF: total=%lf", timer.elapsed()); debug("UPDATE_PIXBUF: total=%lf", timer.elapsed());
#endif #endif
...@@ -206,7 +206,7 @@ public abstract class EditingHostPage : SinglePhotoPage { ...@@ -206,7 +206,7 @@ public abstract class EditingHostPage : SinglePhotoPage {
} }
private bool fetch_original() { private bool fetch_original() {
original = photo.get_original_pixbuf(get_canvas_scale()); original = photo.get_original_pixbuf(get_canvas_scaling());
return false; return false;
} }
...@@ -259,7 +259,7 @@ public abstract class EditingHostPage : SinglePhotoPage { ...@@ -259,7 +259,7 @@ public abstract class EditingHostPage : SinglePhotoPage {
deactivate_tool(); deactivate_tool();
// see if the tool wants a different pixbuf displayed // see if the tool wants a different pixbuf displayed
Gdk.Pixbuf unscaled = tool.get_display_pixbuf(photo); Gdk.Pixbuf unscaled = tool.get_display_pixbuf(get_canvas_scaling(), photo);
if (unscaled != null) if (unscaled != null)
set_pixbuf(unscaled); set_pixbuf(unscaled);
...@@ -310,7 +310,7 @@ public abstract class EditingHostPage : SinglePhotoPage { ...@@ -310,7 +310,7 @@ public abstract class EditingHostPage : SinglePhotoPage {
// set up icon for drag-and-drop // set up icon for drag-and-drop
try { try {
Gdk.Pixbuf icon = photo.get_preview_pixbuf(AppWindow.DND_ICON_SCALE); Gdk.Pixbuf icon = photo.get_preview_pixbuf(Scaling.for_best_fit(AppWindow.DND_ICON_SCALE));
Gtk.drag_source_set_icon_pixbuf(canvas, icon); Gtk.drag_source_set_icon_pixbuf(canvas, icon);
} catch (Error err) { } catch (Error err) {
message("Unable to get drag-and-drop icon: %s", err.message); message("Unable to get drag-and-drop icon: %s", err.message);
...@@ -631,7 +631,7 @@ public abstract class EditingHostPage : SinglePhotoPage { ...@@ -631,7 +631,7 @@ public abstract class EditingHostPage : SinglePhotoPage {
Gdk.Pixbuf pixbuf = null; Gdk.Pixbuf pixbuf = null;
try { try {
pixbuf = photo.get_pixbuf(1024, TransformablePhoto.Exception.ALL); pixbuf = photo.get_pixbuf(Scaling.for_best_fit(1024), TransformablePhoto.Exception.ALL);
} catch (Error e) { } catch (Error e) {
error("PhotoPage: on_enhance_clicked: couldn't obtain pixbuf to build " + error("PhotoPage: on_enhance_clicked: couldn't obtain pixbuf to build " +
"transform histogram"); "transform histogram");
......
...@@ -48,7 +48,7 @@ public class Thumbnail : LayoutItem, PhotoSource { ...@@ -48,7 +48,7 @@ public class Thumbnail : LayoutItem, PhotoSource {
// only fetch and scale if exposed // only fetch and scale if exposed
if (thumb_exposed) { if (thumb_exposed) {
Gdk.Pixbuf pixbuf = photo.get_thumbnail(scale); Gdk.Pixbuf pixbuf = photo.get_thumbnail(scale);
pixbuf = pixbuf.scale_simple(dim.width, dim.height, LOW_QUALITY_INTERP); pixbuf = resize_pixbuf(pixbuf, dim, LOW_QUALITY_INTERP);
interp = LOW_QUALITY_INTERP; interp = LOW_QUALITY_INTERP;
set_image(pixbuf); set_image(pixbuf);
...@@ -79,12 +79,10 @@ public class Thumbnail : LayoutItem, PhotoSource { ...@@ -79,12 +79,10 @@ public class Thumbnail : LayoutItem, PhotoSource {
Gdk.Pixbuf pixbuf = photo.get_thumbnail(scale); Gdk.Pixbuf pixbuf = photo.get_thumbnail(scale);
// only change pixbufs if indeed the image is scaled ... although // only change pixbufs if indeed the image is scaled
// scale_simple() will probably just return the pixbuf if it sees the stupid case, Gtk.Image Gdk.Pixbuf scaled = resize_pixbuf(pixbuf, dim, HIGH_QUALITY_INTERP);
// does not see the case, and will fire off resized events when the new image (which is not if (scaled != pixbuf) {
// really new) is added pixbuf = scaled;
if ((pixbuf.get_width() != dim.width) || (pixbuf.get_height() != dim.height)) {
pixbuf = pixbuf.scale_simple(dim.width, dim.height, HIGH_QUALITY_INTERP);
set_image(pixbuf); set_image(pixbuf);
} }
......
...@@ -69,7 +69,7 @@ public enum Rotation { ...@@ -69,7 +69,7 @@ public enum Rotation {
} }
Gdk.Pixbuf scale_pixbuf(Gdk.Pixbuf pixbuf, int scale, Gdk.InterpType interp) { Gdk.Pixbuf scale_pixbuf(Gdk.Pixbuf pixbuf, int scale, Gdk.InterpType interp) {
Dimensions original = Dimensions(pixbuf.get_width(), pixbuf.get_height()); Dimensions original = Dimensions.for_pixbuf(pixbuf);
Dimensions scaled = original.get_scaled(scale); Dimensions scaled = original.get_scaled(scale);
if ((original.width == scaled.width) && (original.height == scaled.height)) if ((original.width == scaled.width) && (original.height == scaled.height))
return pixbuf; return pixbuf;
...@@ -77,6 +77,14 @@ Gdk.Pixbuf scale_pixbuf(Gdk.Pixbuf pixbuf, int scale, Gdk.InterpType interp) { ...@@ -77,6 +77,14 @@ Gdk.Pixbuf scale_pixbuf(Gdk.Pixbuf pixbuf, int scale, Gdk.InterpType interp) {
return pixbuf.scale_simple(scaled.width, scaled.height, interp); return pixbuf.scale_simple(scaled.width, scaled.height, interp);
} }
Gdk.Pixbuf resize_pixbuf(Gdk.Pixbuf pixbuf, Dimensions resized, Gdk.InterpType interp) {