Commit 9ae0f4c
Speed optimizations for background images This code splits big images in smaller parts and renders only the relevant sections.
Changed files (4)
modifiedlibbirdfont/BackgroundImage.valaaddedlibbirdfont/ScaledBackgroundPart.valaaddedlibbirdfont/ScaledBackgrounds.valaaddedlibbirdfont/ScaledImage.vala
Diff
@@ -47,6 +47,8 @@ public class BackgroundImage { public signal void updated (); + private ScaledBackgrounds? scaled = null;+ public double img_offset_x { get { return img_x + Glyph.xc (); } set { img_x = value - Glyph.xc (); }@@ -114,6 +116,14 @@ public class BackgroundImage { return bg; } + public ScaledBackgrounds get_scaled_backgrounds () {+ if (scaled == null) {+ scaled = new ScaledBackgrounds ((ImageSurface) get_rotated_image ());+ }+ + return (!) scaled;+ }+ public void add_selection (BackgroundSelection bs) { selections.add (bs); }@@ -160,7 +170,7 @@ public class BackgroundImage { if (background_image == null) { background_image = new ImageSurface.from_png (path);- original_image = new ImageSurface.from_png (path);+ original_image = new ImageSurface.from_png (path); } return (!) original_image;@@ -387,7 +397,9 @@ public class BackgroundImage { img_offset_y = g.get_line ("top").pos; } - public void draw (Context cr, WidgetAllocation allocation, double view_offset_x, double view_offset_y, double view_zoom) {+ public void draw (Context cr, WidgetAllocation allocation,+ double view_offset_x, double view_offset_y, double view_zoom) {+ double scale_x, scale_y; double image_scale_x, image_scale_y; ImageSurface s;@@ -417,29 +429,50 @@ public class BackgroundImage { image_scale_y = img_scale_y * ((double) rotated_image.get_height () / s.get_height ()); } - st = new Surface.similar (s, s.get_content (), allocation.width, allocation.height);- ct = new Context (st);- ct.save ();+ // FIXME: rotated and contrast+ ScaledBackgrounds backgrounds = get_scaled_backgrounds ();+ ScaledBackground scaled = backgrounds.get_image (view_zoom * img_scale_x); // FIXME: y - ct.set_source_rgba (1, 1, 1, 1);- ct.rectangle (0, 0, allocation.width, allocation.height);- ct.fill ();+ ScaledBackgroundPart part;+ double part_scale_x = view_zoom * image_scale_x;+ double part_scale_y = view_zoom * image_scale_y;+ + double part_offset_x = img_offset_x - view_offset_x;+ part_offset_x *= view_zoom;+ part_offset_x = -part_offset_x;++ 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); - // scale both canvas and image at the same time scale_x = view_zoom * image_scale_x; scale_y = view_zoom * image_scale_y; - ct.scale (scale_x, scale_y);- ct.translate (-view_offset_x / image_scale_x, -view_offset_y / image_scale_y);+ scale_x /= part.get_scale ();+ scale_y /= part.get_scale (); - ct.set_source_surface (s, img_offset_x / image_scale_x, img_offset_y / image_scale_y);+ ImageSurface scaled_image;+ Context scaled_context;+ scaled_image = new ImageSurface (Format.ARGB32, allocation.width, allocation.height);+ scaled_context = new Context (scaled_image); - ct.paint ();- ct.restore ();+ 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 ();+ // add it cr.save ();- cr.set_source_surface (st, 0, 0);+ cr.set_source_surface (scaled_image, 0, 0); cr.paint (); cr.restore (); }new file mode 100644@@ -0,0 +1,43 @@+/*+ Copyright (C) 2015 Johan Mattsson++ This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 3 of the + License, or (at your option) any later version.++ This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details.+*/++using Cairo;+using Math;+using Gee;++namespace BirdFont {++public class ScaledBackgroundPart : GLib.Object {+ public double scale;+ public int offset_x;+ public int offset_y;+ public ImageSurface image;+ + public ScaledBackgroundPart (ImageSurface image, double scale, int offset_x, int offset_y) {+ this.image = image;+ this.scale = scale;+ this.offset_x = offset_x;+ this.offset_y = offset_y;+ }++ public double get_scale () {+ return scale;+ }+ + public ImageSurface get_image () {+ return image;+ }+}++}new file mode 100644@@ -0,0 +1,64 @@+/*+ Copyright (C) 2015 Johan Mattsson++ This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 3 of the + License, or (at your option) any later version.++ This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details.+*/++using Cairo;+using Math;+using Gee;++namespace BirdFont {++public class ScaledBackgrounds : GLib.Object {+ ImageSurface original;+ ArrayList<ScaledBackground> scaled;+ + public ScaledBackgrounds (ImageSurface original) {+ this.original = original;+ scaled = new ArrayList<ScaledBackground> ();++ ScaledBackground image = scale (0.01);+ scaled.add (image);+ + for (double scale_factor = 0.1; scale_factor <= 1; scale_factor += 0.1) {+ image = scale (scale_factor);+ scaled.add (image);+ }+ }++ public ScaledBackground get_image (double scale) {+ foreach (ScaledBackground image in scaled) {+ if (image.get_scale () < scale) {+ continue;+ }+ + return image;+ }++ return scaled.get (scaled.size - 1);+ }++ private ScaledBackground scale (double scale_factor) {+ ImageSurface scaled_image;+ int width = (int) (scale_factor * original.get_width ());+ int height = (int) (scale_factor * original.get_height ());+ scaled_image = new ImageSurface (Format.ARGB32, width, height);+ Context context = new Context (scaled_image);+ context.scale (scale_factor, scale_factor);+ context.set_source_surface (original, 0, 0);+ context.paint ();+ + return new ScaledBackground (scaled_image, scale_factor);+ }+}++}new file mode 100644@@ -0,0 +1,128 @@+/*+ Copyright (C) 2015 Johan Mattsson++ This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 3 of the + License, or (at your option) any later version.++ This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details.+*/++using Cairo;+using Math;+using Gee;++namespace BirdFont {++public class ScaledBackground : GLib.Object {+ ImageSurface image;+ double scale;+ ArrayList<ImageSurface> parts;+ int size;+ int part_width;+ int part_height;+ + public ScaledBackground (ImageSurface image, double scale) {+ this.image = image;+ this.scale = scale;+ parts = new ArrayList<ImageSurface> ();+ + 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);+ Context context = new Context (next_part);+ context.set_source_surface (image, -x * part_width, -y * part_width);+ context.paint ();+ parts.add (next_part);+ }+ }+ }+ + public double get_scale () {+ return scale;+ }+ + public ImageSurface get_image () {+ return image;+ }+ + ImageSurface? get_part_at (int x, int y) {+ int index = y * size + x;++ if (x >= size || x < 0) {+ return null;+ }++ if (y >= size || y < 0) {+ return null;+ }+ + if (unlikely (!(0 <= index < parts.size))) {+ warning (@"No part at index: $x, $y");+ return null;+ }+ + return parts.get (index);+ }+ + public ScaledBackgroundPart get_part (double offset_x, double offset_y, + int width, int height) {+ + double image_width = part_width * size;+ double image_height = part_height * size;+ + int start_x = (int) ((offset_x / image_width) * size) - 1;+ int start_y = (int) ((offset_y / image_height) * size) - 1;+ int stop_x = (int) (((offset_x + width) / image_width) * size) + 2;+ int stop_y = (int) (((offset_y + height) / image_height) * size) + 2;++ 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);+ Context context = new Context (image);++ int start_offset_x = start_x * part_width;+ int start_offset_y = start_y * part_height;+ + if (start_offset_x > 0) {+ start_x = -1;+ start_offset_x = start_x * part_width;+ }++ if (start_offset_y > 0) {+ start_y = -1;+ start_offset_y = start_y * part_height;+ }+ + for (int y = start_y; y < stop_y; y++) {+ for (int x = start_x; x < stop_x; x++) {+ ImageSurface? part = get_part_at (x, y);+ + if (part != null) {+ context.save ();+ + context.set_source_surface ((!) part,+ (x - start_x) * part_width,+ (y - start_y) * part_height);+ + context.paint ();+ context.restore ();+ }+ }+ }+ + return new ScaledBackgroundPart (image, scale,+ start_offset_x, start_offset_y);+ }+}++}