The Birdfont Source Code


All Repositories / birdfont.git / commit – RSS feed

Speed optimization for rotated background images

These changes was commited to the Birdfont repository Wed, 09 Dec 2015 21:22:35 +0000.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git
author Johan Mattsson <johan.mattsson.m@gmail.com>
Wed, 09 Dec 2015 21:22:35 +0000 (22:22 +0100)
committer Johan Mattsson <johan.mattsson.m@gmail.com>
Wed, 09 Dec 2015 21:22:35 +0000 (22:22 +0100)
commit 815d47d945dd46ef3eba96ce0db7882715563ea5
tree db497d04bf823a9527adf41d34e6c2e4a1fd4b5a
parent 38244fcc0196ec0024ae18a9d29d1420d6defe68
Speed optimization for rotated background images

libbirdfont/BackgroundImage.vala
libbirdfont/BackgroundTool.vala
libbirdfont/ScaledBackgrounds.vala
libbirdfont/ScaledImage.vala
--- a/libbirdfont/BackgroundImage.vala +++ b/libbirdfont/BackgroundImage.vala @@ -29,19 +29,7 @@ public double img_scale_x = 1; public double img_scale_y = 1; - public double img_rotation { - get { - return img_rotation_angle; - } - - set { - scaled = null; - scaled_contrast = null; - img_rotation_angle = value; - } - } - - private double img_rotation_angle = 0; + public double img_rotation = 0; private int size = -1; @@ -60,7 +48,7 @@ public signal void updated (); private ScaledBackgrounds? scaled = null; - private ScaledBackgrounds? scaled_contrast = null; + private ImageSurface? contrast_image = null; public double img_offset_x { get { return img_x + Glyph.xc (); } @@ -365,12 +353,48 @@ } path = (!) png_image.get_path (); + } + + private ScaledBackgrounds get_image () { + return get_scaled_backgrounds (); } + public void preview_img_rotation_from_coordinate (double x, double y) { + double rotation; + ScaledBackgrounds backgounds; + + if (get_img_rotation_from_coordinate (x, y, out rotation)) { + img_rotation = rotation; + backgounds = get_image (); + double view_zoom = MainWindow.get_current_glyph ().view_zoom; + ImageSurface rotated; + + img_rotation = rotation; + + if (!high_contrast) { + rotated = rotate ((ImageSurface) get_padded_image ()); + scaled = new ScaledBackgrounds.single_size (rotated, 1); + } else { + contrast_image = null; + } + } + } + public void set_img_rotation_from_coordinate (double x, double y) { + double rotation; + if (get_img_rotation_from_coordinate (x, y, out rotation)) { + img_rotation = rotation; + scaled = null; + contrast_image = null; + } + } + + public bool get_img_rotation_from_coordinate (double x, double y, out double rotation) { double bcx, bcy; double a, b, c, length; + rotation = 0; + bcx = img_middle_x; bcy = img_middle_y; @@ -379,7 +403,7 @@ c = a * a + b * b; if (c == 0) { - return; + return false; } length = sqrt (fabs (c)); @@ -388,9 +412,8 @@ length = -length; } - img_rotation = (y > bcy) ? acos (a / length) + PI : -acos (a / length) + PI; - - background_image = null; + rotation = (y > bcy) ? acos (a / length) + PI : -acos (a / length) + PI; + return true; } public void set_img_scale (double xs, double ys) { @@ -418,10 +441,6 @@ double image_scale_x, image_scale_y; ScaledBackgrounds backgrounds = get_scaled_backgrounds (); - - if (high_contrast) { - backgrounds = get_contrast_image (); - } if (unlikely (get_img ().status () != Cairo.Status.SUCCESS)) { warning (@"Background image is invalid. (\"$path\")\n"); @@ -432,45 +451,73 @@ image_scale_x = img_scale_x; image_scale_y = img_scale_y; - ScaledBackground scaled; - ScaledBackgroundPart part; + ImageSurface scaled_image; + Context scaled_context; - scaled = backgrounds.get_image (view_zoom * img_scale_x); // FIXME: y + if (!high_contrast) { + ScaledBackground scaled; + ScaledBackgroundPart part; - double part_offset_x = img_offset_x - view_offset_x; - part_offset_x *= view_zoom; - part_offset_x = -part_offset_x; + scaled = backgrounds.get_image (view_zoom * img_scale_x); // FIXME: y - double part_offset_y = img_offset_y - view_offset_y; - part_offset_y *= view_zoom; - part_offset_y = -part_offset_y; - - part = scaled.get_part (part_offset_x, part_offset_y, - allocation.width, allocation.height); + double part_offset_x = img_offset_x - view_offset_x; + part_offset_x *= view_zoom; + part_offset_x = -part_offset_x; - scale_x = view_zoom * image_scale_x; - scale_y = view_zoom * image_scale_y; - - scale_x /= part.get_scale (); - scale_y /= part.get_scale (); - - ImageSurface scaled_image; - Context scaled_context; - - scaled_image = new ImageSurface (Format.ARGB32, allocation.width, allocation.height); - scaled_context = new Context (scaled_image); + double part_offset_y = img_offset_y - view_offset_y; + part_offset_y *= view_zoom; + part_offset_y = -part_offset_y; + + part = scaled.get_part (part_offset_x, part_offset_y, + (int) (allocation.width * view_zoom), (int) (allocation.height * view_zoom)); - scaled_context.scale (scale_x, scale_y); - - double scaled_x = part.offset_x; - double scaled_y = part.offset_y; - - scaled_x += view_zoom * (img_offset_x / scale_x - view_offset_x / scale_x); - scaled_y += view_zoom * (img_offset_y / scale_y - view_offset_y / scale_y); - - scaled_context.set_source_surface (part.get_image (), scaled_x, scaled_y); - scaled_context.paint (); + scale_x = view_zoom * image_scale_x; + scale_y = view_zoom * image_scale_y; + + scale_x /= part.get_scale (); + scale_y /= part.get_scale (); + + scaled_image = new ImageSurface (Format.ARGB32, allocation.width, allocation.height); + + scaled_context = new Context (scaled_image); + scaled_context.scale (scale_x, scale_y); + + double scaled_x = part.offset_x; + double scaled_y = part.offset_y; + + scaled_x += view_zoom * (img_offset_x / scale_x - view_offset_x / scale_x); + scaled_y += view_zoom * (img_offset_y / scale_y - view_offset_y / scale_y); + + scaled_context.set_source_surface (part.get_image (), scaled_x, scaled_y); + scaled_context.paint (); + } else { + ImageSurface contrast = get_contrast_image (); + + image_scale_x = img_scale_x * ((double) size_margin / contrast.get_width ()); + image_scale_y = img_scale_y * ((double) size_margin / contrast.get_height ()); + + scaled_image = new ImageSurface (Format.ARGB32, allocation.width, allocation.height); + Context contrast_context = new Context (scaled_image); + contrast_context.save (); + + contrast_context.set_source_rgba (1, 1, 1, 1); + contrast_context.rectangle (0, 0, allocation.width, allocation.height); + contrast_context.fill (); + + // scale both canvas and image at the same time + scale_x = view_zoom * image_scale_x; + scale_y = view_zoom * image_scale_y; + + contrast_context.scale (scale_x, scale_y); + contrast_context.translate (-view_offset_x / image_scale_x, -view_offset_y / image_scale_y); + + contrast_context.set_source_surface (contrast, img_offset_x / image_scale_x, img_offset_y / image_scale_y); + + contrast_context.paint (); + contrast_context.restore (); + } + // add it cr.save (); cr.set_source_surface (scaled_image, 0, 0); @@ -521,7 +568,11 @@ return sg; } - private ImageSurface rotate (ImageSurface padded_image) { + private ImageSurface rotate (ImageSurface padded_image) { + return rotate_image (padded_image, img_rotation); + } + + public static ImageSurface rotate_image (ImageSurface padded_image, double angle) { ImageSurface s; Context c; @@ -533,12 +584,8 @@ c.save (); - Theme.color (c, "Background 1"); - c.rectangle (0, 0, w, h); - c.fill (); - c.translate (w * 0.5, h * 0.5); - c.rotate (img_rotation); + c.rotate (angle); c.translate (-w * 0.5, -h * 0.5); c.set_source_surface (padded_image, 0, 0); @@ -709,21 +756,20 @@ public void update_background () { background_image = null; - scaled_contrast = null; + contrast_image = null; GlyphCanvas.redraw (); updated (); } - ScaledBackgrounds get_contrast_image () { - if (scaled_contrast == null) { - ImageSurface image = get_contrast_image_surface (); - scaled_contrast = new ScaledBackgrounds (image); + ImageSurface get_contrast_image () { + if (contrast_image == null) { + contrast_image = get_contrast_image_surface (); } - return (!) scaled_contrast; + return (!) contrast_image; } - + ImageSurface get_contrast_image_surface () { ImageSurface s; Context c; @@ -748,6 +794,7 @@ s = new ImageSurface (Format.RGB24, scaled_width, scaled_width); sg = (ImageSurface) get_padded_image (); + sg = rotate (sg); c = new Context (s); c.save (); @@ -833,7 +880,7 @@ return pl; } - img = get_contrast_image ().get_image (1).get_image (); + img = get_contrast_image (); w = img.get_width(); h = img.get_height(); @@ -1214,7 +1261,7 @@ ImageSurface img; double simplification = DrawingTools.auto_trace_simplify.get_value (); - img = get_contrast_image ().get_image (1).get_image (); + img = get_contrast_image (); image_scale_x = ((double) size_margin / img.get_width ()); image_scale_y = ((double) size_margin / img.get_height ());
--- a/libbirdfont/BackgroundTool.vala +++ b/libbirdfont/BackgroundTool.vala @@ -21,6 +21,9 @@ double begin_x = 0; double begin_y = 0; + int last_x; + int last_y; + public double img_offset_x = 0; public double img_offset_y = 0; @@ -78,20 +81,33 @@ img_height = background.get_img ().get_height () * background.img_scale_y; move_bg = true; + + last_x = x; + last_y = y; }); release_action.connect((self, b, x, y) => { Glyph g = MainWindow.get_current_glyph (); BackgroundImage? bg = g.get_background_image (); + double coordinate_x, coordinate_y; if (bg == null) { return; } - img_offset_x = ((!)bg).img_offset_x; - img_offset_y = ((!)bg).img_offset_y; + BackgroundImage background = (!) bg; + + coordinate_x = Glyph.path_coordinate_x (x); + coordinate_y = Glyph.path_coordinate_y (y); + + if (background.selected_handle == 2) { + background.set_img_rotation_from_coordinate (coordinate_x, coordinate_y); + } + + img_offset_x = background.img_offset_x; + img_offset_y = background.img_offset_y; - ((!)bg).handler_release (x, y); + background.handler_release (x, y); move_bg = false; }); @@ -135,7 +151,7 @@ }); } - void move (double x, double y) { + void move (int x, int y) { Glyph g = MainWindow.get_current_glyph (); BackgroundImage? background_image = g.get_background_image (); BackgroundImage bg = (!) background_image; @@ -156,11 +172,11 @@ dx *= PenTool.precision; dy *= PenTool.precision; - + if (bg.selected_handle == 2) { coordinate_x = Glyph.path_coordinate_x (x); coordinate_y = Glyph.path_coordinate_y (y); - bg.set_img_rotation_from_coordinate (coordinate_x, coordinate_y); + bg.preview_img_rotation_from_coordinate (coordinate_x, coordinate_y); } if (bg.selected_handle == 1) { @@ -181,6 +197,9 @@ } GlyphCanvas.redraw (); + + last_x = x; + last_y = y; } public static void load_background_image () {
--- a/libbirdfont/ScaledBackgrounds.vala +++ b/libbirdfont/ScaledBackgrounds.vala @@ -35,6 +35,14 @@ } } + public ScaledBackgrounds.single_size (ImageSurface original, double scale_factor) { + this.original = original; + scaled = new ArrayList<ScaledBackground> (); + + ScaledBackground image = scale (scale_factor); + scaled.add (image); + } + public ScaledBackground get_image (double scale) { foreach (ScaledBackground image in scaled) { if (image.get_scale () < scale) {
--- a/libbirdfont/ScaledImage.vala +++ b/libbirdfont/ScaledImage.vala @@ -20,6 +20,7 @@ public class ScaledBackground : GLib.Object { ImageSurface image; + ImageSurface rotated; ArrayList<ImageSurface> parts; int size; int part_width; @@ -28,24 +29,39 @@ public ScaledBackground (ImageSurface image, double scale) { this.image = image; + rotated = image; this.scale = scale; + parts = new ArrayList<ImageSurface> (); - parts = new ArrayList<ImageSurface> (); + create_parts (); + } + + void create_parts () { + parts.clear (); + size = image.get_width () / 100; - size = 10; + if (size < 10) { + size = 10; + } + part_width = image.get_width () / size; part_height = image.get_height () / size; - + for (int y = 0; y < size; y++) { for (int x = 0; x < size; x++) { ImageSurface next_part; - next_part = new ImageSurface (Format.RGB24, part_width, part_height); + next_part = new ImageSurface (Format.ARGB32, part_width, part_height); Context context = new Context (next_part); - context.set_source_surface (image, -x * part_width, -y * part_width); + context.set_source_surface (rotated, -x * part_width, -y * part_width); context.paint (); parts.add (next_part); } - } + } + } + + public void rotate (double angle) { + rotated = BackgroundImage.rotate_image (image, angle); + create_parts (); } public double get_scale () { @@ -88,7 +104,9 @@ int assembled_width = (int) ((size + 2) * image_width); int assembled_height = (int) ((size + 2) * image_height); - image = new ImageSurface (Format.RGB24, assembled_width, assembled_height); + + image = new ImageSurface (Format.ARGB32, assembled_width, assembled_height); + Context context = new Context (image); int start_offset_x = start_x * part_width;