1 /* This file is part of GEGL editor -- an mrg frontend for GEGL
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 3 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, see <https://www.gnu.org/licenses/>.
16 * Copyright (C) 2015 Øyvind Kolås pippin@gimp.org
19 /* The code in this file is an image viewer/editor written using microraptor
20 * gui and GEGL. It renders the UI directly from GEGLs data structures.
24 #define _DEFAULT_SOURCE
32 #include <sys/types.h>
41 #include <gexiv2/gexiv2.h>
42 #include <gegl-paramspecs.h>
43 #include <gegl-audio-fragment.h>
46 static unsigned char *copy_buf
= NULL
;
47 static int copy_buf_len
= 0;
49 static float cached_x0
= 0;
50 static float cached_y0
= 0;
51 static float cached_width
= 0;
52 static float cached_height
= 0;
53 static float cached_u
= 0;
54 static float cached_v
= 0;
55 static float cached_scale
= 0;
56 static float cached_prev_mul
= 0;
57 static int cached_nearest
= 0;
58 static int cached_dirty
= 0;
59 static cairo_surface_t
*cached_surface
= NULL
;
61 void mrg_gegl_dirty (Mrg
*mrg
)
66 int mrg_gegl_got_nearest (void)
68 return cached_nearest
;
71 void mrg_gegl_buffer_blit (Mrg
*mrg
,
73 float width
, float height
,
77 float preview_multiplier
,
79 int color_manage_display
)
81 float fake_factor
= preview_multiplier
;
84 cairo_t
*cr
= mrg_cr (mrg
);
85 cairo_surface_t
*surface
= NULL
;
90 bounds
= *gegl_buffer_get_extent (buffer
);
92 if (width
== -1 && height
== -1)
95 height
= bounds
.height
;
99 width
= bounds
.width
* height
/ bounds
.height
;
101 height
= bounds
.height
* width
/ bounds
.width
;
103 if (cached_x0
== x0
&&
105 cached_width
== width
&&
106 cached_height
== height
&&
109 cached_scale
== scale
&&
110 cached_prev_mul
== preview_multiplier
&&
113 width
/= fake_factor
;
114 height
/= fake_factor
;
118 surface
= cached_surface
;
124 cached_width
= width
;
125 cached_height
= height
;
128 cached_scale
= scale
;
129 cached_nearest
= nearest_neighbor
;
130 cached_prev_mul
= preview_multiplier
;
133 width
/= fake_factor
;
134 height
/= fake_factor
;
138 if (copy_buf_len
< width
* height
* 4)
143 /* we over-allocate ones scanline, otherwise we sometimes get
146 copy_buf_len
= width
* (height
+1) * 4;
147 copy_buf
= malloc (copy_buf_len
);
150 unsigned char *buf
= copy_buf
;
151 GeglRectangle roi
= {u
, v
, width
, height
};
152 const Babl
*fmt
= NULL
;
153 static const Babl
*fmt_icc
= NULL
;
154 static const Babl
*fmt_srgb
= NULL
;
156 if (color_manage_display
)
161 unsigned const char *icc_data
= mrg_get_profile (mrg
, &icc_length
);
162 const Babl
*space
= NULL
;
164 space
= babl_space_from_icc ((char*)icc_data
, icc_length
, BABL_ICC_INTENT_RELATIVE_COLORIMETRIC
, NULL
);
165 fmt_icc
= babl_format_with_space ("cairo-RGB24", space
);
172 fmt_srgb
= babl_format_with_space ("cairo-RGB24", NULL
);
175 gegl_buffer_get (buffer
, &roi
, scale
/ fake_factor
, fmt
, buf
, width
* 4,
176 GEGL_ABYSS_NONE
| (nearest_neighbor
?GEGL_BUFFER_FILTER_NEAREST
:0));
177 surface
= cairo_image_surface_create_for_data (buf
, CAIRO_FORMAT_RGB24
, width
, height
, width
* 4);
180 cairo_surface_set_device_scale (surface
, 1.0/fake_factor
, 1.0/fake_factor
);
182 cairo_surface_destroy (cached_surface
);
183 cached_surface
= surface
;
187 width
*= fake_factor
;
188 height
*= fake_factor
;
192 cairo_rectangle (cr
, x0
, y0
, width
, height
);
195 cairo_translate (cr
, floorf (x0
* fake_factor
), floorf (y0
* fake_factor
));
196 cairo_pattern_set_filter (cairo_get_source (cr
), CAIRO_FILTER_NEAREST
);
197 cairo_set_source_surface (cr
, surface
, 0, 0);
199 cairo_set_operator (cr
, CAIRO_OPERATOR_SOURCE
);
202 //cairo_surface_destroy (surface);
208 void mrg_gegl_blit (Mrg
*mrg
,
210 float width
, float height
,
214 float preview_multiplier
,
215 int nearest_neighbor
,
216 int color_manage_display
)
218 float fake_factor
= preview_multiplier
;
219 GeglRectangle bounds
;
221 cairo_t
*cr
= mrg_cr (mrg
);
222 cairo_surface_t
*surface
= NULL
;
227 bounds
= gegl_node_get_bounding_box (node
);
229 if (width
== -1 && height
== -1)
231 width
= bounds
.width
;
232 height
= bounds
.height
;
236 width
= bounds
.width
* height
/ bounds
.height
;
238 height
= bounds
.height
* width
/ bounds
.width
;
240 width
/= fake_factor
;
241 height
/= fake_factor
;
245 if (copy_buf_len
< width
* height
* 4)
250 /* XXX: same overallocation as in other code-path, overallocating a fixed
251 amount might also be a sufficient workaround until the underlying
254 copy_buf_len
= width
* (height
+1) * 4;
255 copy_buf
= malloc (copy_buf_len
);
258 unsigned char *buf
= copy_buf
;
259 GeglRectangle roi
= {u
, v
, width
, height
};
260 const Babl
*fmt
= NULL
;
261 static const Babl
*fmt_icc
= NULL
;
262 static const Babl
*fmt_srgb
= NULL
;
264 if (color_manage_display
)
269 unsigned const char *icc_data
= mrg_get_profile (mrg
, &icc_length
);
270 const Babl
*space
= NULL
;
272 space
= babl_space_from_icc ((char*)icc_data
, icc_length
, BABL_ICC_INTENT_RELATIVE_COLORIMETRIC
, NULL
);
273 fmt_icc
= babl_format_with_space ("cairo-RGB24", space
);
280 fmt_srgb
= babl_format_with_space ("cairo-RGB24", NULL
);
284 gegl_node_blit (node
, scale
/ fake_factor
, &roi
, fmt
, buf
, width
* 4,
285 GEGL_BLIT_DEFAULT
| (nearest_neighbor
?GEGL_BUFFER_FILTER_NEAREST
:0));
286 surface
= cairo_image_surface_create_for_data (buf
, CAIRO_FORMAT_RGB24
, width
, height
, width
* 4);
290 cairo_surface_set_device_scale (surface
, 1.0/fake_factor
, 1.0/fake_factor
);
292 width
*= fake_factor
;
293 height
*= fake_factor
;
297 cairo_rectangle (cr
, x0
, y0
, width
, height
);
300 cairo_translate (cr
, floorf (x0
* fake_factor
), floorf (y0
* fake_factor
));
301 cairo_pattern_set_filter (cairo_get_source (cr
), CAIRO_FILTER_NEAREST
);
302 cairo_set_source_surface (cr
, surface
, 0, 0);
304 cairo_set_operator (cr
, CAIRO_OPERATOR_SOURCE
);
306 cairo_surface_destroy (surface
);