The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

ScaledImage.vala in libbirdfont

This file is a part of the Birdfont project.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git

Revisions

View the latest version of libbirdfont/ScaledImage.vala.
Fix optimized rendering of raster images
1 /* 2 Copyright (C) 2015 Johan Mattsson 3 4 This library is free software; you can redistribute it and/or modify 5 it under the terms of the GNU Lesser General Public License as 6 published by the Free Software Foundation; either version 3 of the 7 License, or (at your option) any later version. 8 9 This library is distributed in the hope that it will be useful, but 10 WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 Lesser General Public License for more details. 13 */ 14 15 using Cairo; 16 using Math; 17 using Gee; 18 19 namespace BirdFont { 20 21 public class ScaledBackground : GLib.Object { 22 ImageSurface image; 23 ImageSurface rotated; 24 ArrayList<ImageSurface> parts; 25 int size; 26 int part_width; 27 int part_height; 28 double scale; 29 30 public ScaledBackground (ImageSurface image, double scale) { 31 if (scale <= 0) { 32 warning ("scale <= 0"); 33 scale = 1; 34 } 35 36 this.image = image; 37 rotated = image; 38 this.scale = scale; 39 parts = new ArrayList<ImageSurface> (); 40 41 create_parts (); 42 } 43 44 void create_parts () { 45 parts.clear (); 46 size = image.get_width () / 100; 47 48 if (size < 10) { 49 size = 10; 50 } 51 52 part_width = image.get_width () / size; 53 part_height = image.get_height () / size; 54 55 if (part_width < 1) { 56 part_width = 1; 57 } 58 59 if (part_height < 1) { 60 part_height = 1; 61 } 62 63 for (int y = 0; y < size; y++) { 64 for (int x = 0; x < size; x++) { 65 ImageSurface next_part; 66 next_part = new ImageSurface (Format.ARGB32, part_width, part_height); 67 Context context = new Context (next_part); 68 context.set_source_surface (rotated, -x * part_width, -y * part_width); 69 context.paint (); 70 parts.add (next_part); 71 } 72 } 73 } 74 75 public void rotate (double angle) { 76 rotated = BackgroundImage.rotate_image (image, angle); 77 create_parts (); 78 } 79 80 public double get_scale () { 81 if (unlikely (scale == 0)) { 82 warning ("Zero scale."); 83 return 1; 84 } 85 86 return scale; 87 } 88 89 public ImageSurface get_image () { 90 return image; 91 } 92 93 ImageSurface? get_part_at (int x, int y) { 94 int index = y * size + x; 95 96 if (x >= size || x < 0) { 97 return null; 98 } 99 100 if (y >= size || y < 0) { 101 return null; 102 } 103 104 if (unlikely (!(0 <= index < parts.size))) { 105 warning (@"No part at index: $x, $y"); 106 return null; 107 } 108 109 return parts.get (index); 110 } 111 112 public ScaledBackgroundPart get_part (double offset_x, double offset_y, 113 int width, int height) { 114 115 if (width <= 0 || height <= 0) { 116 warning ("width <= 0 || height <= 0"); 117 scale = 1; 118 } 119 120 double image_width = part_width * size; 121 double image_height = part_height * size; 122 123 int start_x = (int) ((offset_x / image_width) * size); 124 int start_y = (int) ((offset_y / image_height) * size); 125 int stop_x = (int) (((offset_x + width) / image_width) * size) + 1; 126 int stop_y = (int) (((offset_y + height) / image_height) * size) + 1; 127 128 if (start_x < 0) { 129 start_x = 0; 130 } 131 132 if (start_y < 0) { 133 start_y = 0; 134 } 135 136 int assembled_width = (int) ((stop_x - start_x) * image_width); 137 int assembled_height = (int) ((stop_y - start_y) * image_height); 138 139 image = new ImageSurface (Format.ARGB32, assembled_width, assembled_height); 140 141 Context context = new Context (image); 142 143 int start_offset_x = start_x * part_width; 144 int start_offset_y = start_y * part_height; 145 146 for (int y = start_y; y < stop_y; y++) { 147 for (int x = start_x; x < stop_x; x++) { 148 ImageSurface? part = get_part_at (x, y); 149 150 if (part != null) { 151 context.save (); 152 153 context.set_source_surface ((!) part, 154 (x - start_x) * part_width, 155 (y - start_y) * part_height); 156 context.paint (); 157 158 context.restore (); 159 } 160 } 161 } 162 163 return new ScaledBackgroundPart (image, scale, 164 start_offset_x, start_offset_y); 165 } 166 } 167 168 } 169