[gthumb] new tool: special effects
- From: Paolo Bacchilega <paobac src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gthumb] new tool: special effects
- Date: Sun, 25 Jan 2015 12:05:57 +0000 (UTC)
commit f795de2114681abbe0a7a06acbea78a58a3d74b8
Author: Paolo Bacchilega <paobac src gnome org>
Date: Wed Jan 7 12:56:38 2015 +0100
new tool: special effects
data/icons/hicolor/16x16/actions/Makefile.am | 1 +
.../16x16/actions/special-effects-symbolic.svg | 167 +++++
extensions/cairo_io/cairo-image-surface-xcf.c | 60 +--
extensions/file_tools/Makefile.am | 124 ++--
extensions/file_tools/cairo-blur.h | 6 +-
extensions/file_tools/cairo-effects.c | 450 ++++++++++++++
extensions/file_tools/cairo-effects.h | 58 ++
extensions/file_tools/data/ui/Makefile.am | 1 +
extensions/file_tools/data/ui/effects-options.ui | 44 ++
extensions/file_tools/gth-file-tool-effects.c | 655 ++++++++++++++++++++
extensions/file_tools/gth-file-tool-effects.h | 61 ++
extensions/file_tools/main.c | 16 +
gthumb/Makefile.am | 2 +
gthumb/gimp-op.c | 57 ++
gthumb/gimp-op.h | 59 ++
15 files changed, 1645 insertions(+), 116 deletions(-)
---
diff --git a/data/icons/hicolor/16x16/actions/Makefile.am b/data/icons/hicolor/16x16/actions/Makefile.am
index 197e4e7..6d52531 100644
--- a/data/icons/hicolor/16x16/actions/Makefile.am
+++ b/data/icons/hicolor/16x16/actions/Makefile.am
@@ -46,6 +46,7 @@ icons_DATA = \
site-photobucket.png \
site-picasaweb.png \
site-twentythree.png \
+ spacial-effects-symbolic.svg \
swap-values-symbolic.svg \
tag-symbolic.svg \
tools-symbolic.svg \
diff --git a/data/icons/hicolor/16x16/actions/special-effects-symbolic.svg
b/data/icons/hicolor/16x16/actions/special-effects-symbolic.svg
new file mode 100644
index 0000000..2aabd87
--- /dev/null
+++ b/data/icons/hicolor/16x16/actions/special-effects-symbolic.svg
@@ -0,0 +1,167 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.91+devel r13821 custom"
+ sodipodi:docname="special-effects-symbolic.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3946">
+ <stop
+ id="stop3948"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:0.74698794;" />
+ <stop
+ id="stop3950"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0.02409638;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3830-9">
+ <stop
+ style="stop-color:#000000;stop-opacity:0.74698794;"
+ offset="0"
+ id="stop3832-7" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0.02409638;"
+ offset="1"
+ id="stop3834-5" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3984">
+ <stop
+ style="stop-color:#f4deba;stop-opacity:1;"
+ offset="0"
+ id="stop3986" />
+ <stop
+ style="stop-color:#de9625;stop-opacity:0;"
+ offset="1"
+ id="stop3988" />
+ </linearGradient>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#555753"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="1"
+ inkscape:pageshadow="2"
+ inkscape:zoom="22.627417"
+ inkscape:cx="-4.8421885"
+ inkscape:cy="10.750332"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:snap-grids="true"
+ inkscape:window-width="1680"
+ inkscape:window-height="984"
+ inkscape:window-x="0"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1"
+ showborder="true"
+ fit-margin-top="0"
+ fit-margin-right="0"
+ fit-margin-left="0"
+ fit-margin-bottom="0"
+ showguides="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid7044"
+ empspacing="8"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true"
+ originx="-31.97559px"
+ originy="-816.00002px" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Livello 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-31.97559,-220.36218)">
+ <path
+ sodipodi:type="star"
+
style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path4157"
+ sodipodi:sides="5"
+ sodipodi:cx="35.988739"
+ sodipodi:cy="224.53897"
+ sodipodi:r1="4.472136"
+ sodipodi:r2="1.675368"
+ sodipodi:arg1="1.1071487"
+ sodipodi:arg2="1.7494959"
+ inkscape:flatsided="false"
+ inkscape:rounded="0"
+ inkscape:randomized="0"
+ d="m 37.988739,228.53897 -2.297797,-2.35131 -2.888395,1.48949 1.526172,-2.91193 -2.309155,-2.28675
3.241023,0.55164 1.461259,-2.90278 0.476891,3.25286 3.212262,0.49274 -2.946288,1.45874 z"
+ inkscape:transform-center-x="0.30715807"
+ inkscape:transform-center-y="1.5471892"
+ transform="matrix(0.64913853,-0.86150281,0.86150281,0.64913853,-179.99636,110.92512)" />
+ <path
+ transform="matrix(0.17246664,-0.59507374,0.59507374,0.17246664,-97.308777,206.28836)"
+ inkscape:transform-center-y="0.63390317"
+ inkscape:transform-center-x="-0.10387294"
+ d="m 37.988739,228.53897 -2.297797,-2.35131 -2.888395,1.48949 1.526172,-2.91193 -2.309155,-2.28675
3.241023,0.55164 1.461259,-2.90278 0.476891,3.25286 3.212262,0.49274 -2.946288,1.45874 z"
+ inkscape:randomized="0"
+ inkscape:rounded="0"
+ inkscape:flatsided="false"
+ sodipodi:arg2="1.7494959"
+ sodipodi:arg1="1.1071487"
+ sodipodi:r2="1.675368"
+ sodipodi:r1="4.472136"
+ sodipodi:cy="224.53897"
+ sodipodi:cx="35.988739"
+ sodipodi:sides="5"
+ id="path4167"
+
style="opacity:1;fill:#bebebe;fill-opacity:0.74840766;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ sodipodi:type="star" />
+ <path
+ sodipodi:type="star"
+
style="opacity:1;fill:#bebebe;fill-opacity:0.69745225;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path4169"
+ sodipodi:sides="5"
+ sodipodi:cx="35.988739"
+ sodipodi:cy="224.53897"
+ sodipodi:r1="4.472136"
+ sodipodi:r2="1.675368"
+ sodipodi:arg1="1.1071487"
+ sodipodi:arg2="1.7494959"
+ inkscape:flatsided="false"
+ inkscape:rounded="0"
+ inkscape:randomized="0"
+ d="m 37.988739,228.53897 -2.297797,-2.35131 -2.888395,1.48949 1.526172,-2.91193 -2.309155,-2.28675
3.241023,0.55164 1.461259,-2.90278 0.476891,3.25286 3.212262,0.49274 -2.946288,1.45874 z"
+ inkscape:transform-center-x="0.37691353"
+ inkscape:transform-center-y="0.50563846"
+ transform="matrix(0.31512729,-0.24426588,0.24426588,0.31512729,-20.343182,164.16536)" />
+ <path
+
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#bebebe;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background
:accumulate"
+ d="m 39.751212,228.25156 c -0.449408,9e-5 -0.670595,0.54685 -0.347656,0.85938 l 6.011567,6.18638 c
0.471254,0.49084 1.197872,-0.23577 0.707032,-0.70703 l -6.011568,-6.18639 c -0.09421,-0.0974
-0.223892,-0.15234 -0.359375,-0.15234 z"
+ id="path4171"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccc" />
+ </g>
+</svg>
diff --git a/extensions/cairo_io/cairo-image-surface-xcf.c b/extensions/cairo_io/cairo-image-surface-xcf.c
index 946ba9a..f200f3d 100644
--- a/extensions/cairo_io/cairo-image-surface-xcf.c
+++ b/extensions/cairo_io/cairo-image-surface-xcf.c
@@ -26,36 +26,9 @@
#include "cairo-image-surface-xcf.h"
-/* Optimizations taken from xcftools 1.0.7 written by Henning Makholm
- *
- * xL : Layer color
- * xI : Image color
- * aL : Layer alpha
- * */
-
-
-#define TILE_WIDTH 64
-#define MAX_TILE_SIZE (TILE_WIDTH * TILE_WIDTH * 4 * 1.5)
-#define ADD_ALPHA(v, a) (add_alpha_table[v][a])
-#define DISSOLVE_SEED 737893334
-#define CLAMP_TEMP(x, min, max) (temp = (x), CLAMP (temp, min, max))
-#define ABS_TEMP2(x) (temp2 = (x), (temp2 < 0) ? -temp2: temp2)
-#define CLAMP_PIXEL(x) CLAMP_TEMP (x, 0, 255)
-#define GIMP_OP_NORMAL(xL, xI, aL) CLAMP_PIXEL (ADD_ALPHA (xL, aL) + ADD_ALPHA (xI, 255 - aL))
-#define GIMP_OP_LIGHTEN_ONLY(xL, xI) MAX (xI, xL)
-#define GIMP_OP_SCREEN(xL, xI) CLAMP_PIXEL (255 ^ ADD_ALPHA (255 - xI, 255 - xL))
-#define GIMP_OP_DODGE(xL, xI) GIMP_OP_DIVIDE (255-xL, xI)
-#define GIMP_OP_ADDITION(xL, xI) CLAMP_PIXEL (xI + xL)
-#define GIMP_OP_DARKEN_ONLY(xL, xI) MIN (xI, xL)
-#define GIMP_OP_MULTIPLY(xL, xI) CLAMP_PIXEL (ADD_ALPHA (xL, xI))
-#define GIMP_OP_BURN(xL, xI) CLAMP_PIXEL (255 - GIMP_OP_DIVIDE (xL, 255 - xI))
-#define GIMP_OP_SOFT_LIGHT(xL, xI) CLAMP_PIXEL (ADD_ALPHA (xI, xI) + 2 * ADD_ALPHA (xL, ADD_ALPHA (xI,
255 - xI)))
-#define GIMP_OP_HARD_LIGHT(xL, xI) CLAMP_PIXEL (xL > 128 ? 255 ^ ADD_ALPHA (255 - xI, 2 * (255 - xL)) :
ADD_ALPHA (xI, 2 * xL))
-#define GIMP_OP_DIFFERENCE(xL, xI) CLAMP_PIXEL (ABS_TEMP2 (xI - xL))
-#define GIMP_OP_SUBTRACT(xL, xI) CLAMP_PIXEL (xI - xL)
-#define GIMP_OP_GRAIN_EXTRACT(xL, xI) CLAMP_PIXEL ((int) xI - xL + 128)
-#define GIMP_OP_GRAIN_MERGE(xL, xI) CLAMP_PIXEL ((int) xI + xL - 128)
-#define GIMP_OP_DIVIDE(xL, xI) CLAMP_PIXEL ((int) (xI) * 256 / (1 + (xL)))
+#define TILE_WIDTH 64
+#define MAX_TILE_SIZE (TILE_WIDTH * TILE_WIDTH * 4 * 1.5)
+#define DISSOLVE_SEED 737893334
typedef enum {
@@ -147,31 +120,6 @@ typedef struct {
static int cairo_rgba[4] = { CAIRO_RED, CAIRO_GREEN, CAIRO_BLUE, CAIRO_ALPHA };
static int cairo_graya[2] = { 0, CAIRO_ALPHA };
static int cairo_indexed[2] = { 0, CAIRO_ALPHA };
-static guchar add_alpha_table[256][256];
-static GOnce xcf_init_once = G_ONCE_INIT;
-
-
-static gpointer
-xcf_init (gpointer data)
-{
- int v;
- int a;
- int r;
-
- /* add_alpha_table[v][a] = v * a / 255 */
-
- for (v = 0; v < 128; v++) {
- for (a = 0; a <= v; a++) {
- r = (v * a + 127) / 255;
- add_alpha_table[v][a] = add_alpha_table[a][v] = r;
- add_alpha_table[255-v][a] = add_alpha_table[a][255-v] = a - r;
- add_alpha_table[v][255-a] = add_alpha_table[255-a][v] = v - r;
- add_alpha_table[255-v][255-a] = add_alpha_table[255-a][255-v] = (255 - a) - (v - r);
- }
- }
-
- return NULL;
-}
/* -- GDataInputStream functions -- */
@@ -985,7 +933,7 @@ _cairo_image_surface_create_from_xcf (GInputStream *istream,
performance (DEBUG_INFO, "start loading");
- g_once (&xcf_init_once, xcf_init, NULL);
+ gimp_op_init ();
performance (DEBUG_INFO, "end init");
diff --git a/extensions/file_tools/Makefile.am b/extensions/file_tools/Makefile.am
index 22c8d46..c81bbaf 100644
--- a/extensions/file_tools/Makefile.am
+++ b/extensions/file_tools/Makefile.am
@@ -7,33 +7,38 @@ ENUM_TYPES = \
enum-types.h \
enum-types.c
-HEADER_FILES = \
- cairo-blur.h \
- cairo-rotate.h \
- gth-curve.h \
- gth-curve-editor.h \
- gth-file-tool-adjust-colors.h \
- gth-file-tool-adjust-contrast.h \
- gth-file-tool-crop.h \
- gth-file-tool-curves.h \
- gth-file-tool-flip.h \
- gth-file-tool-grayscale.h \
- gth-file-tool-mirror.h \
- gth-file-tool-negative.h \
- gth-file-tool-redo.h \
- gth-file-tool-resize.h \
- gth-file-tool-rotate.h \
- gth-file-tool-rotate-left.h \
- gth-file-tool-rotate-right.h \
- gth-file-tool-rotate.h \
- gth-file-tool-save.h \
- gth-file-tool-save-as.h \
- gth-file-tool-sharpen.h \
- gth-file-tool-undo.h \
- gth-image-line-tool.h \
- gth-image-rotator.h \
- gth-points.h \
- gth-preview-tool.h \
+HEADER_FILES = \
+ cairo-blur.h \
+ cairo-effects.h \
+ cairo-rotate.h \
+ gth-curve.h \
+ gth-curve-editor.h \
+ gth-curve-preset.h \
+ gth-curve-preset-editor-dialog.h \
+ gth-file-tool-adjust-colors.h \
+ gth-file-tool-adjust-contrast.h \
+ gth-file-tool-crop.h \
+ gth-file-tool-curves.h \
+ gth-file-tool-effects.h \
+ gth-file-tool-flip.h \
+ gth-file-tool-grayscale.h \
+ gth-file-tool-lomo.h \
+ gth-file-tool-mirror.h \
+ gth-file-tool-negative.h \
+ gth-file-tool-redo.h \
+ gth-file-tool-resize.h \
+ gth-file-tool-rotate.h \
+ gth-file-tool-rotate-left.h \
+ gth-file-tool-rotate-right.h \
+ gth-file-tool-rotate.h \
+ gth-file-tool-save.h \
+ gth-file-tool-save-as.h \
+ gth-file-tool-sharpen.h \
+ gth-file-tool-undo.h \
+ gth-image-line-tool.h \
+ gth-image-rotator.h \
+ gth-points.h \
+ gth-preview-tool.h \
preferences.h
enum-types.h: $(HEADER_FILES)
@@ -55,36 +60,41 @@ enum-types.c: $(HEADER_FILES)
$^> xgen-$(@F) \
&& mv -f xgen-$(@F) enum-types.c )
-libfile_tools_la_SOURCES = \
- $(ENUM_TYPES) \
- $(HEADER_FILES) \
- cairo-blur.c \
- cairo-rotate.c \
- callbacks.c \
- callbacks.h \
- gth-curve.c \
- gth-curve-editor.c \
- gth-file-tool-adjust-colors.c \
- gth-file-tool-adjust-contrast.c \
- gth-file-tool-crop.c \
- gth-file-tool-curves.c \
- gth-file-tool-flip.c \
- gth-file-tool-grayscale.c \
- gth-file-tool-mirror.c \
- gth-file-tool-negative.c \
- gth-file-tool-redo.c \
- gth-file-tool-resize.c \
- gth-file-tool-rotate.c \
- gth-file-tool-rotate-left.c \
- gth-file-tool-rotate-right.c \
- gth-file-tool-save.c \
- gth-file-tool-save-as.c \
- gth-file-tool-sharpen.c \
- gth-file-tool-undo.c \
- gth-image-line-tool.c \
- gth-image-rotator.c \
- gth-points.c \
- gth-preview-tool.c \
+libfile_tools_la_SOURCES = \
+ $(ENUM_TYPES) \
+ $(HEADER_FILES) \
+ cairo-blur.c \
+ cairo-effects.c \
+ cairo-rotate.c \
+ callbacks.c \
+ callbacks.h \
+ gth-curve.c \
+ gth-curve-editor.c \
+ gth-curve-preset.c \
+ gth-curve-preset-editor-dialog.c \
+ gth-file-tool-adjust-colors.c \
+ gth-file-tool-adjust-contrast.c \
+ gth-file-tool-crop.c \
+ gth-file-tool-curves.c \
+ gth-file-tool-effects.c \
+ gth-file-tool-flip.c \
+ gth-file-tool-grayscale.c \
+ gth-file-tool-lomo.c \
+ gth-file-tool-mirror.c \
+ gth-file-tool-negative.c \
+ gth-file-tool-redo.c \
+ gth-file-tool-resize.c \
+ gth-file-tool-rotate.c \
+ gth-file-tool-rotate-left.c \
+ gth-file-tool-rotate-right.c \
+ gth-file-tool-save.c \
+ gth-file-tool-save-as.c \
+ gth-file-tool-sharpen.c \
+ gth-file-tool-undo.c \
+ gth-image-line-tool.c \
+ gth-image-rotator.c \
+ gth-points.c \
+ gth-preview-tool.c \
main.c
libfile_tools_la_CFLAGS = $(GTHUMB_CFLAGS) -I$(top_srcdir) -I$(top_builddir)/gthumb
diff --git a/extensions/file_tools/cairo-blur.h b/extensions/file_tools/cairo-blur.h
index c2a2e8d..a563975 100644
--- a/extensions/file_tools/cairo-blur.h
+++ b/extensions/file_tools/cairo-blur.h
@@ -19,8 +19,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef GDK_PIXBUF_BLUR_H
-#define GDK_PIXBUF_BLUR_H
+#ifndef CAIRO_BLUR_H
+#define CAIRO_BLUR_H
#include <glib.h>
#include <cairo.h>
@@ -39,4 +39,4 @@ gboolean _cairo_image_surface_sharpen (cairo_surface_t *source,
G_END_DECLS
-#endif /* GDK_PIXBUF_BLUR_H */
+#endif /* CAIRO_BLUR_H */
diff --git a/extensions/file_tools/cairo-effects.c b/extensions/file_tools/cairo-effects.c
new file mode 100644
index 0000000..63d710a
--- /dev/null
+++ b/extensions/file_tools/cairo-effects.c
@@ -0,0 +1,450 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2014 The Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <math.h>
+#include "cairo-effects.h"
+#include "gth-curve.h"
+
+
+gboolean
+cairo_image_surface_apply_curves (cairo_surface_t *source,
+ GthCurve **curve,
+ GthAsyncTask *task)
+{
+ long *value_map[GTH_HISTOGRAM_N_CHANNELS];
+ int c, v;
+ int width;
+ int height;
+ int source_stride;
+ unsigned char *p_source_line;
+ int x, y;
+ gboolean cancelled = FALSE;
+ double progress;
+ unsigned char *p_source;
+ unsigned char image_red, image_green, image_blue, image_alpha;
+
+ for (c = GTH_HISTOGRAM_CHANNEL_VALUE; c <= GTH_HISTOGRAM_CHANNEL_BLUE; c++) {
+ value_map[c] = g_new (long, 256);
+ for (v = 0; v <= 255; v++) {
+ double u = gth_curve_eval (curve[c], v);
+ if (c > GTH_HISTOGRAM_CHANNEL_VALUE)
+ u = value_map[GTH_HISTOGRAM_CHANNEL_VALUE][(int)u];
+ value_map[c][v] = u;
+ }
+ }
+
+ width = cairo_image_surface_get_width (source);
+ height = cairo_image_surface_get_height (source);
+ source_stride = cairo_image_surface_get_stride (source);
+
+ p_source_line = _cairo_image_surface_flush_and_get_data (source);
+ for (y = 0; y < height; y++) {
+ gth_async_task_get_data (task, NULL, &cancelled, NULL);
+ if (cancelled)
+ break;
+
+ progress = (double) y / height;
+ gth_async_task_set_data (task, NULL, NULL, &progress);
+
+ p_source = p_source_line;
+ for (x = 0; x < width; x++) {
+ CAIRO_GET_RGBA (p_source, image_red, image_green, image_blue, image_alpha);
+
+ image_red = value_map[GTH_HISTOGRAM_CHANNEL_RED][image_red];
+ image_green = value_map[GTH_HISTOGRAM_CHANNEL_GREEN][image_green];
+ image_blue = value_map[GTH_HISTOGRAM_CHANNEL_BLUE][image_blue];
+
+ CAIRO_SET_RGBA (p_source, image_red, image_green, image_blue, image_alpha);
+
+ p_source += 4;
+ }
+ p_source_line += source_stride;
+ }
+ cairo_surface_mark_dirty (source);
+
+ for (c = GTH_HISTOGRAM_CHANNEL_VALUE; c <= GTH_HISTOGRAM_CHANNEL_BLUE; c++)
+ g_free (value_map[c]);
+
+ return ! cancelled;
+}
+
+
+gboolean
+cairo_image_surface_apply_vignette (cairo_surface_t *source,
+ GthCurve **curve,
+ GthAsyncTask *task)
+{
+ gboolean local_curves;
+ long *value_map[GTH_HISTOGRAM_N_CHANNELS];
+ int c, v;
+ int width;
+ int height;
+ int source_stride;
+ unsigned char *p_source_line;
+ int x, y;
+ gboolean cancelled = FALSE;
+ double progress;
+ unsigned char *p_source;
+ unsigned char image_red, image_green, image_blue, image_alpha;
+ unsigned char red, green, blue, alpha;
+ double center_x, center_y, d, min_d, max_d;
+ unsigned char temp;
+ GthPoint f1, f2, p;
+
+ gimp_op_init ();
+
+ local_curves = (curve == NULL);
+ if (local_curves) {
+ curve = g_new (GthCurve *, GTH_HISTOGRAM_N_CHANNELS);
+ curve[GTH_HISTOGRAM_CHANNEL_VALUE] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 3, 0,0,
152,103, 255,255);
+ curve[GTH_HISTOGRAM_CHANNEL_RED] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 0);
+ curve[GTH_HISTOGRAM_CHANNEL_GREEN] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 0);
+ curve[GTH_HISTOGRAM_CHANNEL_BLUE] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 0);
+ }
+
+ for (c = GTH_HISTOGRAM_CHANNEL_VALUE; c <= GTH_HISTOGRAM_CHANNEL_BLUE; c++) {
+ value_map[c] = g_new (long, 256);
+ for (v = 0; v <= 255; v++) {
+ double u = gth_curve_eval (curve[c], v);
+ if (c > GTH_HISTOGRAM_CHANNEL_VALUE)
+ u = value_map[GTH_HISTOGRAM_CHANNEL_VALUE][(int)u];
+ value_map[c][v] = u;
+ }
+ }
+
+ width = cairo_image_surface_get_width (source);
+ height = cairo_image_surface_get_height (source);
+ source_stride = cairo_image_surface_get_stride (source);
+
+ center_x = width / 2.0;
+ center_y = height / 2.0;
+ max_d = 2 * sqrt (SQR (center_x) + SQR (center_y));
+
+ {
+ double a = MAX (width, height) / 2.0;
+ double b = MIN (height, width) / 2.0;
+
+ a = a - (a / 10);
+ b = b - (b / 10);
+
+ double e = sqrt (1.0 - SQR (b) / SQR (a));
+ double c = a * e;
+ min_d = 2 * sqrt (SQR (b) + SQR (c));
+
+ if (width > height) {
+ f1.x = center_x - c;
+ f1.y = center_y;
+ f2.x = center_x + c;
+ f2.y = center_y;
+ }
+ else {
+ f1.x = center_x;
+ f1.y = center_y - c;
+ f2.x = center_x;
+ f2.y = center_y + c;
+ }
+ }
+
+ p_source_line = _cairo_image_surface_flush_and_get_data (source);
+ for (y = 0; y < height; y++) {
+ gth_async_task_get_data (task, NULL, &cancelled, NULL);
+ if (cancelled)
+ break;
+
+ progress = (double) y / height;
+ gth_async_task_set_data (task, NULL, NULL, &progress);
+
+ p_source = p_source_line;
+ for (x = 0; x < width; x++) {
+ p.x = x;
+ p.y = y;
+ d = gth_point_distance (&p, &f1) + gth_point_distance (&p, &f2);
+ if (d >= min_d) {
+ CAIRO_GET_RGBA (p_source, image_red, image_green, image_blue, image_alpha);
+ red = value_map[GTH_HISTOGRAM_CHANNEL_RED][image_red];
+ green = value_map[GTH_HISTOGRAM_CHANNEL_GREEN][image_green];
+ blue = value_map[GTH_HISTOGRAM_CHANNEL_BLUE][image_blue];
+
+ if (d <= max_d)
+ alpha = 255 * ((d - min_d) / (max_d - min_d));
+ else
+ alpha = 255;
+
+ p_source[CAIRO_RED] = GIMP_OP_NORMAL (red, image_red, alpha);
+ p_source[CAIRO_GREEN] = GIMP_OP_NORMAL (green, image_green, alpha);
+ p_source[CAIRO_BLUE] = GIMP_OP_NORMAL (blue, image_blue, alpha);
+ p_source[CAIRO_ALPHA] = GIMP_OP_NORMAL (255, image_alpha, alpha);
+ }
+
+ p_source += 4;
+ }
+ p_source_line += source_stride;
+ }
+ cairo_surface_mark_dirty (source);
+
+ if (local_curves) {
+ for (c = GTH_HISTOGRAM_CHANNEL_VALUE; c <= GTH_HISTOGRAM_CHANNEL_BLUE; c++) {
+ g_object_unref (curve[c]);
+ g_free (value_map[c]);
+ }
+ }
+
+ return ! cancelled;
+}
+
+
+gboolean
+cairo_image_surface_apply_bcs (cairo_surface_t *source,
+ double brightness,
+ double contrast,
+ double saturation,
+ GthAsyncTask *task)
+{
+ PixbufCache *cache;
+ int i;
+ double midtone_distance[256];
+ int width;
+ int height;
+ int source_stride;
+ unsigned char *p_source_line;
+ int x, y;
+ gboolean cancelled = FALSE;
+ double progress;
+ unsigned char *p_source;
+ unsigned char image_red, image_green, image_blue, image_alpha;
+ unsigned char values[4];
+ unsigned char red, green, blue, alpha;
+ unsigned char temp, min, max, lightness, value;
+
+ gimp_op_init ();
+ cache = pixbuf_cache_new ();
+ for (i = 0; i < 256; i++)
+ midtone_distance[i] = 0.667 * (1 - SQR (((double) i - 127.0) / 127.0));
+
+ if (saturation < 0)
+ saturation = tan (saturation * G_PI_2);
+
+ width = cairo_image_surface_get_width (source);
+ height = cairo_image_surface_get_height (source);
+ source_stride = cairo_image_surface_get_stride (source);
+ p_source_line = _cairo_image_surface_flush_and_get_data (source);
+
+ for (y = 0; y < height; y++) {
+ gth_async_task_get_data (task, NULL, &cancelled, NULL);
+ if (cancelled)
+ break;
+
+ progress = (double) y / height;
+ gth_async_task_set_data (task, NULL, NULL, &progress);
+
+ p_source = p_source_line;
+ for (x = 0; x < width; x++) {
+ int channel;
+
+ CAIRO_GET_RGBA (p_source, values[0], values[1], values[2], values[3]);
+
+ /* brightness / contrast */
+
+ for (channel = 0; channel < 3; channel++) {
+ value = values[channel];
+
+ if (! pixbuf_cache_get (cache, channel + 1, &value)) {
+ int tmp = value;
+
+ if (brightness > 0)
+ tmp = interpolate_value (value, 0, brightness);
+ else if (brightness < 0)
+ tmp = interpolate_value (value, 255, - brightness);
+ value = CLAMP (tmp, 0, 255);
+
+ if (contrast < 0)
+ tmp = interpolate_value (value, 127, tan (contrast * G_PI_2));
+ else if (contrast > 0)
+ tmp = interpolate_value (value, 127, contrast);
+ value = CLAMP (tmp, 0, 255);
+
+ pixbuf_cache_set (cache, channel + 1, values[channel], value);
+ }
+
+ values[channel] = value;
+ }
+
+ /* saturation */
+
+ if (saturation != 0.0) {
+ guchar min, max, lightness;
+ int tmp;
+
+ max = MAX (MAX (values[0], values[1]), values[2]);
+ min = MIN (MIN (values[0], values[1]), values[2]);
+ lightness = (max + min) / 2;
+
+ tmp = interpolate_value (values[0], lightness, saturation);
+ values[0] = CLAMP (tmp, 0, 255);
+
+ tmp = interpolate_value (values[1], lightness, saturation);
+ values[1] = CLAMP (tmp, 0, 255);
+
+ tmp = interpolate_value (values[2], lightness, saturation);
+ values[2] = CLAMP (tmp, 0, 255);
+ }
+
+ CAIRO_SET_RGBA (p_source, values[0], values[1], values[2], values[3]);
+
+ p_source += 4;
+ }
+ p_source_line += source_stride;
+ }
+ cairo_surface_mark_dirty (source);
+
+ pixbuf_cache_free (cache);
+
+ return ! cancelled;
+}
+
+
+gboolean
+cairo_image_surface_colorize (cairo_surface_t *source,
+ guchar color_red,
+ guchar color_green,
+ guchar color_blue,
+ guchar color_alpha,
+ GthAsyncTask *task)
+{
+ int i;
+ double midtone_distance[256];
+ int width;
+ int height;
+ int source_stride;
+ unsigned char *p_source_line;
+ int x, y;
+ gboolean cancelled = FALSE;
+ double progress;
+ unsigned char *p_source;
+ unsigned char image_red, image_green, image_blue, image_alpha;
+ unsigned char red, green, blue, alpha;
+ unsigned char temp, min, max, lightness;
+
+ gimp_op_init ();
+ for (i = 0; i < 256; i++)
+ midtone_distance[i] = 0.667 * (1 - SQR (((double) i - 127.0) / 127.0));
+
+ width = cairo_image_surface_get_width (source);
+ height = cairo_image_surface_get_height (source);
+ source_stride = cairo_image_surface_get_stride (source);
+ p_source_line = _cairo_image_surface_flush_and_get_data (source);
+
+ for (y = 0; y < height; y++) {
+ gth_async_task_get_data (task, NULL, &cancelled, NULL);
+ if (cancelled)
+ break;
+
+ progress = (double) y / height;
+ gth_async_task_set_data (task, NULL, NULL, &progress);
+
+ p_source = p_source_line;
+ for (x = 0; x < width; x++) {
+ CAIRO_GET_RGBA (p_source, image_red, image_green, image_blue, image_alpha);
+
+ /* desaturate */
+
+ max = MAX (MAX (image_red, image_green), image_blue);
+ min = MIN (MIN (image_red, image_green), image_blue);
+ lightness = (max + min) / 2;
+
+ /* colorize */
+
+ red = lightness + color_red * midtone_distance[lightness];
+ green = lightness + color_green * midtone_distance[lightness];
+ blue = lightness + color_blue * midtone_distance[lightness];
+ alpha = ADD_ALPHA (image_alpha, color_alpha);
+
+ p_source[CAIRO_RED] = GIMP_OP_NORMAL (red, image_red, alpha);
+ p_source[CAIRO_GREEN] = GIMP_OP_NORMAL (green, image_green, alpha);
+ p_source[CAIRO_BLUE] = GIMP_OP_NORMAL (blue, image_blue, alpha);
+ p_source[CAIRO_ALPHA] = GIMP_OP_NORMAL (255, image_alpha, alpha);
+
+ p_source += 4;
+ }
+ p_source_line += source_stride;
+ }
+ cairo_surface_mark_dirty (source);
+
+ return ! cancelled;
+}
+
+
+gboolean
+cairo_image_surface_add_color (cairo_surface_t *source,
+ guchar color_red,
+ guchar color_green,
+ guchar color_blue,
+ guchar color_alpha,
+ GthAsyncTask *task)
+{
+ int i;
+ int width;
+ int height;
+ int source_stride;
+ unsigned char *p_source_line;
+ int x, y;
+ gboolean cancelled = FALSE;
+ double progress;
+ unsigned char *p_source;
+ unsigned char image_red, image_green, image_blue, image_alpha;
+ unsigned char temp, alpha;
+
+ gimp_op_init ();
+
+ width = cairo_image_surface_get_width (source);
+ height = cairo_image_surface_get_height (source);
+ source_stride = cairo_image_surface_get_stride (source);
+ p_source_line = _cairo_image_surface_flush_and_get_data (source);
+
+ for (y = 0; y < height; y++) {
+ gth_async_task_get_data (task, NULL, &cancelled, NULL);
+ if (cancelled)
+ break;
+
+ progress = (double) y / height;
+ gth_async_task_set_data (task, NULL, NULL, &progress);
+
+ p_source = p_source_line;
+ for (x = 0; x < width; x++) {
+ CAIRO_GET_RGBA (p_source, image_red, image_green, image_blue, image_alpha);
+
+ alpha = ADD_ALPHA (image_alpha, color_alpha);
+
+ p_source[CAIRO_RED] = GIMP_OP_NORMAL (color_red, image_red, alpha);
+ p_source[CAIRO_GREEN] = GIMP_OP_NORMAL (color_green, image_green, alpha);
+ p_source[CAIRO_BLUE] = GIMP_OP_NORMAL (color_blue, image_blue, alpha);
+ p_source[CAIRO_ALPHA] = GIMP_OP_NORMAL (255, image_alpha, alpha);
+
+ p_source += 4;
+ }
+ p_source_line += source_stride;
+ }
+ cairo_surface_mark_dirty (source);
+
+ return ! cancelled;
+}
+
diff --git a/extensions/file_tools/cairo-effects.h b/extensions/file_tools/cairo-effects.h
new file mode 100644
index 0000000..0a5dec2
--- /dev/null
+++ b/extensions/file_tools/cairo-effects.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2014 The Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CAIRO_EFFECTS_H
+#define CAIRO_EFFECTS_H
+
+#include <glib.h>
+#include <cairo.h>
+#include <gthumb.h>
+#include "gth-curve.h"
+
+G_BEGIN_DECLS
+
+gboolean cairo_image_surface_apply_curves (cairo_surface_t *source,
+ GthCurve **curve,
+ GthAsyncTask *task);
+gboolean cairo_image_surface_apply_vignette (cairo_surface_t *source,
+ GthCurve **curve,
+ GthAsyncTask *task);
+gboolean cairo_image_surface_apply_bcs (cairo_surface_t *source,
+ double brightness,
+ double contrast,
+ double saturation,
+ GthAsyncTask *task);
+gboolean cairo_image_surface_colorize (cairo_surface_t *source,
+ guchar color_red,
+ guchar color_green,
+ guchar color_blue,
+ guchar color_alpha,
+ GthAsyncTask *task);
+gboolean cairo_image_surface_add_color (cairo_surface_t *source,
+ guchar color_red,
+ guchar color_green,
+ guchar color_blue,
+ guchar color_alpha,
+ GthAsyncTask *task);
+
+G_END_DECLS
+
+#endif /* CAIRO_EFFECTS_H */
diff --git a/extensions/file_tools/data/ui/Makefile.am b/extensions/file_tools/data/ui/Makefile.am
index 3db21b9..8d6d1e5 100644
--- a/extensions/file_tools/data/ui/Makefile.am
+++ b/extensions/file_tools/data/ui/Makefile.am
@@ -4,6 +4,7 @@ ui_DATA = \
adjust-contrast-options.ui \
crop-options.ui \
curves-options.ui \
+ effects-options.ui \
grayscale-options.ui \
resize-options.ui \
rotate-options.ui \
diff --git a/extensions/file_tools/data/ui/effects-options.ui
b/extensions/file_tools/data/ui/effects-options.ui
new file mode 100644
index 0000000..226e60f
--- /dev/null
+++ b/extensions/file_tools/data/ui/effects-options.ui
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.18.3 -->
+<interface>
+ <requires lib="gtk+" version="3.12"/>
+ <object class="GtkAlignment" id="options">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkBox" id="box2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">12</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkBox" id="filter_grid_box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/extensions/file_tools/gth-file-tool-effects.c b/extensions/file_tools/gth-file-tool-effects.c
new file mode 100644
index 0000000..a93cdb0
--- /dev/null
+++ b/extensions/file_tools/gth-file-tool-effects.c
@@ -0,0 +1,655 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2014 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <math.h>
+#include <gthumb.h>
+#include <extensions/image_viewer/image-viewer.h>
+#include "cairo-blur.h"
+#include "cairo-effects.h"
+#include "gth-curve.h"
+#include "gth-file-tool-effects.h"
+#include "gth-preview-tool.h"
+
+
+#define GET_WIDGET(x) (_gtk_builder_get_widget (self->priv->builder, (x)))
+#define APPLY_DELAY 150
+#define PREVIEW_SIZE 0.9
+
+
+G_DEFINE_TYPE (GthFileToolEffects, gth_file_tool_effects, GTH_TYPE_IMAGE_VIEWER_PAGE_TOOL)
+
+
+struct _GthFileToolEffectsPrivate {
+ cairo_surface_t *destination;
+ cairo_surface_t *preview;
+ GtkBuilder *builder;
+ GthTask *image_task;
+ GthImageViewerTool *preview_tool;
+ guint apply_event;
+ gboolean apply_to_original;
+ gboolean closing;
+ gboolean view_original;
+ int method;
+ int last_applied_method;
+ GtkWidget *filter_grid;
+};
+
+
+static void apply_changes (GthFileToolEffects *self);
+
+
+static void
+image_task_completed_cb (GthTask *task,
+ GError *error,
+ gpointer user_data)
+{
+ GthFileToolEffects *self = user_data;
+ GthImage *destination_image;
+
+ g_signal_handlers_disconnect_matched (task, G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL,
image_task_completed_cb, self);
+ self->priv->image_task = NULL;
+
+ if (self->priv->closing) {
+ g_object_unref (task);
+ gth_image_viewer_page_tool_reset_image (GTH_IMAGE_VIEWER_PAGE_TOOL (self));
+ return;
+ }
+
+ if (error != NULL) {
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ apply_changes (self);
+ g_object_unref (task);
+ return;
+ }
+
+ destination_image = gth_image_task_get_destination (GTH_IMAGE_TASK (task));
+ if (destination_image == NULL) {
+ g_object_unref (task);
+ return;
+ }
+
+ cairo_surface_destroy (self->priv->destination);
+ self->priv->destination = gth_image_get_cairo_surface (destination_image);
+ self->priv->last_applied_method = self->priv->method;
+
+ if (self->priv->apply_to_original) {
+ if (self->priv->destination != NULL) {
+ GtkWidget *window;
+ GtkWidget *viewer_page;
+
+ window = gth_file_tool_get_window (GTH_FILE_TOOL (self));
+ viewer_page = gth_browser_get_viewer_page (GTH_BROWSER (window));
+ gth_image_viewer_page_set_image (GTH_IMAGE_VIEWER_PAGE (viewer_page),
self->priv->destination, TRUE);
+ }
+
+ gth_file_tool_hide_options (GTH_FILE_TOOL (self));
+ }
+ else {
+ if (! self->priv->view_original)
+ gth_preview_tool_set_image (GTH_PREVIEW_TOOL (self->priv->preview_tool),
self->priv->destination);
+ }
+
+ g_object_unref (task);
+}
+
+
+static gboolean
+apply_cb (gpointer user_data)
+{
+ GthFileToolEffects *self = user_data;
+ GtkWidget *window;
+
+ if (self->priv->apply_event != 0) {
+ g_source_remove (self->priv->apply_event);
+ self->priv->apply_event = 0;
+ }
+
+ if (self->priv->image_task != NULL) {
+ gth_task_cancel (self->priv->image_task);
+ return FALSE;
+ }
+
+ window = gth_file_tool_get_window (GTH_FILE_TOOL (self));
+
+ self->priv->image_task = gth_filter_grid_get_task (GTH_FILTER_GRID (self->priv->filter_grid),
self->priv->method);
+ if (self->priv->apply_to_original)
+ gth_image_task_set_source_surface (GTH_IMAGE_TASK (self->priv->image_task),
gth_image_viewer_page_tool_get_source (GTH_IMAGE_VIEWER_PAGE_TOOL (self)));
+ else
+ gth_image_task_set_source_surface (GTH_IMAGE_TASK (self->priv->image_task),
self->priv->preview);
+ g_signal_connect (self->priv->image_task,
+ "completed",
+ G_CALLBACK (image_task_completed_cb),
+ self);
+ gth_browser_exec_task (GTH_BROWSER (window), self->priv->image_task, FALSE);
+
+ return FALSE;
+}
+
+
+static void
+apply_changes (GthFileToolEffects *self)
+{
+ if (self->priv->apply_event != 0) {
+ g_source_remove (self->priv->apply_event);
+ self->priv->apply_event = 0;
+ }
+ self->priv->apply_event = g_timeout_add (APPLY_DELAY, apply_cb, self);
+}
+
+
+static void
+gth_file_tool_effects_reset_image (GthImageViewerPageTool *base)
+{
+ GthFileToolEffects *self = GTH_FILE_TOOL_EFFECTS (base);
+
+ if (self->priv->image_task != NULL) {
+ self->priv->closing = TRUE;
+ return;
+ }
+
+ if (self->priv->apply_event != 0) {
+ g_source_remove (self->priv->apply_event);
+ self->priv->apply_event = 0;
+ }
+
+ gth_image_viewer_page_reset (GTH_IMAGE_VIEWER_PAGE (gth_image_viewer_page_tool_get_page
(GTH_IMAGE_VIEWER_PAGE_TOOL (self))));
+ gth_file_tool_hide_options (GTH_FILE_TOOL (self));
+}
+
+
+static void
+filter_grid_activated_cb (GthFilterGrid *filter_grid,
+ int filter_id,
+ gpointer user_data)
+{
+ GthFileToolEffects *self = user_data;
+
+ self->priv->view_original = (filter_id == GTH_FILTER_GRID_NO_FILTER);
+ if (self->priv->view_original) {
+ gth_preview_tool_set_image (GTH_PREVIEW_TOOL (self->priv->preview_tool), self->priv->preview);
+ }
+ else if (filter_id == self->priv->last_applied_method) {
+ gth_preview_tool_set_image (GTH_PREVIEW_TOOL (self->priv->preview_tool),
self->priv->destination);
+ }
+ else {
+ self->priv->method = filter_id;
+ apply_changes (self);
+ }
+}
+
+
+static GtkWidget *
+gth_file_tool_effects_get_options (GthFileTool *base)
+{
+ GthFileToolEffects *self;
+ GtkWidget *window;
+ GtkWidget *viewer_page;
+ GtkWidget *viewer;
+ cairo_surface_t *source;
+ GtkWidget *options;
+ int width, height;
+ GtkAllocation allocation;
+
+ self = (GthFileToolEffects *) base;
+
+ window = gth_file_tool_get_window (base);
+ viewer_page = gth_browser_get_viewer_page (GTH_BROWSER (window));
+ if (! GTH_IS_IMAGE_VIEWER_PAGE (viewer_page))
+ return NULL;
+
+ cairo_surface_destroy (self->priv->destination);
+ cairo_surface_destroy (self->priv->preview);
+
+ viewer = gth_image_viewer_page_get_image_viewer (GTH_IMAGE_VIEWER_PAGE (viewer_page));
+ source = gth_image_viewer_page_tool_get_source (GTH_IMAGE_VIEWER_PAGE_TOOL (self));
+ if (source == NULL)
+ return NULL;
+
+ width = cairo_image_surface_get_width (source);
+ height = cairo_image_surface_get_height (source);
+ gtk_widget_get_allocation (GTK_WIDGET (viewer), &allocation);
+ if (scale_keeping_ratio (&width, &height, PREVIEW_SIZE * allocation.width, PREVIEW_SIZE *
allocation.height, FALSE))
+ self->priv->preview = _cairo_image_surface_scale_bilinear (source, width, height);
+ else
+ self->priv->preview = cairo_surface_reference (source);
+
+ self->priv->destination = cairo_surface_reference (self->priv->preview);
+ self->priv->apply_to_original = FALSE;
+ self->priv->closing = FALSE;
+
+ self->priv->builder = _gtk_builder_new_from_file ("effects-options.ui", "file_tools");
+ options = _gtk_builder_get_widget (self->priv->builder, "options");
+ gtk_widget_show (options);
+
+ self->priv->filter_grid = gth_filter_grid_new ();
+ gth_hook_invoke ("add-special-effect", self->priv->filter_grid);
+ gtk_widget_show (self->priv->filter_grid);
+ gtk_box_pack_start (GTK_BOX (GET_WIDGET ("filter_grid_box")), self->priv->filter_grid, TRUE, FALSE,
0);
+
+ g_signal_connect (self->priv->filter_grid,
+ "activated",
+ G_CALLBACK (filter_grid_activated_cb),
+ self);
+
+ self->priv->preview_tool = gth_preview_tool_new ();
+ gth_preview_tool_set_image (GTH_PREVIEW_TOOL (self->priv->preview_tool), self->priv->preview);
+ gth_image_viewer_set_tool (GTH_IMAGE_VIEWER (viewer), self->priv->preview_tool);
+ gth_filter_grid_generate_previews (GTH_FILTER_GRID (self->priv->filter_grid), source);
+
+ return options;
+}
+
+
+static void
+gth_file_tool_effects_destroy_options (GthFileTool *base)
+{
+ GthFileToolEffects *self;
+ GtkWidget *window;
+ GtkWidget *viewer_page;
+
+ self = (GthFileToolEffects *) base;
+
+ if (self->priv->apply_event != 0) {
+ g_source_remove (self->priv->apply_event);
+ self->priv->apply_event = 0;
+ }
+
+ window = gth_file_tool_get_window (GTH_FILE_TOOL (self));
+ viewer_page = gth_browser_get_viewer_page (GTH_BROWSER (window));
+ gth_image_viewer_page_reset_viewer_tool (GTH_IMAGE_VIEWER_PAGE (viewer_page));
+ gth_viewer_page_update_sensitivity (GTH_VIEWER_PAGE (viewer_page));
+
+ _g_clear_object (&self->priv->builder);
+
+ _cairo_clear_surface (&self->priv->preview);
+ _cairo_clear_surface (&self->priv->destination);
+ self->priv->method = GTH_FILTER_GRID_NO_FILTER;
+ self->priv->last_applied_method = GTH_FILTER_GRID_NO_FILTER;
+}
+
+
+static void
+gth_file_tool_effects_apply_options (GthFileTool *base)
+{
+ GthFileToolEffects *self;
+
+ self = (GthFileToolEffects *) base;
+
+ if (! self->priv->view_original) {
+ self->priv->apply_to_original = TRUE;
+ apply_changes (self);
+ }
+}
+
+
+static void
+gth_file_tool_effects_finalize (GObject *object)
+{
+ GthFileToolEffects *self;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GTH_IS_FILE_TOOL_EFFECTS (object));
+
+ self = (GthFileToolEffects *) object;
+
+ _g_clear_object (&self->priv->builder);
+ _cairo_clear_surface (&self->priv->preview);
+ _cairo_clear_surface (&self->priv->destination);
+
+ G_OBJECT_CLASS (gth_file_tool_effects_parent_class)->finalize (object);
+}
+
+
+static void
+gth_file_tool_effects_class_init (GthFileToolEffectsClass *klass)
+{
+ GObjectClass *gobject_class;
+ GthFileToolClass *file_tool_class;
+ GthImageViewerPageToolClass *image_viewer_page_tool_class;
+
+ g_type_class_add_private (klass, sizeof (GthFileToolEffectsPrivate));
+
+ gobject_class = (GObjectClass*) klass;
+ gobject_class->finalize = gth_file_tool_effects_finalize;
+
+ file_tool_class = GTH_FILE_TOOL_CLASS (klass);
+ file_tool_class->get_options = gth_file_tool_effects_get_options;
+ file_tool_class->destroy_options = gth_file_tool_effects_destroy_options;
+ file_tool_class->apply_options = gth_file_tool_effects_apply_options;
+
+ image_viewer_page_tool_class = (GthImageViewerPageToolClass *) klass;
+ image_viewer_page_tool_class->reset_image = gth_file_tool_effects_reset_image;
+}
+
+
+static void
+gth_file_tool_effects_init (GthFileToolEffects *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_FILE_TOOL_EFFECTS,
GthFileToolEffectsPrivate);
+ self->priv->preview = NULL;
+ self->priv->destination = NULL;
+ self->priv->builder = NULL;
+ self->priv->method = GTH_FILTER_GRID_NO_FILTER;
+ self->priv->last_applied_method = GTH_FILTER_GRID_NO_FILTER;
+ self->priv->view_original = FALSE;
+
+ gth_file_tool_construct (GTH_FILE_TOOL (self),
+ "special-effects-symbolic",
+ _("Special Effects"),
+ GTH_TOOLBOX_SECTION_COLORS);
+}
+
+
+/* -- Warmer -- */
+
+
+static gpointer
+warmer_exec (GthAsyncTask *task,
+ gpointer user_data)
+{
+ cairo_surface_t *original;
+ cairo_surface_t *source;
+ GthCurve *curve[GTH_HISTOGRAM_N_CHANNELS];
+ gboolean cancelled = FALSE;
+
+ original = gth_image_task_get_source_surface (GTH_IMAGE_TASK (task));
+ source = _cairo_image_surface_copy (original);
+
+ curve[GTH_HISTOGRAM_CHANNEL_VALUE] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 0);
+ curve[GTH_HISTOGRAM_CHANNEL_RED] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 3, 0,0, 117,136,
255,255);
+ curve[GTH_HISTOGRAM_CHANNEL_GREEN] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 0);
+ curve[GTH_HISTOGRAM_CHANNEL_BLUE] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 3, 0,0, 136,119,
255,255);
+ if (cairo_image_surface_apply_curves (source, curve, task))
+ gth_image_task_set_destination_surface (GTH_IMAGE_TASK (task), source);
+
+ g_object_unref (curve[GTH_HISTOGRAM_CHANNEL_BLUE]);
+ g_object_unref (curve[GTH_HISTOGRAM_CHANNEL_GREEN]);
+ g_object_unref (curve[GTH_HISTOGRAM_CHANNEL_RED]);
+ g_object_unref (curve[GTH_HISTOGRAM_CHANNEL_VALUE]);
+ cairo_surface_destroy (source);
+ cairo_surface_destroy (original);
+
+ return NULL;
+}
+
+
+void
+warmer_add_to_special_effects (GthFilterGrid *grid)
+{
+ gth_filter_grid_add_filter (grid,
+ GTH_FILTER_GRID_NEW_FILTER_ID,
+ gth_image_task_new (_("Applying changes"), NULL, warmer_exec, NULL, NULL,
NULL),
+ /* Translators: this is the name of a filter that produces warmer colors
*/
+ _("Warmer"),
+ NULL);
+}
+
+
+/* -- Cooler -- */
+
+
+static gpointer
+cooler_exec (GthAsyncTask *task,
+ gpointer user_data)
+{
+ cairo_surface_t *original;
+ cairo_surface_t *source;
+ GthCurve *curve[GTH_HISTOGRAM_N_CHANNELS];
+ gboolean cancelled = FALSE;
+
+ original = gth_image_task_get_source_surface (GTH_IMAGE_TASK (task));
+ source = _cairo_image_surface_copy (original);
+
+ curve[GTH_HISTOGRAM_CHANNEL_VALUE] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 0);
+ curve[GTH_HISTOGRAM_CHANNEL_RED] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 3, 0,0, 136,119,
255,255);
+ curve[GTH_HISTOGRAM_CHANNEL_GREEN] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 0);
+ curve[GTH_HISTOGRAM_CHANNEL_BLUE] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 3, 0,0, 117,136,
255,255);
+ if (cairo_image_surface_apply_curves (source, curve, task))
+ gth_image_task_set_destination_surface (GTH_IMAGE_TASK (task), source);
+
+ g_object_unref (curve[GTH_HISTOGRAM_CHANNEL_BLUE]);
+ g_object_unref (curve[GTH_HISTOGRAM_CHANNEL_GREEN]);
+ g_object_unref (curve[GTH_HISTOGRAM_CHANNEL_RED]);
+ g_object_unref (curve[GTH_HISTOGRAM_CHANNEL_VALUE]);
+ cairo_surface_destroy (source);
+ cairo_surface_destroy (original);
+
+ return NULL;
+}
+
+
+void
+cooler_add_to_special_effects (GthFilterGrid *grid)
+{
+ gth_filter_grid_add_filter (grid,
+ GTH_FILTER_GRID_NEW_FILTER_ID,
+ gth_image_task_new (_("Applying changes"), NULL, cooler_exec, NULL, NULL,
NULL),
+ /* Translators: this is the name of a filter that produces cooler colors
*/
+ _("Cooler"),
+ NULL);
+}
+
+
+/* -- Instagram -- */
+
+
+static gpointer
+instagram_exec (GthAsyncTask *task,
+ gpointer user_data)
+{
+ cairo_surface_t *original;
+ cairo_surface_t *source;
+ GthCurve *curve[GTH_HISTOGRAM_N_CHANNELS];
+ gboolean cancelled = FALSE;
+
+ original = gth_image_task_get_source_surface (GTH_IMAGE_TASK (task));
+ source = _cairo_image_surface_copy (original);
+
+ curve[GTH_HISTOGRAM_CHANNEL_VALUE] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 0);
+ curve[GTH_HISTOGRAM_CHANNEL_RED] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 4, 0,0, 75,83, 198,185,
255,255);
+ curve[GTH_HISTOGRAM_CHANNEL_GREEN] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 4, 0,0, 70,63,
184,189, 255,255);
+ curve[GTH_HISTOGRAM_CHANNEL_BLUE] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 4, 0,0, 76,74,
191,176, 255,255);
+ cancelled = ! cairo_image_surface_apply_curves (source, curve, task);
+ if (! cancelled) {
+ cancelled = ! cairo_image_surface_apply_vignette (source, NULL, task);
+ if (! cancelled)
+ gth_image_task_set_destination_surface (GTH_IMAGE_TASK (task), source);
+ }
+
+ g_object_unref (curve[GTH_HISTOGRAM_CHANNEL_BLUE]);
+ g_object_unref (curve[GTH_HISTOGRAM_CHANNEL_GREEN]);
+ g_object_unref (curve[GTH_HISTOGRAM_CHANNEL_RED]);
+ g_object_unref (curve[GTH_HISTOGRAM_CHANNEL_VALUE]);
+ cairo_surface_destroy (source);
+ cairo_surface_destroy (original);
+
+ return NULL;
+}
+
+
+void
+instagram_add_to_special_effects (GthFilterGrid *grid)
+{
+ gth_filter_grid_add_filter (grid,
+ GTH_FILTER_GRID_NEW_FILTER_ID,
+ gth_image_task_new (_("Applying changes"), NULL, instagram_exec, NULL,
NULL, NULL),
+ _("Instagram"),
+ NULL);
+}
+
+
+/* -- Cherry -- */
+
+
+static gpointer
+cherry_exec (GthAsyncTask *task,
+ gpointer user_data)
+{
+ cairo_surface_t *original;
+ cairo_surface_t *source;
+ GthCurve *curve[GTH_HISTOGRAM_N_CHANNELS];
+ gboolean cancelled = FALSE;
+
+ original = gth_image_task_get_source_surface (GTH_IMAGE_TASK (task));
+ source = _cairo_image_surface_copy (original);
+
+ curve[GTH_HISTOGRAM_CHANNEL_VALUE] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 0);
+ curve[GTH_HISTOGRAM_CHANNEL_RED] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 5, 0,12, 74,79,
134,156, 188,209, 239,255);
+ curve[GTH_HISTOGRAM_CHANNEL_GREEN] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 5, 12,0, 78,67,
138,140, 189,189, 252,233);
+ curve[GTH_HISTOGRAM_CHANNEL_BLUE] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 5, 0,8, 77,100,
139,140, 202,186, 255,244);
+ if (cairo_image_surface_apply_curves (source, curve, task)
+ && cairo_image_surface_apply_vignette (source, NULL, task))
+ {
+ gth_image_task_set_destination_surface (GTH_IMAGE_TASK (task), source);
+ }
+
+ g_object_unref (curve[GTH_HISTOGRAM_CHANNEL_BLUE]);
+ g_object_unref (curve[GTH_HISTOGRAM_CHANNEL_GREEN]);
+ g_object_unref (curve[GTH_HISTOGRAM_CHANNEL_RED]);
+ g_object_unref (curve[GTH_HISTOGRAM_CHANNEL_VALUE]);
+ cairo_surface_destroy (source);
+ cairo_surface_destroy (original);
+
+ return NULL;
+}
+
+
+void
+cherry_add_to_special_effects (GthFilterGrid *grid)
+{
+ gth_filter_grid_add_filter (grid,
+ GTH_FILTER_GRID_NEW_FILTER_ID,
+ gth_image_task_new (_("Applying changes"), NULL, cherry_exec, NULL, NULL,
NULL),
+ _("Cherry"),
+ NULL);
+}
+
+
+/* -- Fresh Blue -- */
+
+
+static gpointer
+grapes_exec (GthAsyncTask *task,
+ gpointer user_data)
+{
+ cairo_surface_t *original;
+ cairo_surface_t *source;
+ GthCurve *curve[GTH_HISTOGRAM_N_CHANNELS];
+ gboolean cancelled = FALSE;
+
+ original = gth_image_task_get_source_surface (GTH_IMAGE_TASK (task));
+ source = _cairo_image_surface_copy (original);
+
+ /*
+ curve[GTH_HISTOGRAM_CHANNEL_VALUE] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 3, 0,0, 126,138,
255,255);
+ curve[GTH_HISTOGRAM_CHANNEL_RED] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 3, 78,41, 145,142,
230,233);
+ curve[GTH_HISTOGRAM_CHANNEL_GREEN] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 4, 0,4, 40,34,
149,145, 255,255);
+ curve[GTH_HISTOGRAM_CHANNEL_BLUE] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 0);
+ */
+
+ /*
+ curve[GTH_HISTOGRAM_CHANNEL_VALUE] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 3, 0,0, 126,137,
255,255);
+ curve[GTH_HISTOGRAM_CHANNEL_RED] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 4, 0,8, 47,32, 207,223,
255,244);
+ curve[GTH_HISTOGRAM_CHANNEL_GREEN] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 4, 0,4, 40,34,
149,145, 255,255);
+ curve[GTH_HISTOGRAM_CHANNEL_BLUE] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 3, 0,0, 119,137,
255,255);
+ */
+
+ curve[GTH_HISTOGRAM_CHANNEL_VALUE] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 0);
+ curve[GTH_HISTOGRAM_CHANNEL_RED] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 5, 0,8, 77,100,
139,140, 202,186, 255,244);
+ curve[GTH_HISTOGRAM_CHANNEL_GREEN] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 5, 12,0, 78,67,
138,140, 189,189, 252,233);
+ curve[GTH_HISTOGRAM_CHANNEL_BLUE] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 5, 0,12, 74,79,
134,156, 188,209, 239,255);
+
+ if (cairo_image_surface_apply_curves (source, curve, task)
+ && cairo_image_surface_apply_vignette (source, NULL, task))
+ {
+ gth_image_task_set_destination_surface (GTH_IMAGE_TASK (task), source);
+ }
+
+ g_object_unref (curve[GTH_HISTOGRAM_CHANNEL_BLUE]);
+ g_object_unref (curve[GTH_HISTOGRAM_CHANNEL_GREEN]);
+ g_object_unref (curve[GTH_HISTOGRAM_CHANNEL_RED]);
+ g_object_unref (curve[GTH_HISTOGRAM_CHANNEL_VALUE]);
+ cairo_surface_destroy (source);
+ cairo_surface_destroy (original);
+
+ return NULL;
+}
+
+
+void
+grapes_add_to_special_effects (GthFilterGrid *grid)
+{
+ gth_filter_grid_add_filter (grid,
+ GTH_FILTER_GRID_NEW_FILTER_ID,
+ gth_image_task_new (_("Applying changes"), NULL, grapes_exec, NULL, NULL,
NULL),
+ _("Grapes"),
+ NULL);
+}
+
+
+/**/
+
+
+static gpointer
+vintage_exec (GthAsyncTask *task,
+ gpointer user_data)
+{
+ cairo_surface_t *original;
+ cairo_surface_t *source;
+ GthCurve *curve[GTH_HISTOGRAM_N_CHANNELS];
+ gboolean cancelled = FALSE;
+
+ original = gth_image_task_get_source_surface (GTH_IMAGE_TASK (task));
+ source = _cairo_image_surface_copy (original);
+
+ curve[GTH_HISTOGRAM_CHANNEL_VALUE] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 3, 0,0, 76,173,
255,255);
+ curve[GTH_HISTOGRAM_CHANNEL_RED] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 0);
+ curve[GTH_HISTOGRAM_CHANNEL_GREEN] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 0);
+ curve[GTH_HISTOGRAM_CHANNEL_BLUE] = gth_curve_new_for_points (GTH_TYPE_BEZIER, 0);
+
+ if (cairo_image_surface_colorize (source, 112, 66, 20, 255, task)
+ && cairo_image_surface_apply_bcs (source, 0, -20 / 100, -20 / 100, task)
+ && cairo_image_surface_apply_vignette (source, curve, task))
+ {
+ gth_image_task_set_destination_surface (GTH_IMAGE_TASK (task), source);
+ }
+
+ g_object_unref (curve[GTH_HISTOGRAM_CHANNEL_BLUE]);
+ g_object_unref (curve[GTH_HISTOGRAM_CHANNEL_GREEN]);
+ g_object_unref (curve[GTH_HISTOGRAM_CHANNEL_RED]);
+ g_object_unref (curve[GTH_HISTOGRAM_CHANNEL_VALUE]);
+ cairo_surface_destroy (source);
+ cairo_surface_destroy (original);
+
+ return NULL;
+}
+
+
+void
+vintage_add_to_special_effects (GthFilterGrid *grid)
+{
+ gth_filter_grid_add_filter (grid,
+ GTH_FILTER_GRID_NEW_FILTER_ID,
+ gth_image_task_new (_("Applying changes"), NULL, vintage_exec, NULL,
NULL, NULL),
+ _("Vintage"),
+ NULL);
+}
diff --git a/extensions/file_tools/gth-file-tool-effects.h b/extensions/file_tools/gth-file-tool-effects.h
new file mode 100644
index 0000000..2b60678
--- /dev/null
+++ b/extensions/file_tools/gth-file-tool-effects.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2014 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GTH_FILE_TOOL_EFFECTS_H
+#define GTH_FILE_TOOL_EFFECTS_H
+
+#include <gthumb.h>
+#include <extensions/image_viewer/image-viewer.h>
+
+G_BEGIN_DECLS
+
+#define GTH_TYPE_FILE_TOOL_EFFECTS (gth_file_tool_effects_get_type ())
+#define GTH_FILE_TOOL_EFFECTS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTH_TYPE_FILE_TOOL_EFFECTS,
GthFileToolEffects))
+#define GTH_FILE_TOOL_EFFECTS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTH_TYPE_FILE_TOOL_EFFECTS,
GthFileToolEffectsClass))
+#define GTH_IS_FILE_TOOL_EFFECTS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTH_TYPE_FILE_TOOL_EFFECTS))
+#define GTH_IS_FILE_TOOL_EFFECTS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTH_TYPE_FILE_TOOL_EFFECTS))
+#define GTH_FILE_TOOL_EFFECTS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTH_TYPE_FILE_TOOL_EFFECTS,
GthFileToolEffectsClass))
+
+typedef struct _GthFileToolEffects GthFileToolEffects;
+typedef struct _GthFileToolEffectsClass GthFileToolEffectsClass;
+typedef struct _GthFileToolEffectsPrivate GthFileToolEffectsPrivate;
+
+struct _GthFileToolEffects {
+ GthImageViewerPageTool parent_instance;
+ GthFileToolEffectsPrivate *priv;
+};
+
+struct _GthFileToolEffectsClass {
+ GthImageViewerPageToolClass parent_class;
+};
+
+GType gth_file_tool_effects_get_type (void);
+
+void warmer_add_to_special_effects (GthFilterGrid *);
+void cooler_add_to_special_effects (GthFilterGrid *);
+void instagram_add_to_special_effects (GthFilterGrid *);
+void cherry_add_to_special_effects (GthFilterGrid *);
+void grapes_add_to_special_effects (GthFilterGrid *);
+void vintage_add_to_special_effects (GthFilterGrid *);
+
+G_END_DECLS
+
+#endif /* GTH_FILE_TOOL_EFFECTS_H */
diff --git a/extensions/file_tools/main.c b/extensions/file_tools/main.c
index 0051fa9..cbfc0fd 100644
--- a/extensions/file_tools/main.c
+++ b/extensions/file_tools/main.c
@@ -28,6 +28,7 @@
#include "gth-file-tool-adjust-contrast.h"
#include "gth-file-tool-crop.h"
#include "gth-file-tool-curves.h"
+#include "gth-file-tool-effects.h"
#include "gth-file-tool-flip.h"
#include "gth-file-tool-grayscale.h"
#include "gth-file-tool-mirror.h"
@@ -57,6 +58,7 @@ gthumb_extension_activate (void)
gth_main_register_type ("file-tools", GTH_TYPE_FILE_TOOL_GRAYSCALE);
gth_main_register_type ("file-tools", GTH_TYPE_FILE_TOOL_CURVES);
gth_main_register_type ("file-tools", GTH_TYPE_FILE_TOOL_NEGATIVE);
+ gth_main_register_type ("file-tools", GTH_TYPE_FILE_TOOL_EFFECTS);
gth_main_register_type ("file-tools", GTH_TYPE_FILE_TOOL_ROTATE_LEFT);
gth_main_register_type ("file-tools", GTH_TYPE_FILE_TOOL_ROTATE_RIGHT);
@@ -68,6 +70,20 @@ gthumb_extension_activate (void)
gth_main_register_type ("file-tools", GTH_TYPE_FILE_TOOL_CROP);
gth_hook_add_callback ("gth-browser-file-list-key-press", 10, G_CALLBACK
(file_tools__gth_browser_file_list_key_press_cb), NULL);
+
+ /**
+ * Add a filter to the filter list shown in the Effects tool
+ *
+ * @filter_grid (GthFilterGrid*): the filter grid to add the effect to.
+ **/
+ gth_hook_register ("add-special-effect", 1);
+
+ gth_hook_add_callback ("add-special-effect", 10, G_CALLBACK (warmer_add_to_special_effects), NULL);
+ gth_hook_add_callback ("add-special-effect", 20, G_CALLBACK (cooler_add_to_special_effects), NULL);
+ gth_hook_add_callback ("add-special-effect", 30, G_CALLBACK (cherry_add_to_special_effects), NULL);
+ gth_hook_add_callback ("add-special-effect", 40, G_CALLBACK (grapes_add_to_special_effects), NULL);
+ gth_hook_add_callback ("add-special-effect", 50, G_CALLBACK (instagram_add_to_special_effects), NULL);
+ gth_hook_add_callback ("add-special-effect", 70, G_CALLBACK (vintage_add_to_special_effects), NULL);
}
diff --git a/gthumb/Makefile.am b/gthumb/Makefile.am
index 19b880a..025f023 100644
--- a/gthumb/Makefile.am
+++ b/gthumb/Makefile.am
@@ -26,6 +26,7 @@ PUBLIC_HEADER_FILES = \
color-utils.h \
dom.h \
gfixed.h \
+ gimp-op.h \
gio-utils.h \
glib-utils.h \
gnome-desktop-thumbnail.h \
@@ -164,6 +165,7 @@ gthumb_SOURCES = \
dlg-preferences-general.c \
dlg-sort-order.c \
dom.c \
+ gimp-op.c \
gio-utils.c \
glib-utils.c \
gsignature.c \
diff --git a/gthumb/gimp-op.c b/gthumb/gimp-op.c
new file mode 100644
index 0000000..6cabe1f
--- /dev/null
+++ b/gthumb/gimp-op.c
@@ -0,0 +1,57 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2014 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include "gimp-op.h"
+
+
+guchar add_alpha_table[256][256];
+static GOnce gimp_op_init_once = G_ONCE_INIT;
+
+
+static gpointer
+init_tables (gpointer data)
+{
+ int v;
+ int a;
+ int r;
+
+ /* add_alpha_table[v][a] = v * a / 255 */
+
+ for (v = 0; v < 128; v++) {
+ for (a = 0; a <= v; a++) {
+ r = (v * a + 127) / 255;
+ add_alpha_table[v][a] = add_alpha_table[a][v] = r;
+ add_alpha_table[255-v][a] = add_alpha_table[a][255-v] = a - r;
+ add_alpha_table[v][255-a] = add_alpha_table[255-a][v] = v - r;
+ add_alpha_table[255-v][255-a] = add_alpha_table[255-a][255-v] = (255 - a) - (v - r);
+ }
+ }
+
+ return NULL;
+}
+
+
+void
+gimp_op_init (void)
+{
+ g_once (&gimp_op_init_once, init_tables, NULL);
+}
diff --git a/gthumb/gimp-op.h b/gthumb/gimp-op.h
new file mode 100644
index 0000000..699437d
--- /dev/null
+++ b/gthumb/gimp-op.h
@@ -0,0 +1,59 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2013 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GIMP_OP_H
+#define GIMP_OP_H
+
+#include <config.h>
+#include <glib.h>
+
+/* Optimizations taken from xcftools 1.0.7 written by Henning Makholm
+ *
+ * xL : Layer color
+ * xI : Image color
+ * aL : Layer alpha
+ * */
+
+#define ADD_ALPHA(v, a) (add_alpha_table[v][a])
+#define CLAMP_TEMP(x, min, max) (temp = (x), CLAMP (temp, min, max))
+#define ABS_TEMP2(x) (temp2 = (x), (temp2 < 0) ? -temp2: temp2)
+#define CLAMP_PIXEL(x) CLAMP_TEMP (x, 0, 255)
+#define GIMP_OP_NORMAL(xL, xI, aL) CLAMP_PIXEL (ADD_ALPHA (xL, aL) + ADD_ALPHA (xI, 255 - aL))
+#define GIMP_OP_LIGHTEN_ONLY(xL, xI) MAX (xI, xL)
+#define GIMP_OP_SCREEN(xL, xI) CLAMP_PIXEL (255 ^ ADD_ALPHA (255 - xI, 255 - xL))
+#define GIMP_OP_DODGE(xL, xI) GIMP_OP_DIVIDE (255-xL, xI)
+#define GIMP_OP_ADDITION(xL, xI) CLAMP_PIXEL (xI + xL)
+#define GIMP_OP_DARKEN_ONLY(xL, xI) MIN (xI, xL)
+#define GIMP_OP_MULTIPLY(xL, xI) CLAMP_PIXEL (ADD_ALPHA (xL, xI))
+#define GIMP_OP_BURN(xL, xI) CLAMP_PIXEL (255 - GIMP_OP_DIVIDE (xL, 255 - xI))
+#define GIMP_OP_SOFT_LIGHT(xL, xI) CLAMP_PIXEL (ADD_ALPHA (xI, xI) + 2 * ADD_ALPHA (xL, ADD_ALPHA (xI,
255 - xI)))
+#define GIMP_OP_HARD_LIGHT(xL, xI) CLAMP_PIXEL (xL > 128 ? 255 ^ ADD_ALPHA (255 - xI, 2 * (255 - xL)) :
ADD_ALPHA (xI, 2 * xL))
+#define GIMP_OP_DIFFERENCE(xL, xI) CLAMP_PIXEL (ABS_TEMP2 (xI - xL))
+#define GIMP_OP_SUBTRACT(xL, xI) CLAMP_PIXEL (xI - xL)
+#define GIMP_OP_GRAIN_EXTRACT(xL, xI) CLAMP_PIXEL ((int) xI - xL + 128)
+#define GIMP_OP_GRAIN_MERGE(xL, xI) CLAMP_PIXEL ((int) xI + xL - 128)
+#define GIMP_OP_DIVIDE(xL, xI) CLAMP_PIXEL ((int) (xI) * 256 / (1 + (xL)))
+
+extern guchar add_alpha_table[256][256];
+
+void gimp_op_init (void);
+
+#endif /* GIMP_OP_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]