11176bdada62cabc6ec4b0308a930e83b679d5d36John Reck/* 21176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Copyright 2012, Red Hat, Inc. 31176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Copyright 2012, Soren Sandmann 41176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * 51176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Permission is hereby granted, free of charge, to any person obtaining a 61176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * copy of this software and associated documentation files (the "Software"), 71176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * to deal in the Software without restriction, including without limitation 81176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * the rights to use, copy, modify, merge, publish, distribute, sublicense, 91176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * and/or sell copies of the Software, and to permit persons to whom the 101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Software is furnished to do so, subject to the following conditions: 111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * 121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * The above copyright notice and this permission notice (including the next 131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * paragraph) shall be included in all copies or substantial portions of the 141176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Software. 151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * 161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 191176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 201176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * DEALINGS IN THE SOFTWARE. 231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * 241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Author: Soren Sandmann <soren.sandmann@gmail.com> 251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck */ 261176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#ifdef HAVE_CONFIG_H 271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include "config.h" 281176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#endif 291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <math.h> 301176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <gtk/gtk.h> 311176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <pixman.h> 321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <stdlib.h> 331176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include "gtk-utils.h" 341176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 351176bdada62cabc6ec4b0308a930e83b679d5d36John Recktypedef struct 361176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 371176bdada62cabc6ec4b0308a930e83b679d5d36John Reck GtkBuilder * builder; 381176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_image_t * original; 391176bdada62cabc6ec4b0308a930e83b679d5d36John Reck GtkAdjustment * scale_x_adjustment; 401176bdada62cabc6ec4b0308a930e83b679d5d36John Reck GtkAdjustment * scale_y_adjustment; 411176bdada62cabc6ec4b0308a930e83b679d5d36John Reck GtkAdjustment * rotate_adjustment; 421176bdada62cabc6ec4b0308a930e83b679d5d36John Reck GtkAdjustment * subsample_adjustment; 431176bdada62cabc6ec4b0308a930e83b679d5d36John Reck int scaled_width; 441176bdada62cabc6ec4b0308a930e83b679d5d36John Reck int scaled_height; 451176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} app_t; 461176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 471176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic GtkWidget * 481176bdada62cabc6ec4b0308a930e83b679d5d36John Reckget_widget (app_t *app, const char *name) 491176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 501176bdada62cabc6ec4b0308a930e83b679d5d36John Reck GtkWidget *widget = GTK_WIDGET (gtk_builder_get_object (app->builder, name)); 511176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 521176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (!widget) 531176bdada62cabc6ec4b0308a930e83b679d5d36John Reck g_error ("Widget %s not found\n", name); 541176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 551176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return widget; 561176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 571176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 581176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic double 591176bdada62cabc6ec4b0308a930e83b679d5d36John Reckmin4 (double a, double b, double c, double d) 601176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 611176bdada62cabc6ec4b0308a930e83b679d5d36John Reck double m1, m2; 621176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 631176bdada62cabc6ec4b0308a930e83b679d5d36John Reck m1 = MIN (a, b); 641176bdada62cabc6ec4b0308a930e83b679d5d36John Reck m2 = MIN (c, d); 651176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return MIN (m1, m2); 661176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 671176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 681176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic double 691176bdada62cabc6ec4b0308a930e83b679d5d36John Reckmax4 (double a, double b, double c, double d) 701176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 711176bdada62cabc6ec4b0308a930e83b679d5d36John Reck double m1, m2; 721176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 731176bdada62cabc6ec4b0308a930e83b679d5d36John Reck m1 = MAX (a, b); 741176bdada62cabc6ec4b0308a930e83b679d5d36John Reck m2 = MAX (c, d); 751176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return MAX (m1, m2); 761176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 771176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 781176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic void 791176bdada62cabc6ec4b0308a930e83b679d5d36John Reckcompute_extents (pixman_f_transform_t *trans, double *sx, double *sy) 801176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 811176bdada62cabc6ec4b0308a930e83b679d5d36John Reck double min_x, max_x, min_y, max_y; 821176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_f_vector_t v[4] = 831176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 841176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { { 1, 1, 1 } }, 851176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { { -1, 1, 1 } }, 861176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { { -1, -1, 1 } }, 871176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { { 1, -1, 1 } }, 881176bdada62cabc6ec4b0308a930e83b679d5d36John Reck }; 891176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 901176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_f_transform_point (trans, &v[0]); 911176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_f_transform_point (trans, &v[1]); 921176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_f_transform_point (trans, &v[2]); 931176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_f_transform_point (trans, &v[3]); 941176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 951176bdada62cabc6ec4b0308a930e83b679d5d36John Reck min_x = min4 (v[0].v[0], v[1].v[0], v[2].v[0], v[3].v[0]); 961176bdada62cabc6ec4b0308a930e83b679d5d36John Reck max_x = max4 (v[0].v[0], v[1].v[0], v[2].v[0], v[3].v[0]); 971176bdada62cabc6ec4b0308a930e83b679d5d36John Reck min_y = min4 (v[0].v[1], v[1].v[1], v[2].v[1], v[3].v[1]); 981176bdada62cabc6ec4b0308a930e83b679d5d36John Reck max_y = max4 (v[0].v[1], v[1].v[1], v[2].v[1], v[3].v[1]); 991176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1001176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *sx = (max_x - min_x) / 2.0; 1011176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *sy = (max_y - min_y) / 2.0; 1021176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 1031176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1041176bdada62cabc6ec4b0308a930e83b679d5d36John Recktypedef struct 1051176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 1061176bdada62cabc6ec4b0308a930e83b679d5d36John Reck char name [20]; 1071176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_kernel_t value; 1081176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} named_int_t; 1091176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1101176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic const named_int_t filters[] = 1111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 1121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { "Box", PIXMAN_KERNEL_BOX }, 1131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { "Impulse", PIXMAN_KERNEL_IMPULSE }, 1141176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { "Linear", PIXMAN_KERNEL_LINEAR }, 1151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { "Cubic", PIXMAN_KERNEL_CUBIC }, 1161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { "Lanczos2", PIXMAN_KERNEL_LANCZOS2 }, 1171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { "Lanczos3", PIXMAN_KERNEL_LANCZOS3 }, 1181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { "Lanczos3 Stretched", PIXMAN_KERNEL_LANCZOS3_STRETCHED }, 1191176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { "Gaussian", PIXMAN_KERNEL_GAUSSIAN }, 1201176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}; 1211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1221176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic const named_int_t repeats[] = 1231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 1241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { "None", PIXMAN_REPEAT_NONE }, 1251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { "Normal", PIXMAN_REPEAT_NORMAL }, 1261176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { "Reflect", PIXMAN_REPEAT_REFLECT }, 1271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { "Pad", PIXMAN_REPEAT_PAD }, 1281176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}; 1291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1301176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic pixman_kernel_t 1311176bdada62cabc6ec4b0308a930e83b679d5d36John Reckget_value (app_t *app, const named_int_t table[], const char *box_name) 1321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 1331176bdada62cabc6ec4b0308a930e83b679d5d36John Reck GtkComboBox *box = GTK_COMBO_BOX (get_widget (app, box_name)); 1341176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1351176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return table[gtk_combo_box_get_active (box)].value; 1361176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 1371176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1381176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic void 1391176bdada62cabc6ec4b0308a930e83b679d5d36John Reckcopy_to_counterpart (app_t *app, GObject *object) 1401176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 1411176bdada62cabc6ec4b0308a930e83b679d5d36John Reck static const char *xy_map[] = 1421176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 1431176bdada62cabc6ec4b0308a930e83b679d5d36John Reck "reconstruct_x_combo_box", "reconstruct_y_combo_box", 1441176bdada62cabc6ec4b0308a930e83b679d5d36John Reck "sample_x_combo_box", "sample_y_combo_box", 1451176bdada62cabc6ec4b0308a930e83b679d5d36John Reck "scale_x_adjustment", "scale_y_adjustment", 1461176bdada62cabc6ec4b0308a930e83b679d5d36John Reck }; 1471176bdada62cabc6ec4b0308a930e83b679d5d36John Reck GObject *counterpart = NULL; 1481176bdada62cabc6ec4b0308a930e83b679d5d36John Reck int i; 1491176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1501176bdada62cabc6ec4b0308a930e83b679d5d36John Reck for (i = 0; i < G_N_ELEMENTS (xy_map); i += 2) 1511176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 1521176bdada62cabc6ec4b0308a930e83b679d5d36John Reck GObject *x = gtk_builder_get_object (app->builder, xy_map[i]); 1531176bdada62cabc6ec4b0308a930e83b679d5d36John Reck GObject *y = gtk_builder_get_object (app->builder, xy_map[i + 1]); 1541176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1551176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (object == x) 1561176bdada62cabc6ec4b0308a930e83b679d5d36John Reck counterpart = y; 1571176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (object == y) 1581176bdada62cabc6ec4b0308a930e83b679d5d36John Reck counterpart = x; 1591176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 1601176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1611176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (!counterpart) 1621176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return; 1631176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1641176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (GTK_IS_COMBO_BOX (counterpart)) 1651176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 1661176bdada62cabc6ec4b0308a930e83b679d5d36John Reck gtk_combo_box_set_active ( 1671176bdada62cabc6ec4b0308a930e83b679d5d36John Reck GTK_COMBO_BOX (counterpart), 1681176bdada62cabc6ec4b0308a930e83b679d5d36John Reck gtk_combo_box_get_active ( 1691176bdada62cabc6ec4b0308a930e83b679d5d36John Reck GTK_COMBO_BOX (object))); 1701176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 1711176bdada62cabc6ec4b0308a930e83b679d5d36John Reck else if (GTK_IS_ADJUSTMENT (counterpart)) 1721176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 1731176bdada62cabc6ec4b0308a930e83b679d5d36John Reck gtk_adjustment_set_value ( 1741176bdada62cabc6ec4b0308a930e83b679d5d36John Reck GTK_ADJUSTMENT (counterpart), 1751176bdada62cabc6ec4b0308a930e83b679d5d36John Reck gtk_adjustment_get_value ( 1761176bdada62cabc6ec4b0308a930e83b679d5d36John Reck GTK_ADJUSTMENT (object))); 1771176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 1781176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 1791176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1801176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic double 1811176bdada62cabc6ec4b0308a930e83b679d5d36John Reckto_scale (double v) 1821176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 1831176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return pow (1.15, v); 1841176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 1851176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1861176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic void 1871176bdada62cabc6ec4b0308a930e83b679d5d36John Reckrescale (GtkWidget *may_be_null, app_t *app) 1881176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 1891176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_f_transform_t ftransform; 1901176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_transform_t transform; 1911176bdada62cabc6ec4b0308a930e83b679d5d36John Reck double new_width, new_height; 1921176bdada62cabc6ec4b0308a930e83b679d5d36John Reck double fscale_x, fscale_y; 1931176bdada62cabc6ec4b0308a930e83b679d5d36John Reck double rotation; 1941176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_fixed_t *params; 1951176bdada62cabc6ec4b0308a930e83b679d5d36John Reck int n_params; 1961176bdada62cabc6ec4b0308a930e83b679d5d36John Reck double sx, sy; 1971176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1981176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_f_transform_init_identity (&ftransform); 1991176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2001176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (may_be_null && gtk_toggle_button_get_active ( 2011176bdada62cabc6ec4b0308a930e83b679d5d36John Reck GTK_TOGGLE_BUTTON (get_widget (app, "lock_checkbutton")))) 2021176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 2031176bdada62cabc6ec4b0308a930e83b679d5d36John Reck copy_to_counterpart (app, G_OBJECT (may_be_null)); 2041176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 2051176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2061176bdada62cabc6ec4b0308a930e83b679d5d36John Reck fscale_x = gtk_adjustment_get_value (app->scale_x_adjustment); 2071176bdada62cabc6ec4b0308a930e83b679d5d36John Reck fscale_y = gtk_adjustment_get_value (app->scale_y_adjustment); 2081176bdada62cabc6ec4b0308a930e83b679d5d36John Reck rotation = gtk_adjustment_get_value (app->rotate_adjustment); 2091176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck fscale_x = to_scale (fscale_x); 2111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck fscale_y = to_scale (fscale_y); 2121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck new_width = pixman_image_get_width (app->original) * fscale_x; 2141176bdada62cabc6ec4b0308a930e83b679d5d36John Reck new_height = pixman_image_get_height (app->original) * fscale_y; 2151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_f_transform_scale (&ftransform, NULL, fscale_x, fscale_y); 2171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_f_transform_translate (&ftransform, NULL, - new_width / 2.0, - new_height / 2.0); 2191176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2201176bdada62cabc6ec4b0308a930e83b679d5d36John Reck rotation = (rotation / 360.0) * 2 * M_PI; 2211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_f_transform_rotate (&ftransform, NULL, cos (rotation), sin (rotation)); 2221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_f_transform_translate (&ftransform, NULL, new_width / 2.0, new_height / 2.0); 2241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_f_transform_invert (&ftransform, &ftransform); 2261176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck compute_extents (&ftransform, &sx, &sy); 2281176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_transform_from_pixman_f_transform (&transform, &ftransform); 2301176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_image_set_transform (app->original, &transform); 2311176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck params = pixman_filter_create_separable_convolution ( 2331176bdada62cabc6ec4b0308a930e83b679d5d36John Reck &n_params, 2341176bdada62cabc6ec4b0308a930e83b679d5d36John Reck sx * 65536.0 + 0.5, 2351176bdada62cabc6ec4b0308a930e83b679d5d36John Reck sy * 65536.0 + 0.5, 2361176bdada62cabc6ec4b0308a930e83b679d5d36John Reck get_value (app, filters, "reconstruct_x_combo_box"), 2371176bdada62cabc6ec4b0308a930e83b679d5d36John Reck get_value (app, filters, "reconstruct_y_combo_box"), 2381176bdada62cabc6ec4b0308a930e83b679d5d36John Reck get_value (app, filters, "sample_x_combo_box"), 2391176bdada62cabc6ec4b0308a930e83b679d5d36John Reck get_value (app, filters, "sample_y_combo_box"), 2401176bdada62cabc6ec4b0308a930e83b679d5d36John Reck gtk_adjustment_get_value (app->subsample_adjustment), 2411176bdada62cabc6ec4b0308a930e83b679d5d36John Reck gtk_adjustment_get_value (app->subsample_adjustment)); 2421176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2431176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_image_set_filter (app->original, PIXMAN_FILTER_SEPARABLE_CONVOLUTION, params, n_params); 2441176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2451176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_image_set_repeat ( 2461176bdada62cabc6ec4b0308a930e83b679d5d36John Reck app->original, get_value (app, repeats, "repeat_combo_box")); 2471176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2481176bdada62cabc6ec4b0308a930e83b679d5d36John Reck free (params); 2491176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2501176bdada62cabc6ec4b0308a930e83b679d5d36John Reck app->scaled_width = ceil (new_width); 2511176bdada62cabc6ec4b0308a930e83b679d5d36John Reck app->scaled_height = ceil (new_height); 2521176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2531176bdada62cabc6ec4b0308a930e83b679d5d36John Reck gtk_widget_set_size_request ( 2541176bdada62cabc6ec4b0308a930e83b679d5d36John Reck get_widget (app, "drawing_area"), new_width + 0.5, new_height + 0.5); 2551176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2561176bdada62cabc6ec4b0308a930e83b679d5d36John Reck gtk_widget_queue_draw ( 2571176bdada62cabc6ec4b0308a930e83b679d5d36John Reck get_widget (app, "drawing_area")); 2581176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 2591176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2601176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic gboolean 2611176bdada62cabc6ec4b0308a930e83b679d5d36John Reckon_expose (GtkWidget *da, GdkEvent *event, gpointer data) 2621176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 2631176bdada62cabc6ec4b0308a930e83b679d5d36John Reck app_t *app = data; 2641176bdada62cabc6ec4b0308a930e83b679d5d36John Reck GdkRectangle *area = &event->expose.area; 2651176bdada62cabc6ec4b0308a930e83b679d5d36John Reck cairo_surface_t *surface; 2661176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_image_t *tmp; 2671176bdada62cabc6ec4b0308a930e83b679d5d36John Reck cairo_t *cr; 2681176bdada62cabc6ec4b0308a930e83b679d5d36John Reck uint32_t *pixels; 2691176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2701176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixels = calloc (1, area->width * area->height * 4); 2711176bdada62cabc6ec4b0308a930e83b679d5d36John Reck tmp = pixman_image_create_bits ( 2721176bdada62cabc6ec4b0308a930e83b679d5d36John Reck PIXMAN_a8r8g8b8, area->width, area->height, pixels, area->width * 4); 2731176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2741176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (area->x < app->scaled_width && area->y < app->scaled_height) 2751176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 2761176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_image_composite ( 2771176bdada62cabc6ec4b0308a930e83b679d5d36John Reck PIXMAN_OP_SRC, 2781176bdada62cabc6ec4b0308a930e83b679d5d36John Reck app->original, NULL, tmp, 2791176bdada62cabc6ec4b0308a930e83b679d5d36John Reck area->x, area->y, 0, 0, 0, 0, 2801176bdada62cabc6ec4b0308a930e83b679d5d36John Reck app->scaled_width - area->x, app->scaled_height - area->y); 2811176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 2821176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2831176bdada62cabc6ec4b0308a930e83b679d5d36John Reck surface = cairo_image_surface_create_for_data ( 2841176bdada62cabc6ec4b0308a930e83b679d5d36John Reck (uint8_t *)pixels, CAIRO_FORMAT_ARGB32, 2851176bdada62cabc6ec4b0308a930e83b679d5d36John Reck area->width, area->height, area->width * 4); 2861176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2871176bdada62cabc6ec4b0308a930e83b679d5d36John Reck cr = gdk_cairo_create (da->window); 2881176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2891176bdada62cabc6ec4b0308a930e83b679d5d36John Reck cairo_set_source_surface (cr, surface, area->x, area->y); 2901176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2911176bdada62cabc6ec4b0308a930e83b679d5d36John Reck cairo_paint (cr); 2921176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2931176bdada62cabc6ec4b0308a930e83b679d5d36John Reck cairo_destroy (cr); 2941176bdada62cabc6ec4b0308a930e83b679d5d36John Reck cairo_surface_destroy (surface); 2951176bdada62cabc6ec4b0308a930e83b679d5d36John Reck free (pixels); 2961176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_image_unref (tmp); 2971176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2981176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return TRUE; 2991176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 3001176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3011176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic void 3021176bdada62cabc6ec4b0308a930e83b679d5d36John Reckset_up_combo_box (app_t *app, const char *box_name, 3031176bdada62cabc6ec4b0308a930e83b679d5d36John Reck int n_entries, const named_int_t table[]) 3041176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 3051176bdada62cabc6ec4b0308a930e83b679d5d36John Reck GtkWidget *widget = get_widget (app, box_name); 3061176bdada62cabc6ec4b0308a930e83b679d5d36John Reck GtkListStore *model; 3071176bdada62cabc6ec4b0308a930e83b679d5d36John Reck GtkCellRenderer *cell; 3081176bdada62cabc6ec4b0308a930e83b679d5d36John Reck int i; 3091176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck model = gtk_list_store_new (1, G_TYPE_STRING); 3111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck cell = gtk_cell_renderer_text_new (); 3131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (widget), cell, TRUE); 3141176bdada62cabc6ec4b0308a930e83b679d5d36John Reck gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (widget), cell, 3151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck "text", 0, 3161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck NULL); 3171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck gtk_combo_box_set_model (GTK_COMBO_BOX (widget), GTK_TREE_MODEL (model)); 3191176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3201176bdada62cabc6ec4b0308a930e83b679d5d36John Reck for (i = 0; i < n_entries; ++i) 3211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 3221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck const named_int_t *info = &(table[i]); 3231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck GtkTreeIter iter; 3241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck gtk_list_store_append (model, &iter); 3261176bdada62cabc6ec4b0308a930e83b679d5d36John Reck gtk_list_store_set (model, &iter, 0, info->name, -1); 3271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 3281176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0); 3301176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3311176bdada62cabc6ec4b0308a930e83b679d5d36John Reck g_signal_connect (widget, "changed", G_CALLBACK (rescale), app); 3321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 3331176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3341176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic void 3351176bdada62cabc6ec4b0308a930e83b679d5d36John Reckset_up_filter_box (app_t *app, const char *box_name) 3361176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 3371176bdada62cabc6ec4b0308a930e83b679d5d36John Reck set_up_combo_box (app, box_name, G_N_ELEMENTS (filters), filters); 3381176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 3391176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3401176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic char * 3411176bdada62cabc6ec4b0308a930e83b679d5d36John Reckformat_value (GtkWidget *widget, double value) 3421176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 3431176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return g_strdup_printf ("%.4f", to_scale (value)); 3441176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 3451176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3461176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic app_t * 3471176bdada62cabc6ec4b0308a930e83b679d5d36John Reckapp_new (pixman_image_t *original) 3481176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 3491176bdada62cabc6ec4b0308a930e83b679d5d36John Reck GtkWidget *widget; 3501176bdada62cabc6ec4b0308a930e83b679d5d36John Reck app_t *app = g_malloc (sizeof *app); 3511176bdada62cabc6ec4b0308a930e83b679d5d36John Reck GError *err = NULL; 3521176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3531176bdada62cabc6ec4b0308a930e83b679d5d36John Reck app->builder = gtk_builder_new (); 3541176bdada62cabc6ec4b0308a930e83b679d5d36John Reck app->original = original; 3551176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3561176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (!gtk_builder_add_from_file (app->builder, "scale.ui", &err)) 3571176bdada62cabc6ec4b0308a930e83b679d5d36John Reck g_error ("Could not read file scale.ui: %s", err->message); 3581176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3591176bdada62cabc6ec4b0308a930e83b679d5d36John Reck app->scale_x_adjustment = 3601176bdada62cabc6ec4b0308a930e83b679d5d36John Reck GTK_ADJUSTMENT (gtk_builder_get_object (app->builder, "scale_x_adjustment")); 3611176bdada62cabc6ec4b0308a930e83b679d5d36John Reck app->scale_y_adjustment = 3621176bdada62cabc6ec4b0308a930e83b679d5d36John Reck GTK_ADJUSTMENT (gtk_builder_get_object (app->builder, "scale_y_adjustment")); 3631176bdada62cabc6ec4b0308a930e83b679d5d36John Reck app->rotate_adjustment = 3641176bdada62cabc6ec4b0308a930e83b679d5d36John Reck GTK_ADJUSTMENT (gtk_builder_get_object (app->builder, "rotate_adjustment")); 3651176bdada62cabc6ec4b0308a930e83b679d5d36John Reck app->subsample_adjustment = 3661176bdada62cabc6ec4b0308a930e83b679d5d36John Reck GTK_ADJUSTMENT (gtk_builder_get_object (app->builder, "subsample_adjustment")); 3671176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3681176bdada62cabc6ec4b0308a930e83b679d5d36John Reck g_signal_connect (app->scale_x_adjustment, "value_changed", G_CALLBACK (rescale), app); 3691176bdada62cabc6ec4b0308a930e83b679d5d36John Reck g_signal_connect (app->scale_y_adjustment, "value_changed", G_CALLBACK (rescale), app); 3701176bdada62cabc6ec4b0308a930e83b679d5d36John Reck g_signal_connect (app->rotate_adjustment, "value_changed", G_CALLBACK (rescale), app); 3711176bdada62cabc6ec4b0308a930e83b679d5d36John Reck g_signal_connect (app->subsample_adjustment, "value_changed", G_CALLBACK (rescale), app); 3721176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3731176bdada62cabc6ec4b0308a930e83b679d5d36John Reck widget = get_widget (app, "scale_x_scale"); 3741176bdada62cabc6ec4b0308a930e83b679d5d36John Reck gtk_scale_add_mark (GTK_SCALE (widget), 0.0, GTK_POS_LEFT, NULL); 3751176bdada62cabc6ec4b0308a930e83b679d5d36John Reck g_signal_connect (widget, "format_value", G_CALLBACK (format_value), app); 3761176bdada62cabc6ec4b0308a930e83b679d5d36John Reck widget = get_widget (app, "scale_y_scale"); 3771176bdada62cabc6ec4b0308a930e83b679d5d36John Reck gtk_scale_add_mark (GTK_SCALE (widget), 0.0, GTK_POS_LEFT, NULL); 3781176bdada62cabc6ec4b0308a930e83b679d5d36John Reck g_signal_connect (widget, "format_value", G_CALLBACK (format_value), app); 3791176bdada62cabc6ec4b0308a930e83b679d5d36John Reck widget = get_widget (app, "rotate_scale"); 3801176bdada62cabc6ec4b0308a930e83b679d5d36John Reck gtk_scale_add_mark (GTK_SCALE (widget), 0.0, GTK_POS_LEFT, NULL); 3811176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3821176bdada62cabc6ec4b0308a930e83b679d5d36John Reck widget = get_widget (app, "drawing_area"); 3831176bdada62cabc6ec4b0308a930e83b679d5d36John Reck g_signal_connect (widget, "expose_event", G_CALLBACK (on_expose), app); 3841176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3851176bdada62cabc6ec4b0308a930e83b679d5d36John Reck set_up_filter_box (app, "reconstruct_x_combo_box"); 3861176bdada62cabc6ec4b0308a930e83b679d5d36John Reck set_up_filter_box (app, "reconstruct_y_combo_box"); 3871176bdada62cabc6ec4b0308a930e83b679d5d36John Reck set_up_filter_box (app, "sample_x_combo_box"); 3881176bdada62cabc6ec4b0308a930e83b679d5d36John Reck set_up_filter_box (app, "sample_y_combo_box"); 3891176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3901176bdada62cabc6ec4b0308a930e83b679d5d36John Reck set_up_combo_box ( 3911176bdada62cabc6ec4b0308a930e83b679d5d36John Reck app, "repeat_combo_box", G_N_ELEMENTS (repeats), repeats); 3921176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3931176bdada62cabc6ec4b0308a930e83b679d5d36John Reck g_signal_connect ( 3941176bdada62cabc6ec4b0308a930e83b679d5d36John Reck gtk_builder_get_object (app->builder, "lock_checkbutton"), 3951176bdada62cabc6ec4b0308a930e83b679d5d36John Reck "toggled", G_CALLBACK (rescale), app); 3961176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3971176bdada62cabc6ec4b0308a930e83b679d5d36John Reck rescale (NULL, app); 3981176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3991176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return app; 4001176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 4011176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 4021176bdada62cabc6ec4b0308a930e83b679d5d36John Reckint 4031176bdada62cabc6ec4b0308a930e83b679d5d36John Reckmain (int argc, char **argv) 4041176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 4051176bdada62cabc6ec4b0308a930e83b679d5d36John Reck GtkWidget *window; 4061176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_image_t *image; 4071176bdada62cabc6ec4b0308a930e83b679d5d36John Reck app_t *app; 4081176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 4091176bdada62cabc6ec4b0308a930e83b679d5d36John Reck gtk_init (&argc, &argv); 4101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 4111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (argc < 2) 4121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 4131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck printf ("%s <image file>\n", argv[0]); 4141176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return -1; 4151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 4161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 4171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (!(image = pixman_image_from_file (argv[1], PIXMAN_a8r8g8b8))) 4181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 4191176bdada62cabc6ec4b0308a930e83b679d5d36John Reck printf ("Could not load image \"%s\"\n", argv[1]); 4201176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return -1; 4211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 4221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 4231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck app = app_new (image); 4241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 4251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck window = get_widget (app, "main"); 4261176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 4271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck g_signal_connect (window, "delete_event", G_CALLBACK (gtk_main_quit), NULL); 4281176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 4291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck gtk_window_set_default_size (GTK_WINDOW (window), 1024, 768); 4301176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 4311176bdada62cabc6ec4b0308a930e83b679d5d36John Reck gtk_widget_show_all (window); 4321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 4331176bdada62cabc6ec4b0308a930e83b679d5d36John Reck gtk_main (); 4341176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 4351176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return 0; 4361176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 437