Merge lp:~ballogy/gloobus-preview/drop-loaders into lp:gloobus-preview
- drop-loaders
- Merge into last_working_branch
Proposed by
Balló György
Status: | Merged |
---|---|
Merged at revision: | 307 |
Proposed branch: | lp:~ballogy/gloobus-preview/drop-loaders |
Merge into: | lp:gloobus-preview |
Diff against target: |
2351 lines (+0/-2281) 7 files modified
configure.ac (+0/-9) src/Makefile.am (+0/-2) src/loaders/PSD/Makefile.am (+0/-12) src/loaders/PSD/io-psd.c (+0/-598) src/loaders/XCF/Makefile.am (+0/-13) src/loaders/XCF/io-xcf.c (+0/-1641) src/plugin-pixbuf/plugin-pixbuf.h (+0/-6) |
To merge this branch: | bzr merge lp:~ballogy/gloobus-preview/drop-loaders |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gloobus Developers | Pending | ||
Review via email: mp+245375@code.launchpad.net |
Commit message
Description of the change
Remove custom gdk-pixbuf loaders
These are buggy and not needed anymore, since PSD and XCF formats are supported by the new imagemagick plugin.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'configure.ac' | |||
2 | --- configure.ac 2014-12-25 16:27:26 +0000 | |||
3 | +++ configure.ac 2014-12-26 04:45:12 +0000 | |||
4 | @@ -32,12 +32,8 @@ | |||
5 | 32 | AC_CHECK_LIB(gthread, g_thread_init) | 32 | AC_CHECK_LIB(gthread, g_thread_init) |
6 | 33 | AC_CHECK_LIB(pthread, pthread_create) | 33 | AC_CHECK_LIB(pthread, pthread_create) |
7 | 34 | 34 | ||
8 | 35 | # To compile XCF loader ==> sudo apt-get install libtool libbz2-dev | ||
9 | 36 | AC_CHECK_LIB(bz2,BZ2_bzDecompressInit,,AC_MSG_ERROR(Can not find libbz2)) | ||
10 | 37 | |||
11 | 38 | # *** checks for headers ***************************************************** # | 35 | # *** checks for headers ***************************************************** # |
12 | 39 | AC_CHECK_HEADERS([stdlib.h string.h pthread.h]) | 36 | AC_CHECK_HEADERS([stdlib.h string.h pthread.h]) |
13 | 40 | AC_CHECK_HEADER(bzlib.h,,AC_MSG_ERROR(Can not find bzlib header)) # To compile XCF loader | ||
14 | 41 | 37 | ||
15 | 42 | # *** checks for modules ***************************************************** # | 38 | # *** checks for modules ***************************************************** # |
16 | 43 | PKG_CHECK_MODULES(ATK, atk) | 39 | PKG_CHECK_MODULES(ATK, atk) |
17 | @@ -57,9 +53,6 @@ | |||
18 | 57 | PKG_CHECK_MODULES(DBUS, dbus-glib-1) | 53 | PKG_CHECK_MODULES(DBUS, dbus-glib-1) |
19 | 58 | PKG_CHECK_MODULES(X11, x11) | 54 | PKG_CHECK_MODULES(X11, x11) |
20 | 59 | 55 | ||
21 | 60 | PKG_CHECK_MODULES(GMODULE, gmodule-2.0) # To compile XCF loader | ||
22 | 61 | PKG_CHECK_MODULES(GDKPIXBUF, gdk-pixbuf-2.0) # To compile XCF loader | ||
23 | 62 | |||
24 | 63 | # Checks for typedefs, structures, and compiler characteristics. | 56 | # Checks for typedefs, structures, and compiler characteristics. |
25 | 64 | AC_HEADER_STDBOOL | 57 | AC_HEADER_STDBOOL |
26 | 65 | 58 | ||
27 | @@ -90,8 +83,6 @@ | |||
28 | 90 | src/plugin-text/Makefile | 83 | src/plugin-text/Makefile |
29 | 91 | src/plugin-ttf/Makefile | 84 | src/plugin-ttf/Makefile |
30 | 92 | src/plugin-xps/Makefile | 85 | src/plugin-xps/Makefile |
31 | 93 | src/loaders/PSD/Makefile | ||
32 | 94 | src/loaders/XCF/Makefile | ||
33 | 95 | src/gloobus-sushi/Makefile | 86 | src/gloobus-sushi/Makefile |
34 | 96 | data/Makefile | 87 | data/Makefile |
35 | 97 | data/images/Makefile | 88 | data/images/Makefile |
36 | 98 | 89 | ||
37 | === modified file 'src/Makefile.am' | |||
38 | --- src/Makefile.am 2014-12-25 16:27:26 +0000 | |||
39 | +++ src/Makefile.am 2014-12-26 04:45:12 +0000 | |||
40 | @@ -1,7 +1,5 @@ | |||
41 | 1 | SUBDIRS = \ | 1 | SUBDIRS = \ |
42 | 2 | gloobus-sushi \ | 2 | gloobus-sushi \ |
43 | 3 | loaders/PSD \ | ||
44 | 4 | loaders/XCF \ | ||
45 | 5 | plugin-comic \ | 3 | plugin-comic \ |
46 | 6 | plugin-folder \ | 4 | plugin-folder \ |
47 | 7 | plugin-compressed \ | 5 | plugin-compressed \ |
48 | 8 | 6 | ||
49 | === removed directory 'src/loaders' | |||
50 | === removed directory 'src/loaders/PSD' | |||
51 | === removed file 'src/loaders/PSD/Makefile.am' | |||
52 | --- src/loaders/PSD/Makefile.am 2010-08-21 18:06:49 +0000 | |||
53 | +++ src/loaders/PSD/Makefile.am 1970-01-01 00:00:00 +0000 | |||
54 | @@ -1,12 +0,0 @@ | |||
55 | 1 | #pluginexecdir = $(prefix)/lib/gtk-2.0/2.10.0/loaders/ | ||
56 | 2 | pluginexecdir = $(prefix)/lib/gdk-pixbuf-2.0/2.10.0/loaders/ | ||
57 | 3 | |||
58 | 4 | AM_CPPFLAGS += $(GTK_CFLAGS) -shared -fpic -std=c99 -DGDK_PIXBUF_ENABLE_BACKEND | ||
59 | 5 | AM_LDFLAGS = $(GTK_LIBS) | ||
60 | 6 | |||
61 | 7 | pluginexec_LTLIBRARIES = libpixbufloader-psd.la | ||
62 | 8 | libpixbufloader_psd_la_SOURCES = io-psd.c | ||
63 | 9 | libpixbufloader_psd_la_LDFLAGS = -module -export-dynamic $(AM_LDFLAGS) | ||
64 | 10 | |||
65 | 11 | #install-exec-hook: | ||
66 | 12 | # install -d $(prefix)/lib/gdk-pixbuf-2.0/2.10.0/loaders/ | ||
67 | 13 | 0 | ||
68 | === removed file 'src/loaders/PSD/io-psd.c' | |||
69 | --- src/loaders/PSD/io-psd.c 2009-12-23 17:50:28 +0000 | |||
70 | +++ src/loaders/PSD/io-psd.c 1970-01-01 00:00:00 +0000 | |||
71 | @@ -1,598 +0,0 @@ | |||
72 | 1 | /* -*- mode: C; c-file-style: "linux" -*- */ | ||
73 | 2 | /* GdkPixbuf library - PSD image loader | ||
74 | 3 | * | ||
75 | 4 | * Copyright (C) 2008 Jan Dudek | ||
76 | 5 | * | ||
77 | 6 | * Authors: Jan Dudek <jd@jandudek.com> | ||
78 | 7 | * | ||
79 | 8 | * This library is free software; you can redistribute it and/or | ||
80 | 9 | * modify it under the terms of the GNU Lesser General Public | ||
81 | 10 | * License as published by the Free Software Foundation; either | ||
82 | 11 | * version 2 of the License, or (at your option) any later version. | ||
83 | 12 | * | ||
84 | 13 | * This library is distributed in the hope that it will be useful, | ||
85 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
86 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
87 | 16 | * Lesser General Public License for more | ||
88 | 17 | * You should have received a copy of the GNU Lesser General Public | ||
89 | 18 | * License along with this library; if not, write to the | ||
90 | 19 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
91 | 20 | * Boston, MA 02111-1307, USA. | ||
92 | 21 | */ | ||
93 | 22 | |||
94 | 23 | /* | ||
95 | 24 | * TODO | ||
96 | 25 | * - use http://library.gnome.org/devel/glib/unstable/glib-Byte-Order-Macros.html | ||
97 | 26 | * - report errors from parse_psd_header | ||
98 | 27 | * - other color modes (CMYK at least) | ||
99 | 28 | * - i18n | ||
100 | 29 | */ | ||
101 | 30 | |||
102 | 31 | #include <stdlib.h> | ||
103 | 32 | #include <stdio.h> | ||
104 | 33 | #include <string.h> | ||
105 | 34 | #include <gdk-pixbuf/gdk-pixbuf-io.h> | ||
106 | 35 | #include <glib/gstdio.h> | ||
107 | 36 | |||
108 | 37 | |||
109 | 38 | typedef struct | ||
110 | 39 | { | ||
111 | 40 | guchar signature[4]; /* file ID, always "8BPS" */ | ||
112 | 41 | guint16 version; /* version number, always 1 */ | ||
113 | 42 | guchar resetved[6]; | ||
114 | 43 | guint16 channels; /* number of color channels (1-24) */ | ||
115 | 44 | guint32 rows; /* height of image in pixels (1-30000) */ | ||
116 | 45 | guint32 columns; /* width of image in pixels (1-30000) */ | ||
117 | 46 | guint16 depth; /* number of bits per channel (1, 8, and 16) */ | ||
118 | 47 | guint16 color_mode; /* color mode as defined below */ | ||
119 | 48 | } PsdHeader; | ||
120 | 49 | |||
121 | 50 | #define PSD_HEADER_SIZE 26 | ||
122 | 51 | |||
123 | 52 | typedef enum | ||
124 | 53 | { | ||
125 | 54 | PSD_MODE_MONO = 0, | ||
126 | 55 | PSD_MODE_GRAYSCALE = 1, | ||
127 | 56 | PSD_MODE_INDEXED = 2, | ||
128 | 57 | PSD_MODE_RGB = 3, | ||
129 | 58 | PSD_MODE_CMYK = 4, | ||
130 | 59 | PSD_MODE_MULTICHANNEL = 7, | ||
131 | 60 | PSD_MODE_DUOTONE = 8, | ||
132 | 61 | PSD_MODE_LAB = 9, | ||
133 | 62 | } PsdColorMode; | ||
134 | 63 | |||
135 | 64 | typedef enum | ||
136 | 65 | { | ||
137 | 66 | PSD_COMPRESSION_NONE = 0, | ||
138 | 67 | PSD_COMPRESSION_RLE = 1 | ||
139 | 68 | } PsdCompressionType; | ||
140 | 69 | |||
141 | 70 | typedef enum | ||
142 | 71 | { | ||
143 | 72 | PSD_STATE_HEADER, | ||
144 | 73 | PSD_STATE_COLOR_MODE_BLOCK, | ||
145 | 74 | PSD_STATE_RESOURCES_BLOCK, | ||
146 | 75 | PSD_STATE_LAYERS_BLOCK, | ||
147 | 76 | PSD_STATE_COMPRESSION, | ||
148 | 77 | PSD_STATE_LINES_LENGTHS, | ||
149 | 78 | PSD_STATE_CHANNEL_DATA, | ||
150 | 79 | PSD_STATE_DONE | ||
151 | 80 | } PsdReadState; | ||
152 | 81 | |||
153 | 82 | typedef struct | ||
154 | 83 | { | ||
155 | 84 | PsdReadState state; | ||
156 | 85 | |||
157 | 86 | GdkPixbuf* pixbuf; | ||
158 | 87 | |||
159 | 88 | GdkPixbufModuleSizeFunc size_func; | ||
160 | 89 | GdkPixbufModuleUpdatedFunc updated_func; | ||
161 | 90 | GdkPixbufModulePreparedFunc prepared_func; | ||
162 | 91 | gpointer user_data; | ||
163 | 92 | |||
164 | 93 | guchar* buffer; | ||
165 | 94 | guint bytes_read; | ||
166 | 95 | guint32 bytes_to_skip; | ||
167 | 96 | gboolean bytes_to_skip_known; | ||
168 | 97 | |||
169 | 98 | guint32 width; /* width of image in pixels (1-30000) */ | ||
170 | 99 | guint32 height; /* height of image in pixels (1-30000) */ | ||
171 | 100 | guint16 channels; /* number of color channels (1-24) */ | ||
172 | 101 | guint16 depth; /* number of bits per channel (1/8/16) */ | ||
173 | 102 | PsdColorMode color_mode; | ||
174 | 103 | PsdCompressionType compression; | ||
175 | 104 | |||
176 | 105 | guchar** ch_bufs; /* channels buffers */ | ||
177 | 106 | guint curr_ch; /* current channel */ | ||
178 | 107 | guint curr_row; | ||
179 | 108 | guint pos; // redundant? | ||
180 | 109 | guint16* lines_lengths; | ||
181 | 110 | gboolean finalized; | ||
182 | 111 | gboolean use_alpha; | ||
183 | 112 | } PsdContext; | ||
184 | 113 | |||
185 | 114 | |||
186 | 115 | static guint16 | ||
187 | 116 | read_uint16 (guchar* buf) | ||
188 | 117 | { | ||
189 | 118 | return (buf[0] << 8) | buf[1]; | ||
190 | 119 | } | ||
191 | 120 | |||
192 | 121 | static guint32 | ||
193 | 122 | read_uint32 (guchar* buf) | ||
194 | 123 | { | ||
195 | 124 | return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; | ||
196 | 125 | } | ||
197 | 126 | |||
198 | 127 | |||
199 | 128 | /* | ||
200 | 129 | * Parse Psdheader from buffer | ||
201 | 130 | * | ||
202 | 131 | * str is expected to be at least PSD_HEADER_SIZE long | ||
203 | 132 | */ | ||
204 | 133 | static PsdHeader | ||
205 | 134 | psd_parse_header (guchar* str) | ||
206 | 135 | { | ||
207 | 136 | PsdHeader hd; | ||
208 | 137 | |||
209 | 138 | memcpy(hd.signature, str, 4); | ||
210 | 139 | hd.version = read_uint16(str + 4); | ||
211 | 140 | hd.channels = read_uint16(str + 12); | ||
212 | 141 | hd.rows = read_uint32(str + 14); | ||
213 | 142 | hd.columns = read_uint32(str + 18); | ||
214 | 143 | hd.depth = read_uint16(str + 22); | ||
215 | 144 | hd.color_mode = read_uint16(str + 24); | ||
216 | 145 | |||
217 | 146 | return hd; | ||
218 | 147 | } | ||
219 | 148 | |||
220 | 149 | /* | ||
221 | 150 | * Attempts to read bytes_needed bytes from data and stores them in buffer. | ||
222 | 151 | * | ||
223 | 152 | * Returns true if there were enough bytes and false otherwise | ||
224 | 153 | * (which means we need to call feed_buffer again) | ||
225 | 154 | */ | ||
226 | 155 | static gboolean | ||
227 | 156 | feed_buffer (guchar* buffer, | ||
228 | 157 | guint* bytes_read, | ||
229 | 158 | const guchar** data, | ||
230 | 159 | guint* size, | ||
231 | 160 | guint bytes_needed) | ||
232 | 161 | { | ||
233 | 162 | gint how_many = bytes_needed - *bytes_read; | ||
234 | 163 | if (how_many > *size) { | ||
235 | 164 | how_many = *size; | ||
236 | 165 | } | ||
237 | 166 | memcpy(buffer + *bytes_read, *data, how_many); | ||
238 | 167 | *bytes_read += how_many; | ||
239 | 168 | *data += how_many; | ||
240 | 169 | *size -= how_many; | ||
241 | 170 | return (*bytes_read == bytes_needed); | ||
242 | 171 | } | ||
243 | 172 | |||
244 | 173 | /* | ||
245 | 174 | * Attempts to read size of the block and then skip this block. | ||
246 | 175 | * | ||
247 | 176 | * Returns true when finishes consuming block data, otherwise false | ||
248 | 177 | * (false means we need to call skip_block again) | ||
249 | 178 | */ | ||
250 | 179 | static gboolean | ||
251 | 180 | skip_block (PsdContext* context, const guchar** data, guint* size) | ||
252 | 181 | { | ||
253 | 182 | static guint counter; | ||
254 | 183 | |||
255 | 184 | if (!context->bytes_to_skip_known) { | ||
256 | 185 | context->bytes_read = 0; | ||
257 | 186 | if (feed_buffer(context->buffer, &context->bytes_read, data, size, 4)) { | ||
258 | 187 | context->bytes_to_skip = read_uint32(context->buffer); | ||
259 | 188 | context->bytes_to_skip_known = TRUE; | ||
260 | 189 | counter = 0; | ||
261 | 190 | } else { | ||
262 | 191 | return FALSE; | ||
263 | 192 | } | ||
264 | 193 | } | ||
265 | 194 | if (*size < context->bytes_to_skip) { | ||
266 | 195 | *data += *size; | ||
267 | 196 | context->bytes_to_skip -= *size; | ||
268 | 197 | counter += *size; | ||
269 | 198 | *size = 0; | ||
270 | 199 | return FALSE; | ||
271 | 200 | } else { | ||
272 | 201 | counter += context->bytes_to_skip; | ||
273 | 202 | *size -= context->bytes_to_skip; | ||
274 | 203 | *data += context->bytes_to_skip; | ||
275 | 204 | return TRUE; | ||
276 | 205 | } | ||
277 | 206 | } | ||
278 | 207 | |||
279 | 208 | /* | ||
280 | 209 | * Decodes RLE-compressed data | ||
281 | 210 | */ | ||
282 | 211 | static void | ||
283 | 212 | decompress_line(const guchar* src, guint line_length, guchar* dest) | ||
284 | 213 | { | ||
285 | 214 | guint16 bytes_read = 0; | ||
286 | 215 | while (bytes_read < line_length) { | ||
287 | 216 | gchar byte = src[bytes_read]; | ||
288 | 217 | ++bytes_read; | ||
289 | 218 | |||
290 | 219 | if (byte == -128) { | ||
291 | 220 | continue; | ||
292 | 221 | } else if (byte > -1) { | ||
293 | 222 | gint count = byte + 1; | ||
294 | 223 | |||
295 | 224 | // copy next count bytes | ||
296 | 225 | for (int k = 0; k < count; ++k) { | ||
297 | 226 | *dest = src[bytes_read]; | ||
298 | 227 | ++dest; | ||
299 | 228 | ++bytes_read; | ||
300 | 229 | } | ||
301 | 230 | } else { | ||
302 | 231 | gint count = -byte + 1; | ||
303 | 232 | |||
304 | 233 | // copy next byte count times | ||
305 | 234 | guchar next_byte = src[bytes_read]; | ||
306 | 235 | ++bytes_read; | ||
307 | 236 | for (int k = 0; k < count; ++k) { | ||
308 | 237 | *dest = next_byte; | ||
309 | 238 | ++dest; | ||
310 | 239 | } | ||
311 | 240 | } | ||
312 | 241 | } | ||
313 | 242 | } | ||
314 | 243 | |||
315 | 244 | static void | ||
316 | 245 | reset_context_buffer(PsdContext* ctx) | ||
317 | 246 | { | ||
318 | 247 | ctx->bytes_read = 0; | ||
319 | 248 | ctx->bytes_to_skip = 0; | ||
320 | 249 | ctx->bytes_to_skip_known = FALSE; | ||
321 | 250 | } | ||
322 | 251 | |||
323 | 252 | static gpointer | ||
324 | 253 | gdk_pixbuf__psd_image_begin_load (GdkPixbufModuleSizeFunc size_func, | ||
325 | 254 | GdkPixbufModulePreparedFunc prepared_func, | ||
326 | 255 | GdkPixbufModuleUpdatedFunc updated_func, | ||
327 | 256 | gpointer user_data, | ||
328 | 257 | GError **error) | ||
329 | 258 | { | ||
330 | 259 | PsdContext* context = g_malloc(sizeof(PsdContext)); | ||
331 | 260 | if (context == NULL) { | ||
332 | 261 | g_set_error ( | ||
333 | 262 | error, | ||
334 | 263 | GDK_PIXBUF_ERROR, | ||
335 | 264 | GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, | ||
336 | 265 | ("Not enough memory")); | ||
337 | 266 | return NULL; | ||
338 | 267 | } | ||
339 | 268 | context->size_func = size_func; | ||
340 | 269 | context->prepared_func = prepared_func; | ||
341 | 270 | context->updated_func = updated_func; | ||
342 | 271 | context->user_data = user_data; | ||
343 | 272 | |||
344 | 273 | context->state = PSD_STATE_HEADER; | ||
345 | 274 | |||
346 | 275 | // we'll allocate larger buffer once we know image size | ||
347 | 276 | context->buffer = g_malloc(PSD_HEADER_SIZE); | ||
348 | 277 | reset_context_buffer(context); | ||
349 | 278 | |||
350 | 279 | context->ch_bufs = NULL; | ||
351 | 280 | context->curr_ch = 0; | ||
352 | 281 | context->curr_row = 0; | ||
353 | 282 | context->pos = 0; | ||
354 | 283 | context->lines_lengths = NULL; | ||
355 | 284 | context->finalized = FALSE; | ||
356 | 285 | context->use_alpha = FALSE; | ||
357 | 286 | |||
358 | 287 | return (gpointer) context; | ||
359 | 288 | } | ||
360 | 289 | |||
361 | 290 | static gboolean | ||
362 | 291 | gdk_pixbuf__psd_image_stop_load (gpointer context_ptr, GError **error) | ||
363 | 292 | { | ||
364 | 293 | PsdContext *ctx = (PsdContext *) context_ptr; | ||
365 | 294 | gboolean retval = TRUE; | ||
366 | 295 | |||
367 | 296 | if (ctx->state != PSD_STATE_DONE) { | ||
368 | 297 | g_set_error ( | ||
369 | 298 | error, | ||
370 | 299 | GDK_PIXBUF_ERROR, | ||
371 | 300 | GDK_PIXBUF_ERROR_CORRUPT_IMAGE, | ||
372 | 301 | ("PSD file was corrupted or incomplete.")); | ||
373 | 302 | retval = FALSE; | ||
374 | 303 | } | ||
375 | 304 | |||
376 | 305 | g_free(ctx->buffer); | ||
377 | 306 | g_free(ctx->lines_lengths); | ||
378 | 307 | if (ctx->ch_bufs) { | ||
379 | 308 | for (int i = 0; i < ctx->channels; i++) { | ||
380 | 309 | g_free(ctx->ch_bufs[i]); | ||
381 | 310 | } | ||
382 | 311 | } | ||
383 | 312 | g_free(ctx); | ||
384 | 313 | |||
385 | 314 | return retval; | ||
386 | 315 | } | ||
387 | 316 | |||
388 | 317 | |||
389 | 318 | static gboolean | ||
390 | 319 | gdk_pixbuf__psd_image_load_increment (gpointer context_ptr, | ||
391 | 320 | const guchar *data, | ||
392 | 321 | guint size, | ||
393 | 322 | GError **error) | ||
394 | 323 | { | ||
395 | 324 | PsdContext* ctx = (PsdContext*) context_ptr; | ||
396 | 325 | |||
397 | 326 | while (size > 0) { | ||
398 | 327 | switch (ctx->state) { | ||
399 | 328 | case PSD_STATE_HEADER: | ||
400 | 329 | if (feed_buffer( | ||
401 | 330 | ctx->buffer, &ctx->bytes_read, | ||
402 | 331 | &data, &size, PSD_HEADER_SIZE)) | ||
403 | 332 | { | ||
404 | 333 | PsdHeader hd = psd_parse_header(ctx->buffer); | ||
405 | 334 | |||
406 | 335 | ctx->width = hd.columns; | ||
407 | 336 | ctx->height = hd.rows; | ||
408 | 337 | ctx->channels = hd.channels; | ||
409 | 338 | ctx->depth = hd.depth; | ||
410 | 339 | ctx->color_mode = hd.color_mode; | ||
411 | 340 | |||
412 | 341 | /* | ||
413 | 342 | if (ctx->color_mode == PSD_MODE_RGB && ctx->channels == 4) { | ||
414 | 343 | ctx->use_alpha = TRUE; | ||
415 | 344 | }*/ | ||
416 | 345 | |||
417 | 346 | //g_message("color_mode=%d, channels=%d, depth=%d", | ||
418 | 347 | // ctx->color_mode, ctx->channels, ctx->depth); | ||
419 | 348 | |||
420 | 349 | if (ctx->color_mode != PSD_MODE_RGB | ||
421 | 350 | //&& ctx->color_mode != PSD_MODE_CMYK | ||
422 | 351 | ) { | ||
423 | 352 | g_set_error (error, GDK_PIXBUF_ERROR, | ||
424 | 353 | GDK_PIXBUF_ERROR_UNKNOWN_TYPE, | ||
425 | 354 | ("Unsupported color mode")); | ||
426 | 355 | return FALSE; | ||
427 | 356 | } | ||
428 | 357 | |||
429 | 358 | if (ctx->depth != 8) { | ||
430 | 359 | g_set_error (error, GDK_PIXBUF_ERROR, | ||
431 | 360 | GDK_PIXBUF_ERROR_UNKNOWN_TYPE, | ||
432 | 361 | ("Unsupported color depth")); | ||
433 | 362 | return FALSE; | ||
434 | 363 | } | ||
435 | 364 | |||
436 | 365 | if (ctx->size_func) { | ||
437 | 366 | gint w = ctx->width; | ||
438 | 367 | gint h = ctx->height; | ||
439 | 368 | ctx->size_func(&w, &h, ctx->user_data); | ||
440 | 369 | if (w == 0 || h == 0) { | ||
441 | 370 | return FALSE; | ||
442 | 371 | } | ||
443 | 372 | } | ||
444 | 373 | |||
445 | 374 | // we need buffer that can contain one channel data of one | ||
446 | 375 | // row in RLE compressed format. 2*width should be enough | ||
447 | 376 | g_free(ctx->buffer); | ||
448 | 377 | ctx->buffer = g_malloc(ctx->width * 2); | ||
449 | 378 | |||
450 | 379 | // this will be needed for RLE decompression | ||
451 | 380 | ctx->lines_lengths = | ||
452 | 381 | g_malloc(2 * ctx->channels * ctx->height); | ||
453 | 382 | |||
454 | 383 | ctx->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, | ||
455 | 384 | ctx->use_alpha, 8, ctx->width, ctx->height); | ||
456 | 385 | |||
457 | 386 | if (ctx->lines_lengths == NULL || ctx->buffer == NULL || | ||
458 | 387 | ctx->pixbuf == NULL) | ||
459 | 388 | { | ||
460 | 389 | g_set_error (error, GDK_PIXBUF_ERROR, | ||
461 | 390 | GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, | ||
462 | 391 | ("Insufficient memory to load PSD image file")); | ||
463 | 392 | return FALSE; | ||
464 | 393 | } | ||
465 | 394 | |||
466 | 395 | // create separate buffers for each channel | ||
467 | 396 | ctx->ch_bufs = g_malloc(sizeof(guchar*) * ctx->channels); | ||
468 | 397 | for (int i = 0; i < ctx->channels; i++) { | ||
469 | 398 | ctx->ch_bufs[i] = | ||
470 | 399 | g_malloc(ctx->width * ctx->height); | ||
471 | 400 | |||
472 | 401 | if (ctx->ch_bufs[i] == NULL) { | ||
473 | 402 | g_set_error (error, GDK_PIXBUF_ERROR, | ||
474 | 403 | GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, | ||
475 | 404 | ("Insufficient memory to load PSD image file")); | ||
476 | 405 | return FALSE; | ||
477 | 406 | } | ||
478 | 407 | } | ||
479 | 408 | |||
480 | 409 | ctx->prepared_func(ctx->pixbuf, NULL, ctx->user_data); | ||
481 | 410 | |||
482 | 411 | ctx->state = PSD_STATE_COLOR_MODE_BLOCK; | ||
483 | 412 | reset_context_buffer(ctx); | ||
484 | 413 | } | ||
485 | 414 | break; | ||
486 | 415 | case PSD_STATE_COLOR_MODE_BLOCK: | ||
487 | 416 | if (skip_block(ctx, &data, &size)) { | ||
488 | 417 | ctx->state = PSD_STATE_RESOURCES_BLOCK; | ||
489 | 418 | reset_context_buffer(ctx); | ||
490 | 419 | } | ||
491 | 420 | break; | ||
492 | 421 | case PSD_STATE_RESOURCES_BLOCK: | ||
493 | 422 | if (skip_block(ctx, &data, &size)) { | ||
494 | 423 | ctx->state = PSD_STATE_LAYERS_BLOCK; | ||
495 | 424 | reset_context_buffer(ctx); | ||
496 | 425 | } | ||
497 | 426 | break; | ||
498 | 427 | case PSD_STATE_LAYERS_BLOCK: | ||
499 | 428 | if (skip_block(ctx, &data, &size)) { | ||
500 | 429 | ctx->state = PSD_STATE_COMPRESSION; | ||
501 | 430 | reset_context_buffer(ctx); | ||
502 | 431 | } | ||
503 | 432 | break; | ||
504 | 433 | case PSD_STATE_COMPRESSION: | ||
505 | 434 | if (feed_buffer(ctx->buffer, &ctx->bytes_read, &data, &size, 2)) | ||
506 | 435 | { | ||
507 | 436 | ctx->compression = read_uint16(ctx->buffer); | ||
508 | 437 | |||
509 | 438 | if (ctx->compression == PSD_COMPRESSION_RLE) { | ||
510 | 439 | ctx->state = PSD_STATE_LINES_LENGTHS; | ||
511 | 440 | reset_context_buffer(ctx); | ||
512 | 441 | } else if (ctx->compression == PSD_COMPRESSION_NONE) { | ||
513 | 442 | ctx->state = PSD_STATE_CHANNEL_DATA; | ||
514 | 443 | } else { | ||
515 | 444 | g_set_error (error, GDK_PIXBUF_ERROR, | ||
516 | 445 | GDK_PIXBUF_ERROR_UNKNOWN_TYPE, | ||
517 | 446 | ("Unsupported compression type")); | ||
518 | 447 | return FALSE; | ||
519 | 448 | } | ||
520 | 449 | } | ||
521 | 450 | break; | ||
522 | 451 | case PSD_STATE_LINES_LENGTHS: | ||
523 | 452 | if (feed_buffer( | ||
524 | 453 | (guchar*) ctx->lines_lengths, &ctx->bytes_read, &data, | ||
525 | 454 | &size, 2 * ctx->height * ctx->channels)) | ||
526 | 455 | { | ||
527 | 456 | // convert from different endianness | ||
528 | 457 | for (int i = 0; i < ctx->height * ctx->channels; i++) { | ||
529 | 458 | ctx->lines_lengths[i] = read_uint16( | ||
530 | 459 | (guchar*) &ctx->lines_lengths[i]); | ||
531 | 460 | } | ||
532 | 461 | ctx->state = PSD_STATE_CHANNEL_DATA; | ||
533 | 462 | reset_context_buffer(ctx); | ||
534 | 463 | } | ||
535 | 464 | break; | ||
536 | 465 | case PSD_STATE_CHANNEL_DATA: | ||
537 | 466 | { | ||
538 | 467 | guint line_length = ctx->width; | ||
539 | 468 | if (ctx->compression == PSD_COMPRESSION_RLE) { | ||
540 | 469 | line_length = ctx->lines_lengths[ | ||
541 | 470 | ctx->curr_ch * ctx->height + ctx->curr_row]; | ||
542 | 471 | } | ||
543 | 472 | |||
544 | 473 | if (feed_buffer(ctx->buffer, &ctx->bytes_read, &data, &size, | ||
545 | 474 | line_length)) | ||
546 | 475 | { | ||
547 | 476 | reset_context_buffer(ctx); | ||
548 | 477 | |||
549 | 478 | if (ctx->compression == PSD_COMPRESSION_RLE) { | ||
550 | 479 | decompress_line(ctx->buffer, line_length, | ||
551 | 480 | ctx->ch_bufs[ctx->curr_ch] + ctx->pos | ||
552 | 481 | ); | ||
553 | 482 | } else { | ||
554 | 483 | memcpy(ctx->ch_bufs[ctx->curr_ch] + ctx->pos, | ||
555 | 484 | ctx->buffer, ctx->width); | ||
556 | 485 | } | ||
557 | 486 | |||
558 | 487 | ctx->pos += ctx->width; | ||
559 | 488 | ++ctx->curr_row; | ||
560 | 489 | |||
561 | 490 | if (ctx->curr_row >= ctx->height) { | ||
562 | 491 | ++ctx->curr_ch; | ||
563 | 492 | ctx->curr_row = 0; | ||
564 | 493 | ctx->pos = 0; | ||
565 | 494 | if (ctx->curr_ch >= ctx->channels) { | ||
566 | 495 | ctx->state = PSD_STATE_DONE; | ||
567 | 496 | } | ||
568 | 497 | } | ||
569 | 498 | } | ||
570 | 499 | } | ||
571 | 500 | break; | ||
572 | 501 | case PSD_STATE_DONE: | ||
573 | 502 | default: | ||
574 | 503 | size = 0; | ||
575 | 504 | break; | ||
576 | 505 | } | ||
577 | 506 | } | ||
578 | 507 | |||
579 | 508 | if (ctx->state == PSD_STATE_DONE && !ctx->finalized) { | ||
580 | 509 | // convert or copy channel buffers to our GdkPixbuf | ||
581 | 510 | if (ctx->color_mode == PSD_MODE_RGB && !ctx->use_alpha) { | ||
582 | 511 | guchar* pixels = gdk_pixbuf_get_pixels(ctx->pixbuf); | ||
583 | 512 | for (int i = 0; i < ctx->height; i++) { | ||
584 | 513 | for (int j = 0; j < ctx->width; j++) { | ||
585 | 514 | pixels[3*j+0] = ctx->ch_bufs[0][ctx->width*i + j]; | ||
586 | 515 | pixels[3*j+1] = ctx->ch_bufs[1][ctx->width*i + j]; | ||
587 | 516 | pixels[3*j+2] = ctx->ch_bufs[2][ctx->width*i + j]; | ||
588 | 517 | } | ||
589 | 518 | pixels += gdk_pixbuf_get_rowstride(ctx->pixbuf); | ||
590 | 519 | } | ||
591 | 520 | } else if (ctx->color_mode == PSD_MODE_RGB && ctx->use_alpha) { | ||
592 | 521 | guchar* pixels = gdk_pixbuf_get_pixels(ctx->pixbuf); | ||
593 | 522 | for (int i = 0; i < ctx->height; i++) { | ||
594 | 523 | for (int j = 0; j < ctx->width; j++) { | ||
595 | 524 | pixels[4*j+0] = ctx->ch_bufs[0][ctx->width*i + j]; | ||
596 | 525 | pixels[4*j+1] = ctx->ch_bufs[1][ctx->width*i + j]; | ||
597 | 526 | pixels[4*j+2] = ctx->ch_bufs[2][ctx->width*i + j]; | ||
598 | 527 | pixels[4*j+3] = ctx->ch_bufs[3][ctx->width*i + j]; | ||
599 | 528 | } | ||
600 | 529 | pixels += gdk_pixbuf_get_rowstride(ctx->pixbuf); | ||
601 | 530 | } | ||
602 | 531 | } else if (ctx->color_mode == PSD_MODE_CMYK) { | ||
603 | 532 | // unfortunately, this doesn't seem to work correctly... | ||
604 | 533 | |||
605 | 534 | guchar* pixels = gdk_pixbuf_get_pixels(ctx->pixbuf); | ||
606 | 535 | for (int i = 0; i < ctx->height; i++) { | ||
607 | 536 | for (int j = 0; j < ctx->width; j++) { | ||
608 | 537 | double c = 1.0 - | ||
609 | 538 | (double) ctx->ch_bufs[0][ctx->width*i + j] / 255.0; | ||
610 | 539 | double m = 1.0 - | ||
611 | 540 | (double) ctx->ch_bufs[1][ctx->width*i + j] / 255.0; | ||
612 | 541 | double y = 1.0 - | ||
613 | 542 | (double) ctx->ch_bufs[2][ctx->width*i + j] / 255.0; | ||
614 | 543 | double k = 1.0 - | ||
615 | 544 | (double) ctx->ch_bufs[3][ctx->width*i + j] / 255.0; | ||
616 | 545 | |||
617 | 546 | pixels[3*j+0] = (1.0 - (c * (1.0 - k) + k)) * 255.0; | ||
618 | 547 | pixels[3*j+1] = (1.0 - (m * (1.0 - k) + k)) * 255.0; | ||
619 | 548 | pixels[3*j+2] = (1.0 - (y * (1.0 - k) + k)) * 255.0; | ||
620 | 549 | } | ||
621 | 550 | pixels += gdk_pixbuf_get_rowstride(ctx->pixbuf); | ||
622 | 551 | } | ||
623 | 552 | } | ||
624 | 553 | ctx->finalized = TRUE; | ||
625 | 554 | } | ||
626 | 555 | |||
627 | 556 | return TRUE; | ||
628 | 557 | } | ||
629 | 558 | |||
630 | 559 | |||
631 | 560 | #ifndef INCLUDE_psd | ||
632 | 561 | #define MODULE_ENTRY(function) G_MODULE_EXPORT void function | ||
633 | 562 | #else | ||
634 | 563 | #define MODULE_ENTRY(function) void _gdk_pixbuf__psd_ ## function | ||
635 | 564 | #endif | ||
636 | 565 | |||
637 | 566 | MODULE_ENTRY (fill_vtable) (GdkPixbufModule* module) | ||
638 | 567 | { | ||
639 | 568 | module->begin_load = gdk_pixbuf__psd_image_begin_load; | ||
640 | 569 | module->stop_load = gdk_pixbuf__psd_image_stop_load; | ||
641 | 570 | module->load_increment = gdk_pixbuf__psd_image_load_increment; | ||
642 | 571 | } | ||
643 | 572 | |||
644 | 573 | MODULE_ENTRY (fill_info) (GdkPixbufFormat *info) | ||
645 | 574 | { | ||
646 | 575 | static GdkPixbufModulePattern signature[] = { | ||
647 | 576 | { "8BPS", NULL, 100 }, | ||
648 | 577 | { NULL, NULL, 0 } | ||
649 | 578 | }; | ||
650 | 579 | static gchar * mime_types[] = { | ||
651 | 580 | "image/x-psd", | ||
652 | 581 | NULL | ||
653 | 582 | }; | ||
654 | 583 | static gchar * extensions[] = { | ||
655 | 584 | "psd", | ||
656 | 585 | NULL | ||
657 | 586 | }; | ||
658 | 587 | |||
659 | 588 | info->name = "psd"; | ||
660 | 589 | info->signature = signature; | ||
661 | 590 | //info->description = N_("Adobe Photoshop format"); | ||
662 | 591 | info->description = "Adobe Photoshop format"; | ||
663 | 592 | info->mime_types = mime_types; | ||
664 | 593 | info->extensions = extensions; | ||
665 | 594 | info->flags = GDK_PIXBUF_FORMAT_THREADSAFE; | ||
666 | 595 | info->flags = 0; | ||
667 | 596 | info->license = "LGPL"; | ||
668 | 597 | } | ||
669 | 598 | |||
670 | 599 | 0 | ||
671 | === removed directory 'src/loaders/XCF' | |||
672 | === removed file 'src/loaders/XCF/Makefile.am' | |||
673 | --- src/loaders/XCF/Makefile.am 2010-08-21 18:06:49 +0000 | |||
674 | +++ src/loaders/XCF/Makefile.am 1970-01-01 00:00:00 +0000 | |||
675 | @@ -1,13 +0,0 @@ | |||
676 | 1 | #pluginexecdir = $(prefix)/lib/gtk-2.0/2.10.0/loaders/ | ||
677 | 2 | pluginexecdir = $(prefix)/lib/gdk-pixbuf-2.0/2.10.0/loaders/ | ||
678 | 3 | |||
679 | 4 | AM_CPPFLAGS += $(GTK_CFLAGS) $(GDKPIXBUF_CFLAGS) $(GLIB_CFLAGS) -shared -fpic -g -std=c99 -DGDK_PIXBUF_ENABLE_BACKEND | ||
680 | 5 | AM_LDFLAGS = $(GTK_LIBS) $(GDKPIXBUF_LIBS) $(GLIB_LIBS) | ||
681 | 6 | |||
682 | 7 | |||
683 | 8 | pluginexec_LTLIBRARIES = libpixbufloader-xcf.la | ||
684 | 9 | libpixbufloader_xcf_la_SOURCES = io-xcf.c | ||
685 | 10 | libpixbufloader_xcf_la_LDFLAGS = -module -export-dynamic $(AM_LDFLAGS) | ||
686 | 11 | |||
687 | 12 | #install-exec-hook: | ||
688 | 13 | # install -d $(prefix)/lib/gdk-pixbuf-2.0/2.10.0/loaders/ | ||
689 | 14 | 0 | ||
690 | === removed file 'src/loaders/XCF/io-xcf.c' | |||
691 | --- src/loaders/XCF/io-xcf.c 2010-05-24 09:46:52 +0000 | |||
692 | +++ src/loaders/XCF/io-xcf.c 1970-01-01 00:00:00 +0000 | |||
693 | @@ -1,1641 +0,0 @@ | |||
694 | 1 | /* | ||
695 | 2 | * Pixbuf loader for xcf | ||
696 | 3 | * | ||
697 | 4 | * Author(s): | ||
698 | 5 | * Stephane Delcroix <stephane@delcroix.org> | ||
699 | 6 | * | ||
700 | 7 | * Copyright (C) 2009 Novell, Inc | ||
701 | 8 | * | ||
702 | 9 | * This is a clean room implementation, based solely on | ||
703 | 10 | * http://henning.makholm.net/xcftools/xcfspec.txt and hexdumps | ||
704 | 11 | * of existing .xcf files. | ||
705 | 12 | * | ||
706 | 13 | * This library is free software; you can redistribute it and/or | ||
707 | 14 | * modify it under the terms of the GNU Lesser General Public | ||
708 | 15 | * License as published by the Free Software Foundation; either | ||
709 | 16 | * version 2 of the License, or (at your option) any later version. | ||
710 | 17 | * | ||
711 | 18 | * This library is distributed in the hope that it will be useful, | ||
712 | 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
713 | 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
714 | 21 | * Lesser General Public License for more details. | ||
715 | 22 | * | ||
716 | 23 | * You should have received a copy of the GNU Lesser General Public | ||
717 | 24 | * License along with this library; if not, write to the | ||
718 | 25 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
719 | 26 | * Boston, MA 02111-1307, USA. | ||
720 | 27 | */ | ||
721 | 28 | |||
722 | 29 | /* | ||
723 | 30 | * TODO: | ||
724 | 31 | * - fix the spots/stains (where are they coming from) ? | ||
725 | 32 | * - indexed mode | ||
726 | 33 | * - if the bg layer mode is not Normal or Dissolve, change it to Normal | ||
727 | 34 | * - file an enhancement request to gdk-pixbuf | ||
728 | 35 | */ | ||
729 | 36 | |||
730 | 37 | //#define GDK_PIXBUF_ENABLE_BACKEND | ||
731 | 38 | |||
732 | 39 | #include <gmodule.h> | ||
733 | 40 | #include <gdk-pixbuf/gdk-pixbuf.h> | ||
734 | 41 | #include <gio/gio.h> | ||
735 | 42 | #if GIO_2_23 | ||
736 | 43 | #include <gio/gzlibcompressor.h> | ||
737 | 44 | #include <gio/gunixinputstream.h> | ||
738 | 45 | #include <gio/gunixoutputstream.h> | ||
739 | 46 | #endif | ||
740 | 47 | #include <stdio.h> | ||
741 | 48 | #include <math.h> | ||
742 | 49 | #include <string.h> | ||
743 | 50 | #include <stdlib.h> | ||
744 | 51 | #include <errno.h> | ||
745 | 52 | #include <bzlib.h> | ||
746 | 53 | #include <glib.h> | ||
747 | 54 | #include <glib/gstdio.h> | ||
748 | 55 | |||
749 | 56 | //#define LOG(...) printf (__VA_ARGS__); | ||
750 | 57 | #define LOG(...) | ||
751 | 58 | |||
752 | 59 | #define _GNU_SOURCE 1 | ||
753 | 60 | #define POSIX_SOURCE 1 | ||
754 | 61 | |||
755 | 62 | #define PROP_END 0 | ||
756 | 63 | #define PROP_COLORMAP 1 | ||
757 | 64 | #define PROP_FLOATING_SELECTION 5 | ||
758 | 65 | #define PROP_OPACITY 6 | ||
759 | 66 | #define PROP_MODE 7 | ||
760 | 67 | #define PROP_VISIBLE 8 | ||
761 | 68 | #define PROP_LINKED 9 | ||
762 | 69 | #define PROP_APPLY_MASK 11 | ||
763 | 70 | #define PROP_OFFSETS 15 | ||
764 | 71 | #define PROP_COMPRESSION 17 | ||
765 | 72 | #define PROP_GUIDES 18 | ||
766 | 73 | #define PROP_RESOLUTION 19 | ||
767 | 74 | #define PROP_TATOO 20 | ||
768 | 75 | #define PROP_PARASITES 21 | ||
769 | 76 | #define PROP_UNIT 22 | ||
770 | 77 | #define PROP_PATHS 23 | ||
771 | 78 | #define PROP_USER_UNIT 24 | ||
772 | 79 | #define PROP_VECTORS 25 | ||
773 | 80 | |||
774 | 81 | #define COMPRESSION_NONE 0 | ||
775 | 82 | #define COMPRESSION_RLE 1 | ||
776 | 83 | |||
777 | 84 | #define LAYERTYPE_RGB 0 | ||
778 | 85 | #define LAYERTYPE_RGBA 1 | ||
779 | 86 | #define LAYERTYPE_GRAYSCALE 2 | ||
780 | 87 | #define LAYERTYPE_GRAYSCALEA 3 | ||
781 | 88 | #define LAYERTYPE_INDEXED 4 | ||
782 | 89 | #define LAYERTYPE_INDEXEDA 5 | ||
783 | 90 | |||
784 | 91 | #define LAYERMODE_NORMAL 0 | ||
785 | 92 | #define LAYERMODE_DISSOLVE 1 | ||
786 | 93 | #define LAYERMODE_BEHIND 2 | ||
787 | 94 | #define LAYERMODE_MULTIPLY 3 | ||
788 | 95 | #define LAYERMODE_SCREEN 4 | ||
789 | 96 | #define LAYERMODE_OVERLAY 5 | ||
790 | 97 | #define LAYERMODE_DIFFERENCE 6 | ||
791 | 98 | #define LAYERMODE_ADDITION 7 | ||
792 | 99 | #define LAYERMODE_SUBTRACT 8 | ||
793 | 100 | #define LAYERMODE_DARKENONLY 9 | ||
794 | 101 | #define LAYERMODE_LIGHTENONLY 10 | ||
795 | 102 | #define LAYERMODE_HUE 11 | ||
796 | 103 | #define LAYERMODE_SATURATION 12 | ||
797 | 104 | #define LAYERMODE_COLOR 13 | ||
798 | 105 | #define LAYERMODE_VALUE 14 | ||
799 | 106 | #define LAYERMODE_DIVIDE 15 | ||
800 | 107 | #define LAYERMODE_DODGE 16 | ||
801 | 108 | #define LAYERMODE_BURN 17 | ||
802 | 109 | #define LAYERMODE_HARDLIGHT 18 | ||
803 | 110 | #define LAYERMODE_SOFTLIGHT 19 | ||
804 | 111 | #define LAYERMODE_GRAINEXTRACT 20 | ||
805 | 112 | #define LAYERMODE_GRAINMERGE 21 | ||
806 | 113 | |||
807 | 114 | #define FILETYPE_STREAMCLOSED -1 | ||
808 | 115 | #define FILETYPE_UNKNOWN 0 | ||
809 | 116 | #define FILETYPE_XCF 1 | ||
810 | 117 | #define FILETYPE_XCF_BZ2 2 | ||
811 | 118 | #if GIO_2_23 | ||
812 | 119 | #define FILETYPE_XCF_GZ 3 | ||
813 | 120 | #endif | ||
814 | 121 | |||
815 | 122 | extern FILE *fdopen (int __fd, __const char *__modes) __THROW __wur; | ||
816 | 123 | |||
817 | 124 | typedef struct _XcfContext XcfContext; | ||
818 | 125 | struct _XcfContext { | ||
819 | 126 | GdkPixbufModuleSizeFunc size_func; | ||
820 | 127 | GdkPixbufModulePreparedFunc prepare_func; | ||
821 | 128 | GdkPixbufModuleUpdatedFunc update_func; | ||
822 | 129 | gpointer user_data; | ||
823 | 130 | gint type; | ||
824 | 131 | bz_stream *bz_stream; | ||
825 | 132 | |||
826 | 133 | #if GIO_2_23 | ||
827 | 134 | GInputStream *input, *stream; | ||
828 | 135 | #endif | ||
829 | 136 | |||
830 | 137 | gchar *tempname; | ||
831 | 138 | FILE *file; | ||
832 | 139 | }; | ||
833 | 140 | |||
834 | 141 | typedef struct _XcfChannel XcfChannel; | ||
835 | 142 | struct _XcfChannel { | ||
836 | 143 | guint32 width; | ||
837 | 144 | guint32 height; | ||
838 | 145 | gboolean visible; | ||
839 | 146 | guint32 opacity; | ||
840 | 147 | guint32 lptr; | ||
841 | 148 | }; | ||
842 | 149 | |||
843 | 150 | typedef struct _XcfLayer XcfLayer; | ||
844 | 151 | struct _XcfLayer { | ||
845 | 152 | guint32 width; | ||
846 | 153 | guint32 height; | ||
847 | 154 | guint32 type; | ||
848 | 155 | guint32 mode; | ||
849 | 156 | gboolean apply_mask; | ||
850 | 157 | gboolean visible; | ||
851 | 158 | guint32 opacity; | ||
852 | 159 | gint32 dx; | ||
853 | 160 | gint32 dy; | ||
854 | 161 | XcfChannel* layer_mask; | ||
855 | 162 | guint32 lptr;; | ||
856 | 163 | }; | ||
857 | 164 | |||
858 | 165 | void | ||
859 | 166 | rle_decode (FILE *f, gchar *ptr, int count, int type) | ||
860 | 167 | { | ||
861 | 168 | int channels; | ||
862 | 169 | switch (type) { | ||
863 | 170 | case LAYERTYPE_RGB : channels = 3; break; | ||
864 | 171 | case LAYERTYPE_RGBA: channels = 4; break; | ||
865 | 172 | case LAYERTYPE_GRAYSCALE: channels = 1; break; | ||
866 | 173 | case LAYERTYPE_GRAYSCALEA: channels = 2; break; | ||
867 | 174 | case LAYERTYPE_INDEXED: channels = 1; break; | ||
868 | 175 | case LAYERTYPE_INDEXEDA: channels = 2; break; | ||
869 | 176 | } | ||
870 | 177 | |||
871 | 178 | guchar opcode; | ||
872 | 179 | guchar buffer[3]; | ||
873 | 180 | guchar ch[channels][count]; | ||
874 | 181 | int channel; | ||
875 | 182 | size_t lfr; | ||
876 | 183 | |||
877 | 184 | //un-rle | ||
878 | 185 | for (channel = 0; channel < channels; channel++) { | ||
879 | 186 | int pixels_count = 0; | ||
880 | 187 | while (pixels_count < count) { | ||
881 | 188 | lfr = fread (&opcode, sizeof(guchar), 1, f); | ||
882 | 189 | if (opcode <= 126) { | ||
883 | 190 | lfr = fread (buffer, 1, 1, f); | ||
884 | 191 | opcode ++; | ||
885 | 192 | while (opcode --) | ||
886 | 193 | memcpy (ch[channel] + (pixels_count++), buffer, 1); | ||
887 | 194 | } else if (opcode == 127) { | ||
888 | 195 | lfr = fread (buffer, 3, 1, f); | ||
889 | 196 | int p = buffer[0]; | ||
890 | 197 | int q = buffer[1]; | ||
891 | 198 | int count = p*256+q; | ||
892 | 199 | while (count --) | ||
893 | 200 | memcpy (ch[channel] + (pixels_count++), buffer+2, 1); | ||
894 | 201 | } else if (opcode == 128) { | ||
895 | 202 | lfr = fread (buffer, 2, 1, f); | ||
896 | 203 | int p = buffer[0]; | ||
897 | 204 | int q = buffer[1]; | ||
898 | 205 | lfr = fread (ch[channel] + pixels_count, p*256+q, 1, f); | ||
899 | 206 | pixels_count += p*256+q; | ||
900 | 207 | } else if (opcode >= 129) { | ||
901 | 208 | lfr = fread (ch[channel] + pixels_count, 256 - opcode, 1, f); | ||
902 | 209 | pixels_count += 256 - opcode; | ||
903 | 210 | } | ||
904 | 211 | } | ||
905 | 212 | } | ||
906 | 213 | |||
907 | 214 | //reinterlace the channels | ||
908 | 215 | int i, j; | ||
909 | 216 | for (i=0; i <count; i++) | ||
910 | 217 | for (j=0; j<channels; j++) | ||
911 | 218 | memcpy (ptr + i * channels + j, ch[j] + i, 1); | ||
912 | 219 | } | ||
913 | 220 | |||
914 | 221 | void | ||
915 | 222 | to_rgba (gchar *ptr, int count, int type) | ||
916 | 223 | { | ||
917 | 224 | //pad to rgba | ||
918 | 225 | int i; | ||
919 | 226 | |||
920 | 227 | for (i=count-1; i>=0;i--) | ||
921 | 228 | switch (type) { | ||
922 | 229 | case LAYERTYPE_RGB: | ||
923 | 230 | memcpy (ptr + 4*i, ptr + 3*i, 3); | ||
924 | 231 | ptr[4*i + 3] = 0xff; | ||
925 | 232 | break; | ||
926 | 233 | case LAYERTYPE_RGBA: | ||
927 | 234 | ///nothing to do | ||
928 | 235 | break; | ||
929 | 236 | case LAYERTYPE_GRAYSCALE: | ||
930 | 237 | memcpy (ptr + 4*i, ptr + i, 1); | ||
931 | 238 | memcpy (ptr + 4*i + 1, ptr + i, 1); | ||
932 | 239 | memcpy (ptr + 4*i + 2, ptr + i, 1); | ||
933 | 240 | ptr[4*i + 3] = 0xff; | ||
934 | 241 | break; | ||
935 | 242 | case LAYERTYPE_GRAYSCALEA: | ||
936 | 243 | memcpy (ptr + 4*i, ptr + i, 1); | ||
937 | 244 | memcpy (ptr + 4*i + 1, ptr + i, 1); | ||
938 | 245 | memcpy (ptr + 4*i + 2, ptr + i, 1); | ||
939 | 246 | memcpy (ptr + 4+i + 3, ptr + i + 1, 1); | ||
940 | 247 | break; | ||
941 | 248 | } | ||
942 | 249 | } | ||
943 | 250 | |||
944 | 251 | void | ||
945 | 252 | apply_opacity (guchar* ptr, int size, guint32 opacity) | ||
946 | 253 | { | ||
947 | 254 | int i; | ||
948 | 255 | for (i=0; i<size; i++) | ||
949 | 256 | ptr[4*i + 3] = (guchar)((ptr[4*i+3] * opacity) / 0xff); | ||
950 | 257 | } | ||
951 | 258 | |||
952 | 259 | void | ||
953 | 260 | apply_mask (FILE *f, gchar compression, guchar *ptr, int size, XcfChannel *mask, int tile_id) | ||
954 | 261 | { | ||
955 | 262 | //save file position | ||
956 | 263 | long pos = ftell (f); | ||
957 | 264 | size_t lfr; | ||
958 | 265 | |||
959 | 266 | guint32 tptr = mask->lptr + (2 + tile_id) * sizeof(guint32); //skip width and height | ||
960 | 267 | fseek (f, tptr, SEEK_SET); | ||
961 | 268 | lfr = fread (&tptr, sizeof(guint32), 1, f); | ||
962 | 269 | fseek (f, GUINT32_FROM_BE(tptr), SEEK_SET); | ||
963 | 270 | |||
964 | 271 | gchar pixels[4096]; | ||
965 | 272 | if (compression == COMPRESSION_RLE) | ||
966 | 273 | rle_decode (f, pixels, size, LAYERTYPE_GRAYSCALE); | ||
967 | 274 | else //COMPRESSION_NONE | ||
968 | 275 | lfr = fread (pixels, sizeof(gchar), size, f); | ||
969 | 276 | |||
970 | 277 | int i; | ||
971 | 278 | for (i = 0; i<size; i++) | ||
972 | 279 | ptr[4*i + 3] = ptr[4 * i + 3] * pixels[i] / 0xff; | ||
973 | 280 | |||
974 | 281 | //rewind | ||
975 | 282 | fseek (f, pos, SEEK_SET); | ||
976 | 283 | } | ||
977 | 284 | |||
978 | 285 | |||
979 | 286 | void | ||
980 | 287 | intersect_tile (guchar* ptr, int im_width, int im_height, int *ox, int *oy, int *tw, int *th) | ||
981 | 288 | { | ||
982 | 289 | int i; | ||
983 | 290 | if (*ox < 0) { | ||
984 | 291 | for (i=0; i<*th; i++) { | ||
985 | 292 | memmove (ptr + 4 * i * (*tw + *ox), ptr + 4 * i * (*tw), 4 * (*tw + *ox)); | ||
986 | 293 | } | ||
987 | 294 | *tw = *tw + *ox; | ||
988 | 295 | *ox = 0; | ||
989 | 296 | } | ||
990 | 297 | if (*oy < 0) { | ||
991 | 298 | memmove (ptr, ptr + 4 * *tw * -*oy, 4 * *tw * (*th + *oy)); | ||
992 | 299 | *th = *th + *oy; | ||
993 | 300 | *oy = 0; | ||
994 | 301 | } | ||
995 | 302 | if (*ox + *tw > im_width) { | ||
996 | 303 | for (i=0; i<*th; i++) { | ||
997 | 304 | memmove (ptr + 4 * i * (im_width - *ox), ptr + 4 * i * (*tw), 4 * (im_width - *ox)); | ||
998 | 305 | } | ||
999 | 306 | *tw = im_width - *ox; | ||
1000 | 307 | } | ||
1001 | 308 | if (*oy + *th > im_height) { | ||
1002 | 309 | *th = im_height - *oy; | ||
1003 | 310 | } | ||
1004 | 311 | } | ||
1005 | 312 | |||
1006 | 313 | void blend (guchar* rgba0, guchar* rgba1) | ||
1007 | 314 | { | ||
1008 | 315 | if (rgba0[3] == 0 && rgba1[3] == 0) | ||
1009 | 316 | return; | ||
1010 | 317 | |||
1011 | 318 | guchar k = 0xff * rgba1[3] / (0xff - (0xff-rgba0[3])*(0xff-rgba1[3])/0xff); | ||
1012 | 319 | rgba0[0] = ((0xff - k) * rgba0[0] + k * rgba1[0]) / 0xff; | ||
1013 | 320 | rgba0[1] = ((0xff - k) * rgba0[1] + k * rgba1[1]) / 0xff; | ||
1014 | 321 | rgba0[2] = ((0xff - k) * rgba0[2] + k * rgba1[2]) / 0xff; | ||
1015 | 322 | } | ||
1016 | 323 | |||
1017 | 324 | typedef void (*composite_func) (guchar* rgb0, guchar* rgb1); | ||
1018 | 325 | |||
1019 | 326 | void | ||
1020 | 327 | multiply (guchar *rgb0, guchar *rgb1) | ||
1021 | 328 | { | ||
1022 | 329 | rgb1[0] = (rgb0[0] * rgb1[0] ) / 0xff; | ||
1023 | 330 | rgb1[1] = (rgb0[1] * rgb1[1] ) / 0xff; | ||
1024 | 331 | rgb1[2] = (rgb0[2] * rgb1[2] ) / 0xff; | ||
1025 | 332 | } | ||
1026 | 333 | |||
1027 | 334 | void | ||
1028 | 335 | screen (guchar *rgb0, guchar *rgb1) | ||
1029 | 336 | { | ||
1030 | 337 | rgb1[0] = 0xff - (0xff - rgb0[0]) * (0xff - rgb1[0]) / 0xff; | ||
1031 | 338 | rgb1[1] = 0xff - (0xff - rgb0[1]) * (0xff - rgb1[1]) / 0xff; | ||
1032 | 339 | rgb1[2] = 0xff - (0xff - rgb0[2]) * (0xff - rgb1[2]) / 0xff; | ||
1033 | 340 | } | ||
1034 | 341 | |||
1035 | 342 | void | ||
1036 | 343 | overlay (guchar *rgb0, guchar *rgb1) | ||
1037 | 344 | { | ||
1038 | 345 | //FIXME | ||
1039 | 346 | //LOG ("Overlay (%d %d %d) (%d %d %d) : ", rgb0[0], rgb0[1], rgb0[2], rgb1[0], rgb1[1], rgb1[2]); | ||
1040 | 347 | rgb1[0] = MIN (0xff, ((0xff - rgb1[0]) * rgb0[0] * rgb0[0] / 0xff + rgb0[0] * (0xff - (0xff - rgb1[0]) * (0xff - rgb1[0]) / 0xff)) / 0xff); | ||
1041 | 348 | rgb1[1] = MIN (0xff, ((0xff - rgb1[1]) * rgb0[1] * rgb0[1] / 0xff + rgb0[1] * (0xff - (0xff - rgb1[1]) * (0xff - rgb1[1]) / 0xff)) / 0xff); | ||
1042 | 349 | rgb1[2] = MIN (0xff, ((0xff - rgb1[2]) * rgb0[2] * rgb0[2] / 0xff + rgb0[2] * (0xff - (0xff - rgb1[2]) * (0xff - rgb1[2]) / 0xff)) / 0xff); | ||
1043 | 350 | //LOG ("(%d %d %d)\n", rgb1[0], rgb1[1], rgb1[2]); | ||
1044 | 351 | } | ||
1045 | 352 | |||
1046 | 353 | void | ||
1047 | 354 | difference (guchar *rgb0, guchar *rgb1) | ||
1048 | 355 | { | ||
1049 | 356 | rgb1[0] = (rgb0[0] > rgb1[0]) ? rgb0[0] - rgb1[0] : rgb1[0] - rgb0[0]; | ||
1050 | 357 | rgb1[1] = (rgb0[1] > rgb1[1]) ? rgb0[1] - rgb1[1] : rgb1[1] - rgb0[1]; | ||
1051 | 358 | rgb1[2] = (rgb0[2] > rgb1[2]) ? rgb0[2] - rgb1[2] : rgb1[2] - rgb0[2]; | ||
1052 | 359 | } | ||
1053 | 360 | |||
1054 | 361 | void | ||
1055 | 362 | addition (guchar *rgb0, guchar *rgb1) | ||
1056 | 363 | { | ||
1057 | 364 | // LOG ("addition (%d %d %d) (%d %d %d):", rgb0[0], rgb0[1], rgb0[2], rgb1[0], rgb1[1], rgb1[2]); | ||
1058 | 365 | rgb1[0] = (rgb0[0] + rgb1[0]) > 0xff ? 0xff : rgb0[0] + rgb1[0]; | ||
1059 | 366 | rgb1[1] = (rgb0[1] + rgb1[1]) > 0xff ? 0xff : rgb0[1] + rgb1[1]; | ||
1060 | 367 | rgb1[2] = (rgb0[2] + rgb1[2]) > 0xff ? 0xff : rgb0[2] + rgb1[2]; | ||
1061 | 368 | // LOG ("(%d %d %d)\n", rgb1[0], rgb1[1], rgb1[2]); | ||
1062 | 369 | } | ||
1063 | 370 | |||
1064 | 371 | void | ||
1065 | 372 | subtract (guchar *rgb0, guchar *rgb1) | ||
1066 | 373 | { | ||
1067 | 374 | rgb1[0] = (rgb0[0] - rgb1[0]) < 0 ? 0 : rgb0[0] - rgb1[0]; | ||
1068 | 375 | rgb1[1] = (rgb0[1] - rgb1[1]) < 0 ? 0 : rgb0[1] - rgb1[1]; | ||
1069 | 376 | rgb1[2] = (rgb0[2] - rgb1[2]) < 0 ? 0 : rgb0[2] - rgb1[2]; | ||
1070 | 377 | } | ||
1071 | 378 | |||
1072 | 379 | void | ||
1073 | 380 | min (guchar *rgb0, guchar *rgb1) | ||
1074 | 381 | { | ||
1075 | 382 | rgb1[0] = MIN (rgb0[0], rgb1[0]); | ||
1076 | 383 | rgb1[1] = MIN (rgb0[1], rgb1[1]); | ||
1077 | 384 | rgb1[2] = MIN (rgb0[2], rgb1[2]); | ||
1078 | 385 | } | ||
1079 | 386 | |||
1080 | 387 | void | ||
1081 | 388 | max (guchar *rgb0, guchar *rgb1) | ||
1082 | 389 | { | ||
1083 | 390 | rgb1[0] = MAX (rgb0[0], rgb1[0]); | ||
1084 | 391 | rgb1[1] = MAX (rgb0[1], rgb1[1]); | ||
1085 | 392 | rgb1[2] = MAX (rgb0[2], rgb1[2]); | ||
1086 | 393 | } | ||
1087 | 394 | |||
1088 | 395 | void | ||
1089 | 396 | divide (guchar *rgb0, guchar *rgb1) | ||
1090 | 397 | { | ||
1091 | 398 | rgb1[0] = rgb1[0] == 0 ? (rgb0[0] == 0 ? 0 : 0xff) : MIN (0xff, 0xff * rgb0[0] / rgb1[0]); | ||
1092 | 399 | rgb1[1] = rgb1[1] == 0 ? (rgb0[1] == 0 ? 0 : 0xff) : MIN (0xff, 0xff * rgb0[1] / rgb1[1]); | ||
1093 | 400 | rgb1[2] = rgb1[2] == 0 ? (rgb0[2] == 0 ? 0 : 0xff) : MIN (0xff, 0xff * rgb0[2] / rgb1[2]); | ||
1094 | 401 | } | ||
1095 | 402 | |||
1096 | 403 | void | ||
1097 | 404 | dodge (guchar *rgb0, guchar *rgb1) | ||
1098 | 405 | { | ||
1099 | 406 | rgb1[0] = rgb1[0] == 0xff ? (rgb0[0] == 0 ? 0 : 0xff) : MIN (0xff, 0xff * rgb0[0] / (0xff - rgb1[0])); | ||
1100 | 407 | rgb1[1] = rgb1[1] == 0xff ? (rgb0[1] == 0 ? 0 : 0xff) : MIN (0xff, 0xff * rgb0[1] / (0xff - rgb1[1])); | ||
1101 | 408 | rgb1[2] = rgb1[2] == 0xff ? (rgb0[2] == 0 ? 0 : 0xff) : MIN (0xff, 0xff * rgb0[2] / (0xff - rgb1[2])); | ||
1102 | 409 | } | ||
1103 | 410 | |||
1104 | 411 | void | ||
1105 | 412 | burn (guchar *rgb0, guchar *rgb1) // 1-(1-x1)/x2 | ||
1106 | 413 | { | ||
1107 | 414 | rgb1[0] = rgb1[0] == 0 ? (rgb0[0] == 0xff ? 0xff : 0) : 0xff - MIN (0xff, 0xff * (0xff - rgb0[0]) / rgb1[0]); | ||
1108 | 415 | rgb1[1] = rgb1[1] == 0 ? (rgb0[1] == 0xff ? 0xff : 0) : 0xff - MIN (0xff, 0xff * (0xff - rgb0[1]) / rgb1[1]); | ||
1109 | 416 | rgb1[2] = rgb1[2] == 0 ? (rgb0[2] == 0xff ? 0xff : 0) : 0xff - MIN (0xff, 0xff * (0xff - rgb0[2]) / rgb1[2]); | ||
1110 | 417 | } | ||
1111 | 418 | |||
1112 | 419 | void | ||
1113 | 420 | hardlight (guchar *rgb0, guchar *rgb1) //if x2 < 0.5 then 2*x1*x2 else 1-2*(1-x1)(1-x2) | ||
1114 | 421 | { | ||
1115 | 422 | rgb1[0] = rgb1[0] < 0x80 ? 2 * rgb0[0] * rgb1[0] / 0xff : 0xff - 2 * (0xff - rgb0[0]) * (0xff - rgb1[0])/ 0xff; | ||
1116 | 423 | rgb1[1] = rgb1[1] < 0x80 ? 2 * rgb0[1] * rgb1[1] / 0xff : 0xff - 2 * (0xff - rgb0[1]) * (0xff - rgb1[1])/ 0xff; | ||
1117 | 424 | rgb1[2] = rgb1[2] < 0x80 ? 2 * rgb0[2] * rgb1[2] / 0xff : 0xff - 2 * (0xff - rgb0[2]) * (0xff - rgb1[2])/ 0xff; | ||
1118 | 425 | } | ||
1119 | 426 | |||
1120 | 427 | void | ||
1121 | 428 | softlight(guchar *rgb0, guchar *rgb1) | ||
1122 | 429 | { | ||
1123 | 430 | //FIXME | ||
1124 | 431 | //LOG ("Softlight (%d %d %d) (%d %d %d) : ", rgb0[0], rgb0[1], rgb0[2], rgb1[0], rgb1[1], rgb1[2]); | ||
1125 | 432 | rgb1[0] = ((0xff - rgb0[0]) * rgb0[0] * rgb1[0] / 0xff + rgb0[0] * (0xff - (0xff - rgb1[0]) * (0xff - rgb0[0]) / 0x100)) / 0x100; | ||
1126 | 433 | rgb1[1] = ((0xff - rgb0[1]) * rgb0[1] * rgb1[1] / 0xff + rgb0[1] * (0xff - (0xff - rgb1[1]) * (0xff - rgb0[1]) / 0x100)) / 0x100; | ||
1127 | 434 | rgb1[2] = ((0xff - rgb0[2]) * rgb0[2] * rgb1[2] / 0xff + rgb0[2] * (0xff - (0xff - rgb1[2]) * (0xff - rgb0[2]) / 0x100)) / 0x100; | ||
1128 | 435 | //LOG ("(%d %d %d)\n", rgb1[0], rgb1[1], rgb1[2]); | ||
1129 | 436 | } | ||
1130 | 437 | |||
1131 | 438 | void | ||
1132 | 439 | grainextract (guchar *rgb0, guchar *rgb1) //x1-x2+.5 | ||
1133 | 440 | { | ||
1134 | 441 | rgb1[0] = MAX (0, MIN (0xff, rgb0[0] - rgb1[0] + 0x80)); | ||
1135 | 442 | rgb1[1] = MAX (0, MIN (0xff, rgb0[1] - rgb1[1] + 0x80)); | ||
1136 | 443 | rgb1[2] = MAX (0, MIN (0xff, rgb0[2] - rgb1[2] + 0x80)); | ||
1137 | 444 | } | ||
1138 | 445 | |||
1139 | 446 | void | ||
1140 | 447 | grainmerge (guchar *rgb0, guchar *rgb1) | ||
1141 | 448 | { | ||
1142 | 449 | rgb1[0] = MAX (0, MIN (0xff, rgb0[0] + rgb1[0] - 0x80)); | ||
1143 | 450 | rgb1[1] = MAX (0, MIN (0xff, rgb0[1] + rgb1[1] - 0x80)); | ||
1144 | 451 | rgb1[2] = MAX (0, MIN (0xff, rgb0[2] + rgb1[2] - 0x80)); | ||
1145 | 452 | } | ||
1146 | 453 | |||
1147 | 454 | |||
1148 | 455 | //FIXME: any way to do the following 4 ones in integer arithmetic ? | ||
1149 | 456 | void | ||
1150 | 457 | hue (guchar *rgb0, guchar *rgb1) | ||
1151 | 458 | { | ||
1152 | 459 | if (rgb1[0] == rgb1[1] == rgb1[2]) { | ||
1153 | 460 | rgb1[0] = rgb0[0]; | ||
1154 | 461 | rgb1[1] = rgb0[1]; | ||
1155 | 462 | rgb1[2] = rgb0[2]; | ||
1156 | 463 | return; | ||
1157 | 464 | } | ||
1158 | 465 | //hue of rgb1, value and saturation of rgb0 | ||
1159 | 466 | guchar min0 = MIN (MIN (rgb0[0], rgb0[1]), rgb0[2]); | ||
1160 | 467 | guchar max0 = MAX (MAX (rgb0[0], rgb0[1]), rgb0[2]); | ||
1161 | 468 | guchar min1 = MIN (MIN (rgb1[0], rgb1[1]), rgb1[2]); | ||
1162 | 469 | guchar max1 = MAX (MAX (rgb1[0], rgb1[1]), rgb1[2]); | ||
1163 | 470 | if (max0 == 0) { | ||
1164 | 471 | rgb1[0] = 0x00; | ||
1165 | 472 | rgb1[1] = 0x00; | ||
1166 | 473 | rgb1[2] = 0x00; | ||
1167 | 474 | return; | ||
1168 | 475 | } | ||
1169 | 476 | double p = max0 * (max0 - min0) / (max1*(max0-min0) - min1*max0 + max1*min0); | ||
1170 | 477 | double q = - max0 * (min1*max0 - max1*min0) / (max1*(max0-min0) - min1*max0 + max1*min0); | ||
1171 | 478 | rgb1[0] = (guchar)(rgb1[0] * p + q); | ||
1172 | 479 | rgb1[1] = (guchar)(rgb1[1] * p + q); | ||
1173 | 480 | rgb1[2] = (guchar)(rgb1[2] * p + q); | ||
1174 | 481 | } | ||
1175 | 482 | |||
1176 | 483 | void | ||
1177 | 484 | saturation (guchar *rgb0, guchar *rgb1) | ||
1178 | 485 | { | ||
1179 | 486 | //hue and value of rgb0, saturation of rgb1 | ||
1180 | 487 | guchar min0 = MIN (MIN (rgb0[0], rgb0[1]), rgb0[2]); | ||
1181 | 488 | guchar max0 = MAX (MAX (rgb0[0], rgb0[1]), rgb0[2]); | ||
1182 | 489 | guchar min1 = MIN (MIN (rgb1[0], rgb1[1]), rgb1[2]); | ||
1183 | 490 | guchar max1 = MAX (MAX (rgb1[0], rgb1[1]), rgb1[2]); | ||
1184 | 491 | if (max0 == 0) { | ||
1185 | 492 | rgb1[0] = 0x00; | ||
1186 | 493 | rgb1[1] = 0x00; | ||
1187 | 494 | rgb1[2] = 0x00; | ||
1188 | 495 | return; | ||
1189 | 496 | } | ||
1190 | 497 | if (max0 == min0) { | ||
1191 | 498 | rgb1[0] = max0; | ||
1192 | 499 | rgb1[1] = min1*max0 / max0; | ||
1193 | 500 | rgb1[2] = rgb1[1]; | ||
1194 | 501 | return; | ||
1195 | 502 | } | ||
1196 | 503 | double p = max0 * (min1 - max1) / (max0*(min1-max1) - min1*max0 + max1*min0); | ||
1197 | 504 | double q = - max0 * (min1*max0 - max1*min0) / (max0*(min1-max1) - min1*max0 + max1*min0); | ||
1198 | 505 | rgb1[0] = (guchar)(rgb0[0] * p + q); | ||
1199 | 506 | rgb1[1] = (guchar)(rgb0[1] * p + q); | ||
1200 | 507 | rgb1[2] = (guchar)(rgb0[2] * p + q); | ||
1201 | 508 | |||
1202 | 509 | } | ||
1203 | 510 | |||
1204 | 511 | void | ||
1205 | 512 | value (guchar *rgb0, guchar *rgb1) | ||
1206 | 513 | { | ||
1207 | 514 | //hue and saturation ov rgb0, value of rgb1 | ||
1208 | 515 | guchar min0 = MIN (MIN (rgb0[0], rgb0[1]), rgb0[2]); | ||
1209 | 516 | guchar max0 = MAX (MAX (rgb0[0], rgb0[1]), rgb0[2]); | ||
1210 | 517 | guchar min1 = MIN (MIN (rgb1[0], rgb1[1]), rgb1[2]); | ||
1211 | 518 | guchar max1 = MAX (MAX (rgb1[0], rgb1[1]), rgb1[2]); | ||
1212 | 519 | if (max0 == 0) { | ||
1213 | 520 | rgb1[0] = 0x00; | ||
1214 | 521 | rgb1[1] = 0x00; | ||
1215 | 522 | rgb1[2] = 0x00; | ||
1216 | 523 | return; | ||
1217 | 524 | } | ||
1218 | 525 | if (max0 == min0) { | ||
1219 | 526 | rgb1[0] = max1; | ||
1220 | 527 | rgb1[1] = max1; | ||
1221 | 528 | rgb1[2] = max1; | ||
1222 | 529 | return; | ||
1223 | 530 | } | ||
1224 | 531 | |||
1225 | 532 | double p = max1 / max0; | ||
1226 | 533 | |||
1227 | 534 | rgb1[0] = (guchar)(rgb0[0] * p); | ||
1228 | 535 | rgb1[1] = (guchar)(rgb0[1] * p); | ||
1229 | 536 | rgb1[2] = (guchar)(rgb0[2] * p); | ||
1230 | 537 | } | ||
1231 | 538 | |||
1232 | 539 | void | ||
1233 | 540 | color (guchar *rgb0, guchar *rgb1) | ||
1234 | 541 | { | ||
1235 | 542 | //hue and hsl-saturation or rgb1, luminosity of rgb0 | ||
1236 | 543 | guchar min0 = MIN (MIN (rgb0[0], rgb0[1]), rgb0[2]); | ||
1237 | 544 | guchar max0 = MAX (MAX (rgb0[0], rgb0[1]), rgb0[2]); | ||
1238 | 545 | guchar min1 = MIN (MIN (rgb1[0], rgb1[1]), rgb1[2]); | ||
1239 | 546 | guchar max1 = MAX (MAX (rgb1[0], rgb1[1]), rgb1[2]); | ||
1240 | 547 | |||
1241 | 548 | double p = MIN ((min0+max0)/2, 0xff - (min0+max0)/2) / MIN ((min1+max1)/2, 0xff - (min1+max1)/2); | ||
1242 | 549 | double q = (min0 + max0 - (min1 + max1) * p) / 2.0; | ||
1243 | 550 | |||
1244 | 551 | rgb1[0] = (guchar)(rgb1[0] * p + q); | ||
1245 | 552 | rgb1[1] = (guchar)(rgb1[1] * p + q); | ||
1246 | 553 | rgb1[2] = (guchar)(rgb1[2] * p + q); | ||
1247 | 554 | } | ||
1248 | 555 | |||
1249 | 556 | void | ||
1250 | 557 | composite (gchar *pixbuf_pixels, int rowstride, gchar *tile_pixels, int ox, int oy, int tw, int th, guint32 layer_mode) | ||
1251 | 558 | { | ||
1252 | 559 | composite_func f = NULL; | ||
1253 | 560 | int origin = 4 * ox + rowstride * oy; | ||
1254 | 561 | int i, j; | ||
1255 | 562 | |||
1256 | 563 | switch (layer_mode) { | ||
1257 | 564 | case LAYERMODE_NORMAL: | ||
1258 | 565 | for (j=0;j<th;j++) | ||
1259 | 566 | for (i=0;i<tw;i++) { | ||
1260 | 567 | //a0 = 1 - (1-a0)*(a-a1) | ||
1261 | 568 | //rgb0 = BLEND (rgba0, rgba1) | ||
1262 | 569 | gchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i; | ||
1263 | 570 | gchar *src = tile_pixels + j*tw*4 + i*4; | ||
1264 | 571 | guchar alpha = 0xff - (0xff - dest[3]) * (0xff - src [3]); | ||
1265 | 572 | blend (dest, src); | ||
1266 | 573 | dest[3] = alpha; | ||
1267 | 574 | } | ||
1268 | 575 | break; | ||
1269 | 576 | case LAYERMODE_DISSOLVE: | ||
1270 | 577 | srand(time(0)); | ||
1271 | 578 | for (j=0;j<th;j++) | ||
1272 | 579 | for (i=0;i<tw;i++) { | ||
1273 | 580 | guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i; | ||
1274 | 581 | guchar *src = tile_pixels + j*tw*4 + i*4; | ||
1275 | 582 | guchar d = rand () % 0x100; | ||
1276 | 583 | dest [0] = d <= src[3] ? src[0] : dest[0]; | ||
1277 | 584 | dest [1] = d <= src[3] ? src[1] : dest[1]; | ||
1278 | 585 | dest [2] = d <= src[3] ? src[2] : dest[2]; | ||
1279 | 586 | dest [3] = d <= src[3] ? 0xff : dest[3]; | ||
1280 | 587 | } | ||
1281 | 588 | break; | ||
1282 | 589 | case LAYERMODE_BEHIND: //ignore | ||
1283 | 590 | break; | ||
1284 | 591 | // 3<=mode<=10 || 15<=mode<=21 | ||
1285 | 592 | // a0 = a0 | ||
1286 | 593 | // rgba0 = blend (rgba0, F(rgb0, rgb1), MIN(a0, a1) | ||
1287 | 594 | case LAYERMODE_MULTIPLY: | ||
1288 | 595 | f = multiply; | ||
1289 | 596 | for (j=0;j<th;j++) | ||
1290 | 597 | for (i=0;i<tw;i++) { | ||
1291 | 598 | guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i; | ||
1292 | 599 | guchar *src = tile_pixels + j*tw*4 + i*4; | ||
1293 | 600 | f (dest, src); | ||
1294 | 601 | src[3] = MIN (dest[3], src[3]); | ||
1295 | 602 | blend (dest, src); | ||
1296 | 603 | } | ||
1297 | 604 | break; | ||
1298 | 605 | case LAYERMODE_SCREEN: | ||
1299 | 606 | f = screen; | ||
1300 | 607 | for (j=0;j<th;j++) | ||
1301 | 608 | for (i=0;i<tw;i++) { | ||
1302 | 609 | guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i; | ||
1303 | 610 | guchar *src = tile_pixels + j*tw*4 + i*4; | ||
1304 | 611 | f (dest, src); | ||
1305 | 612 | src[3] = MIN (dest[3], src[3]); | ||
1306 | 613 | blend (dest, src); | ||
1307 | 614 | } | ||
1308 | 615 | break; | ||
1309 | 616 | case LAYERMODE_OVERLAY: | ||
1310 | 617 | f = overlay; | ||
1311 | 618 | for (j=0;j<th;j++) | ||
1312 | 619 | for (i=0;i<tw;i++) { | ||
1313 | 620 | guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i; | ||
1314 | 621 | guchar *src = tile_pixels + j*tw*4 + i*4; | ||
1315 | 622 | f (dest, src); | ||
1316 | 623 | src[3] = MIN (dest[3], src[3]); | ||
1317 | 624 | blend (dest, src); | ||
1318 | 625 | } | ||
1319 | 626 | break; | ||
1320 | 627 | case LAYERMODE_SOFTLIGHT: | ||
1321 | 628 | f = softlight; | ||
1322 | 629 | for (j=0;j<th;j++) | ||
1323 | 630 | for (i=0;i<tw;i++) { | ||
1324 | 631 | guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i; | ||
1325 | 632 | guchar *src = tile_pixels + j*tw*4 + i*4; | ||
1326 | 633 | f (dest, src); | ||
1327 | 634 | src[3] = MIN (dest[3], src[3]); | ||
1328 | 635 | blend (dest, src); | ||
1329 | 636 | } | ||
1330 | 637 | break; | ||
1331 | 638 | case LAYERMODE_DIFFERENCE: | ||
1332 | 639 | f = difference; | ||
1333 | 640 | for (j=0;j<th;j++) | ||
1334 | 641 | for (i=0;i<tw;i++) { | ||
1335 | 642 | guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i; | ||
1336 | 643 | guchar *src = tile_pixels + j*tw*4 + i*4; | ||
1337 | 644 | f (dest, src); | ||
1338 | 645 | src[3] = MIN (dest[3], src[3]); | ||
1339 | 646 | blend (dest, src); | ||
1340 | 647 | } | ||
1341 | 648 | break; | ||
1342 | 649 | case LAYERMODE_ADDITION: | ||
1343 | 650 | f = addition; | ||
1344 | 651 | for (j=0;j<th;j++) | ||
1345 | 652 | for (i=0;i<tw;i++) { | ||
1346 | 653 | guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i; | ||
1347 | 654 | guchar *src = tile_pixels + j*tw*4 + i*4; | ||
1348 | 655 | f (dest, src); | ||
1349 | 656 | src[3] = MIN (dest[3], src[3]); | ||
1350 | 657 | blend (dest, src); | ||
1351 | 658 | } | ||
1352 | 659 | break; | ||
1353 | 660 | case LAYERMODE_SUBTRACT: | ||
1354 | 661 | f = subtract; | ||
1355 | 662 | for (j=0;j<th;j++) | ||
1356 | 663 | for (i=0;i<tw;i++) { | ||
1357 | 664 | guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i; | ||
1358 | 665 | guchar *src = tile_pixels + j*tw*4 + i*4; | ||
1359 | 666 | f (dest, src); | ||
1360 | 667 | src[3] = MIN (dest[3], src[3]); | ||
1361 | 668 | blend (dest, src); | ||
1362 | 669 | } | ||
1363 | 670 | break; | ||
1364 | 671 | case LAYERMODE_DARKENONLY: | ||
1365 | 672 | f = min; | ||
1366 | 673 | for (j=0;j<th;j++) | ||
1367 | 674 | for (i=0;i<tw;i++) { | ||
1368 | 675 | guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i; | ||
1369 | 676 | guchar *src = tile_pixels + j*tw*4 + i*4; | ||
1370 | 677 | f (dest, src); | ||
1371 | 678 | src[3] = MIN (dest[3], src[3]); | ||
1372 | 679 | blend (dest, src); | ||
1373 | 680 | } | ||
1374 | 681 | break; | ||
1375 | 682 | case LAYERMODE_LIGHTENONLY: | ||
1376 | 683 | f = max; | ||
1377 | 684 | for (j=0;j<th;j++) | ||
1378 | 685 | for (i=0;i<tw;i++) { | ||
1379 | 686 | guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i; | ||
1380 | 687 | guchar *src = tile_pixels + j*tw*4 + i*4; | ||
1381 | 688 | f (dest, src); | ||
1382 | 689 | src[3] = MIN (dest[3], src[3]); | ||
1383 | 690 | blend (dest, src); | ||
1384 | 691 | } | ||
1385 | 692 | break; | ||
1386 | 693 | case LAYERMODE_DIVIDE: | ||
1387 | 694 | f = divide; | ||
1388 | 695 | for (j=0;j<th;j++) | ||
1389 | 696 | for (i=0;i<tw;i++) { | ||
1390 | 697 | guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i; | ||
1391 | 698 | guchar *src = tile_pixels + j*tw*4 + i*4; | ||
1392 | 699 | f (dest, src); | ||
1393 | 700 | src[3] = MIN (dest[3], src[3]); | ||
1394 | 701 | blend (dest, src); | ||
1395 | 702 | } | ||
1396 | 703 | break; | ||
1397 | 704 | case LAYERMODE_DODGE: | ||
1398 | 705 | f = dodge; | ||
1399 | 706 | for (j=0;j<th;j++) | ||
1400 | 707 | for (i=0;i<tw;i++) { | ||
1401 | 708 | guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i; | ||
1402 | 709 | guchar *src = tile_pixels + j*tw*4 + i*4; | ||
1403 | 710 | f (dest, src); | ||
1404 | 711 | src[3] = MIN (dest[3], src[3]); | ||
1405 | 712 | blend (dest, src); | ||
1406 | 713 | } | ||
1407 | 714 | break; | ||
1408 | 715 | case LAYERMODE_BURN: | ||
1409 | 716 | f = burn; | ||
1410 | 717 | for (j=0;j<th;j++) | ||
1411 | 718 | for (i=0;i<tw;i++) { | ||
1412 | 719 | guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i; | ||
1413 | 720 | guchar *src = tile_pixels + j*tw*4 + i*4; | ||
1414 | 721 | f (dest, src); | ||
1415 | 722 | src[3] = MIN (dest[3], src[3]); | ||
1416 | 723 | blend (dest, src); | ||
1417 | 724 | } | ||
1418 | 725 | break; | ||
1419 | 726 | case LAYERMODE_HARDLIGHT: | ||
1420 | 727 | f = hardlight; | ||
1421 | 728 | for (j=0;j<th;j++) | ||
1422 | 729 | for (i=0;i<tw;i++) { | ||
1423 | 730 | guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i; | ||
1424 | 731 | guchar *src = tile_pixels + j*tw*4 + i*4; | ||
1425 | 732 | f (dest, src); | ||
1426 | 733 | src[3] = MIN (dest[3], src[3]); | ||
1427 | 734 | blend (dest, src); | ||
1428 | 735 | } | ||
1429 | 736 | break; | ||
1430 | 737 | case LAYERMODE_GRAINEXTRACT: | ||
1431 | 738 | f = grainextract; | ||
1432 | 739 | for (j=0;j<th;j++) | ||
1433 | 740 | for (i=0;i<tw;i++) { | ||
1434 | 741 | guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i; | ||
1435 | 742 | guchar *src = tile_pixels + j*tw*4 + i*4; | ||
1436 | 743 | f (dest, src); | ||
1437 | 744 | src[3] = MIN (dest[3], src[3]); | ||
1438 | 745 | blend (dest, src); | ||
1439 | 746 | } | ||
1440 | 747 | break; | ||
1441 | 748 | case LAYERMODE_GRAINMERGE: | ||
1442 | 749 | f = grainmerge; | ||
1443 | 750 | for (j=0;j<th;j++) | ||
1444 | 751 | for (i=0;i<tw;i++) { | ||
1445 | 752 | guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i; | ||
1446 | 753 | guchar *src = tile_pixels + j*tw*4 + i*4; | ||
1447 | 754 | f (dest, src); | ||
1448 | 755 | src[3] = MIN (dest[3], src[3]); | ||
1449 | 756 | blend (dest, src); | ||
1450 | 757 | } | ||
1451 | 758 | break; | ||
1452 | 759 | case LAYERMODE_HUE: | ||
1453 | 760 | f = hue; | ||
1454 | 761 | for (j=0;j<th;j++) | ||
1455 | 762 | for (i=0;i<tw;i++) { | ||
1456 | 763 | guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i; | ||
1457 | 764 | guchar *src = tile_pixels + j*tw*4 + i*4; | ||
1458 | 765 | f (dest, src); | ||
1459 | 766 | src[3] = MIN (dest[3], src[3]); | ||
1460 | 767 | blend (dest, src); | ||
1461 | 768 | } | ||
1462 | 769 | break; | ||
1463 | 770 | case LAYERMODE_SATURATION: | ||
1464 | 771 | f = saturation; | ||
1465 | 772 | for (j=0;j<th;j++) | ||
1466 | 773 | for (i=0;i<tw;i++) { | ||
1467 | 774 | guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i; | ||
1468 | 775 | guchar *src = tile_pixels + j*tw*4 + i*4; | ||
1469 | 776 | f (dest, src); | ||
1470 | 777 | src[3] = MIN (dest[3], src[3]); | ||
1471 | 778 | blend (dest, src); | ||
1472 | 779 | } | ||
1473 | 780 | break; | ||
1474 | 781 | case LAYERMODE_VALUE: | ||
1475 | 782 | f = value; | ||
1476 | 783 | for (j=0;j<th;j++) | ||
1477 | 784 | for (i=0;i<tw;i++) { | ||
1478 | 785 | guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i; | ||
1479 | 786 | guchar *src = tile_pixels + j*tw*4 + i*4; | ||
1480 | 787 | f (dest, src); | ||
1481 | 788 | src[3] = MIN (dest[3], src[3]); | ||
1482 | 789 | blend (dest, src); | ||
1483 | 790 | } | ||
1484 | 791 | break; | ||
1485 | 792 | case LAYERMODE_COLOR: | ||
1486 | 793 | f = color; | ||
1487 | 794 | for (j=0;j<th;j++) | ||
1488 | 795 | for (i=0;i<tw;i++) { | ||
1489 | 796 | guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i; | ||
1490 | 797 | guchar *src = tile_pixels + j*tw*4 + i*4; | ||
1491 | 798 | f (dest, src); | ||
1492 | 799 | src[3] = MIN (dest[3], src[3]); | ||
1493 | 800 | blend (dest, src); | ||
1494 | 801 | } | ||
1495 | 802 | break; | ||
1496 | 803 | |||
1497 | 804 | default: //Pack layer on top of each other, without any blending at all | ||
1498 | 805 | for (j=0; j<th;j++) { | ||
1499 | 806 | memcpy (pixbuf_pixels + origin + j * rowstride, tile_pixels + j*tw*4 , tw*4); | ||
1500 | 807 | } | ||
1501 | 808 | break; | ||
1502 | 809 | } | ||
1503 | 810 | |||
1504 | 811 | } | ||
1505 | 812 | |||
1506 | 813 | static GdkPixbuf* | ||
1507 | 814 | xcf_image_load_real (FILE *f, XcfContext *context, GError **error) | ||
1508 | 815 | { | ||
1509 | 816 | guint32 width; | ||
1510 | 817 | guint32 height; | ||
1511 | 818 | guint32 color_mode; | ||
1512 | 819 | gchar compression = 0; | ||
1513 | 820 | GList *layers = NULL; | ||
1514 | 821 | GdkPixbuf *pixbuf = NULL; | ||
1515 | 822 | |||
1516 | 823 | guchar buffer[32]; | ||
1517 | 824 | guint32 data[3]; | ||
1518 | 825 | guint32 property[2]; | ||
1519 | 826 | size_t lfr; | ||
1520 | 827 | |||
1521 | 828 | //Magic and version | ||
1522 | 829 | lfr = fread (buffer, sizeof(guchar), 9, f); | ||
1523 | 830 | //LOG ("%s\n", buffer); | ||
1524 | 831 | if (strncmp (buffer, "gimp xcf ", 9)) { | ||
1525 | 832 | g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE, "Wrong magic"); | ||
1526 | 833 | return NULL; | ||
1527 | 834 | } | ||
1528 | 835 | |||
1529 | 836 | lfr = fread (buffer, sizeof(guchar), 4, f); | ||
1530 | 837 | if (strncmp (buffer, "file", 4) && strncmp (buffer, "v001", 4) && strncmp (buffer, "v002", 4)) { | ||
1531 | 838 | g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_UNKNOWN_TYPE, "Unsupported version"); | ||
1532 | 839 | return NULL; | ||
1533 | 840 | } | ||
1534 | 841 | lfr = fread (buffer, sizeof(guchar), 1, f); | ||
1535 | 842 | |||
1536 | 843 | //Canvas size and Color mode | ||
1537 | 844 | lfr = fread (data, sizeof(guint32), 3, f); | ||
1538 | 845 | |||
1539 | 846 | width = GUINT32_FROM_BE(data[0]); | ||
1540 | 847 | height = GUINT32_FROM_BE(data[1]); | ||
1541 | 848 | color_mode = GUINT32_FROM_BE(data[2]); | ||
1542 | 849 | if (color_mode == 2) { //Indexed, not supported for now | ||
1543 | 850 | g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_UNKNOWN_TYPE, "Indexed color mode unsupported"); | ||
1544 | 851 | return NULL; | ||
1545 | 852 | } | ||
1546 | 853 | |||
1547 | 854 | |||
1548 | 855 | LOG ("W: %d, H: %d, mode: %d\n", width, height, color_mode); | ||
1549 | 856 | |||
1550 | 857 | //Image Properties | ||
1551 | 858 | while (1) { | ||
1552 | 859 | lfr = fread (property, sizeof(guint32), 2, f); //read property and payload | ||
1553 | 860 | if (!property[0]) | ||
1554 | 861 | break; | ||
1555 | 862 | property[0] = GUINT32_FROM_BE(property[0]); | ||
1556 | 863 | property[1] = GUINT32_FROM_BE(property[1]); | ||
1557 | 864 | //LOG ("property %d, payload %d\n", property[0], property[1]); | ||
1558 | 865 | switch (property[0]) { | ||
1559 | 866 | case PROP_COMPRESSION: | ||
1560 | 867 | lfr = fread (&compression, sizeof(gchar), 1, f); | ||
1561 | 868 | LOG ("compression: %d\n", compression); | ||
1562 | 869 | break; | ||
1563 | 870 | case PROP_COLORMAP: //essential, need to parse this | ||
1564 | 871 | case PROP_END: | ||
1565 | 872 | default: | ||
1566 | 873 | //skip the payload | ||
1567 | 874 | fseek (f, property[1], SEEK_CUR); | ||
1568 | 875 | break; | ||
1569 | 876 | } | ||
1570 | 877 | } | ||
1571 | 878 | |||
1572 | 879 | //Layer Pointer | ||
1573 | 880 | guint32 layer_ptr; | ||
1574 | 881 | while (1) { | ||
1575 | 882 | lfr = fread (&layer_ptr, sizeof(guint32), 1, f); | ||
1576 | 883 | layer_ptr = GUINT32_FROM_BE (layer_ptr); | ||
1577 | 884 | if (!layer_ptr) | ||
1578 | 885 | break;; | ||
1579 | 886 | |||
1580 | 887 | XcfLayer *layer = g_try_new (XcfLayer, 1); | ||
1581 | 888 | if (!layer) { | ||
1582 | 889 | g_set_error (error, | ||
1583 | 890 | GDK_PIXBUF_ERROR, | ||
1584 | 891 | GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, | ||
1585 | 892 | "Cannot allocate memory for loading XCF image"); | ||
1586 | 893 | return NULL; | ||
1587 | 894 | } | ||
1588 | 895 | |||
1589 | 896 | gboolean ignore_layer = FALSE; | ||
1590 | 897 | |||
1591 | 898 | layer->mode = 0; | ||
1592 | 899 | layer->apply_mask = FALSE; | ||
1593 | 900 | layer->layer_mask = NULL; | ||
1594 | 901 | layer->dx = layer->dy = 0; | ||
1595 | 902 | layer->visible = TRUE; | ||
1596 | 903 | layer->opacity = 0xff; | ||
1597 | 904 | |||
1598 | 905 | //LOG ("layer_ptr: %d\n", layer_ptr); | ||
1599 | 906 | long pos = ftell (f); | ||
1600 | 907 | //jump to the layer | ||
1601 | 908 | fseek(f, layer_ptr, SEEK_SET); | ||
1602 | 909 | |||
1603 | 910 | //layer width, height, type | ||
1604 | 911 | lfr = fread (data, sizeof(guint32), 3, f); | ||
1605 | 912 | layer->width = GUINT32_FROM_BE(data[0]); | ||
1606 | 913 | layer->height = GUINT32_FROM_BE(data[1]); | ||
1607 | 914 | layer->type = GUINT32_FROM_BE(data[2]); | ||
1608 | 915 | LOG("\tLayer w:%d h:%d type:%d\n", layer->width, layer->height, layer->type); | ||
1609 | 916 | |||
1610 | 917 | //Layer name, ignore | ||
1611 | 918 | guint32 string_size; | ||
1612 | 919 | lfr = fread (&string_size, sizeof(guint32), 1, f); | ||
1613 | 920 | fseek (f, GUINT32_FROM_BE(string_size), SEEK_CUR); | ||
1614 | 921 | |||
1615 | 922 | //Layer properties | ||
1616 | 923 | while (1) { | ||
1617 | 924 | lfr = fread (property, sizeof(guint32), 2, f); //property and payload | ||
1618 | 925 | if (!property[0]) | ||
1619 | 926 | break; //break on PROP_END | ||
1620 | 927 | property[0] = GUINT32_FROM_BE (property[0]); | ||
1621 | 928 | property[1] = GUINT32_FROM_BE (property[1]); | ||
1622 | 929 | //LOG ("\tproperty %d, payload %d\n", property[0], property[1]); | ||
1623 | 930 | switch (property[0]) { | ||
1624 | 931 | case PROP_OPACITY: | ||
1625 | 932 | lfr = fread (data, sizeof(guint32), 1, f); | ||
1626 | 933 | layer->opacity = GUINT32_FROM_BE(data[0]); | ||
1627 | 934 | break; | ||
1628 | 935 | case PROP_MODE: | ||
1629 | 936 | lfr = fread (data, sizeof(guint32), 1, f); | ||
1630 | 937 | layer->mode = GUINT32_FROM_BE (data[0]); | ||
1631 | 938 | break; | ||
1632 | 939 | case PROP_VISIBLE: | ||
1633 | 940 | lfr = fread (data, sizeof(guint32), 1, f); | ||
1634 | 941 | if (GUINT32_FROM_BE(data[0]) == 0) { | ||
1635 | 942 | layer->visible = FALSE; | ||
1636 | 943 | ignore_layer = TRUE; | ||
1637 | 944 | } | ||
1638 | 945 | break; | ||
1639 | 946 | case PROP_APPLY_MASK: | ||
1640 | 947 | lfr = fread (data, sizeof(guint32), 1, f); | ||
1641 | 948 | if (GUINT32_FROM_BE(data[0]) == 1) | ||
1642 | 949 | layer->apply_mask = TRUE; | ||
1643 | 950 | break; | ||
1644 | 951 | case PROP_OFFSETS: | ||
1645 | 952 | lfr = fread(data, sizeof(gint32), 2, f); | ||
1646 | 953 | layer->dx = GUINT32_FROM_BE(data[0]); | ||
1647 | 954 | layer->dy = GUINT32_FROM_BE(data[1]); | ||
1648 | 955 | break; | ||
1649 | 956 | case PROP_FLOATING_SELECTION: | ||
1650 | 957 | ignore_layer = TRUE; | ||
1651 | 958 | default: | ||
1652 | 959 | //skip the payload | ||
1653 | 960 | fseek (f, property[1], SEEK_CUR); | ||
1654 | 961 | break; | ||
1655 | 962 | } | ||
1656 | 963 | } | ||
1657 | 964 | |||
1658 | 965 | //Hierararchy Pointer | ||
1659 | 966 | guint32 hptr; | ||
1660 | 967 | lfr = fread (&hptr, sizeof(guint32), 1, f); | ||
1661 | 968 | hptr = GUINT32_FROM_BE (hptr); | ||
1662 | 969 | long pos1 = ftell (f); | ||
1663 | 970 | //jump to hierarchy | ||
1664 | 971 | fseek (f, hptr, SEEK_SET); | ||
1665 | 972 | |||
1666 | 973 | //Hierarchy w, h, bpp | ||
1667 | 974 | lfr = fread (data, sizeof(guint32), 3, f); | ||
1668 | 975 | data[0] = GUINT32_FROM_BE(data[0]); | ||
1669 | 976 | data[1] = GUINT32_FROM_BE(data[1]); | ||
1670 | 977 | data[2] = GUINT32_FROM_BE(data[2]); | ||
1671 | 978 | //LOG ("\tHierarchy w:%d, h:%d, bpp:%d\n", data[0], data[1], data[2]); | ||
1672 | 979 | |||
1673 | 980 | guint32 lptr; | ||
1674 | 981 | lfr = fread (&lptr, sizeof(guint32), 1, f); | ||
1675 | 982 | layer->lptr = GUINT32_FROM_BE (lptr); | ||
1676 | 983 | //Layer parsing is done at rendering time | ||
1677 | 984 | |||
1678 | 985 | //Here I could iterate over the unused dlevels and skip them | ||
1679 | 986 | |||
1680 | 987 | //rewind to the layer position | ||
1681 | 988 | fseek (f, pos1, SEEK_SET); | ||
1682 | 989 | |||
1683 | 990 | //Mask Pointer | ||
1684 | 991 | guint32 mptr; | ||
1685 | 992 | lfr = fread (&mptr, sizeof(guint32), 1, f); | ||
1686 | 993 | if (mptr) | ||
1687 | 994 | mptr = GUINT32_FROM_BE(mptr); | ||
1688 | 995 | |||
1689 | 996 | //rewind to the previous position | ||
1690 | 997 | fseek (f, pos, SEEK_SET); | ||
1691 | 998 | |||
1692 | 999 | |||
1693 | 1000 | if (!ignore_layer) | ||
1694 | 1001 | layers = g_list_prepend (layers, layer); //prepend so the layers are in a bottom-up order in the list | ||
1695 | 1002 | else { | ||
1696 | 1003 | g_free (layer); | ||
1697 | 1004 | continue; | ||
1698 | 1005 | } | ||
1699 | 1006 | |||
1700 | 1007 | if (!layer->apply_mask || !mptr) | ||
1701 | 1008 | continue; | ||
1702 | 1009 | |||
1703 | 1010 | LOG ("\t\tthis layer has a mask\n"); | ||
1704 | 1011 | XcfChannel *mask = g_try_new (XcfChannel, 1); | ||
1705 | 1012 | if (!mask) { | ||
1706 | 1013 | g_set_error (error, | ||
1707 | 1014 | GDK_PIXBUF_ERROR, | ||
1708 | 1015 | GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, | ||
1709 | 1016 | "Cannot allocate memory for loading XCF image"); | ||
1710 | 1017 | return NULL; | ||
1711 | 1018 | } | ||
1712 | 1019 | |||
1713 | 1020 | mask->opacity = 0xff; | ||
1714 | 1021 | mask->visible = TRUE; | ||
1715 | 1022 | |||
1716 | 1023 | //LOG ("\t\tchannel_ptr: %d\n", mptr); | ||
1717 | 1024 | long mpos = ftell (f); | ||
1718 | 1025 | //jump to the channel | ||
1719 | 1026 | fseek(f, mptr, SEEK_SET); | ||
1720 | 1027 | |||
1721 | 1028 | //Channel w, h | ||
1722 | 1029 | lfr = fread (data, sizeof(guint32), 2, f); | ||
1723 | 1030 | data[0] = GUINT32_FROM_BE(data[0]); | ||
1724 | 1031 | data[1] = GUINT32_FROM_BE(data[1]); | ||
1725 | 1032 | LOG ("\t\tChannel w:%d, h:%d\n", data[0], data[1]); | ||
1726 | 1033 | |||
1727 | 1034 | //Channel name, ignore | ||
1728 | 1035 | lfr = fread (&string_size, sizeof(guint32), 1, f); | ||
1729 | 1036 | fseek (f, GUINT32_FROM_BE(string_size), SEEK_CUR); | ||
1730 | 1037 | |||
1731 | 1038 | //Channel properties | ||
1732 | 1039 | while (1) { | ||
1733 | 1040 | lfr = fread (property, sizeof(guint32), 2, f); //property and payload | ||
1734 | 1041 | if (!property[0]) | ||
1735 | 1042 | break; //break on PROP_END | ||
1736 | 1043 | property[0] = GUINT32_FROM_BE (property[0]); | ||
1737 | 1044 | property[1] = GUINT32_FROM_BE (property[1]); | ||
1738 | 1045 | //LOG ("\tproperty %d, payload %d\n", property[0], property[1]); | ||
1739 | 1046 | switch (property[0]) { | ||
1740 | 1047 | case PROP_OPACITY: | ||
1741 | 1048 | lfr = fread (data, sizeof(guint32), 1, f); | ||
1742 | 1049 | mask->opacity = GUINT32_FROM_BE(data[0]); | ||
1743 | 1050 | break; | ||
1744 | 1051 | case PROP_VISIBLE: | ||
1745 | 1052 | lfr = fread (data, sizeof(guint32), 1, f); | ||
1746 | 1053 | if (GUINT32_FROM_BE(data[0]) == 0) | ||
1747 | 1054 | mask->visible = FALSE; | ||
1748 | 1055 | break; | ||
1749 | 1056 | default: | ||
1750 | 1057 | //skip the payload | ||
1751 | 1058 | fseek (f, property[1], SEEK_CUR); | ||
1752 | 1059 | break; | ||
1753 | 1060 | } | ||
1754 | 1061 | } | ||
1755 | 1062 | |||
1756 | 1063 | //Hierararchy Pointer | ||
1757 | 1064 | lfr = fread (&hptr, sizeof(guint32), 1, f); | ||
1758 | 1065 | hptr = GUINT32_FROM_BE (hptr); | ||
1759 | 1066 | long mpos1 = ftell (f); | ||
1760 | 1067 | //jump to hierarchy | ||
1761 | 1068 | fseek (f, hptr, SEEK_SET); | ||
1762 | 1069 | |||
1763 | 1070 | //Hierarchy w, h, bpp | ||
1764 | 1071 | lfr = fread (data, sizeof(guint32), 3, f); | ||
1765 | 1072 | data[0] = GUINT32_FROM_BE(data[0]); | ||
1766 | 1073 | data[1] = GUINT32_FROM_BE(data[1]); | ||
1767 | 1074 | data[2] = GUINT32_FROM_BE(data[2]); | ||
1768 | 1075 | //LOG ("\tHierarchy w:%d, h:%d, bpp:%d\n", data[0], data[1], data[2]); | ||
1769 | 1076 | |||
1770 | 1077 | lfr = fread (&lptr, sizeof(guint32), 1, f); | ||
1771 | 1078 | mask->lptr = GUINT32_FROM_BE (lptr); | ||
1772 | 1079 | //level parsing is done at render time | ||
1773 | 1080 | |||
1774 | 1081 | if (mask->visible) | ||
1775 | 1082 | layer->layer_mask = mask; | ||
1776 | 1083 | else | ||
1777 | 1084 | g_free (mask); | ||
1778 | 1085 | |||
1779 | 1086 | //rewind... | ||
1780 | 1087 | fseek (f, mpos1, SEEK_SET); | ||
1781 | 1088 | |||
1782 | 1089 | //rewind to the previous position | ||
1783 | 1090 | fseek (f, mpos, SEEK_SET); | ||
1784 | 1091 | } | ||
1785 | 1092 | |||
1786 | 1093 | //Channels goes here, don't read | ||
1787 | 1094 | |||
1788 | 1095 | LOG("Done parsing\n"); | ||
1789 | 1096 | |||
1790 | 1097 | //Compose the pixbuf | ||
1791 | 1098 | pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height); | ||
1792 | 1099 | LOG ("pixbuf %d %d\n", gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf)); | ||
1793 | 1100 | LOG ("PrepareFunc\n"); | ||
1794 | 1101 | if (context && context->prepare_func) | ||
1795 | 1102 | (* context->prepare_func) (pixbuf, NULL, context->user_data); | ||
1796 | 1103 | |||
1797 | 1104 | if (!pixbuf) | ||
1798 | 1105 | g_set_error (error, | ||
1799 | 1106 | GDK_PIXBUF_ERROR, | ||
1800 | 1107 | GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, | ||
1801 | 1108 | "Cannot allocate memory for loading XCF image"); | ||
1802 | 1109 | |||
1803 | 1110 | gdk_pixbuf_fill (pixbuf, 0x00000000); | ||
1804 | 1111 | |||
1805 | 1112 | GList *current; | ||
1806 | 1113 | gchar pixels[16384]; | ||
1807 | 1114 | for (current = g_list_first (layers); current; current = g_list_next(current)) { | ||
1808 | 1115 | XcfLayer *layer = current->data; | ||
1809 | 1116 | if (!layer->visible) | ||
1810 | 1117 | continue; | ||
1811 | 1118 | |||
1812 | 1119 | fseek (f, layer->lptr, SEEK_SET); | ||
1813 | 1120 | //Ignore Level w and h (same as hierarchy) | ||
1814 | 1121 | fseek (f, 2 * sizeof(guint32), SEEK_CUR); | ||
1815 | 1122 | |||
1816 | 1123 | |||
1817 | 1124 | //Iterate on the tiles | ||
1818 | 1125 | guint32 tptr; | ||
1819 | 1126 | int tile_id = 0; | ||
1820 | 1127 | guchar *pixs = gdk_pixbuf_get_pixels (pixbuf); | ||
1821 | 1128 | int rowstride = gdk_pixbuf_get_rowstride (pixbuf); | ||
1822 | 1129 | int line_width = ceil ((layer->width) / 64.0); | ||
1823 | 1130 | |||
1824 | 1131 | while (1) { | ||
1825 | 1132 | lfr = fread (&tptr, sizeof(guint32), 1, f); | ||
1826 | 1133 | if (!tptr) | ||
1827 | 1134 | break; | ||
1828 | 1135 | tptr = GUINT32_FROM_BE(tptr); | ||
1829 | 1136 | long lpos = ftell (f); | ||
1830 | 1137 | fseek (f, tptr, SEEK_SET); | ||
1831 | 1138 | |||
1832 | 1139 | int ox = 64 * (tile_id % line_width); | ||
1833 | 1140 | int oy = 64 * (tile_id / line_width); | ||
1834 | 1141 | int tw = MIN (64, layer->width - ox); | ||
1835 | 1142 | int th = MIN (64, layer->height - oy); | ||
1836 | 1143 | ox += layer->dx; | ||
1837 | 1144 | oy += layer->dy; | ||
1838 | 1145 | //LOG("\tTile %d %d (%d %d) (%d %d)\n", tile_id, tptr, ox, oy, tw, th); | ||
1839 | 1146 | |||
1840 | 1147 | //if the tile doesn't intersect with the canvas, ignore | ||
1841 | 1148 | if (ox + tw < 0 || oy + th < 0 || ox > (int)width || oy > (int)height ) { | ||
1842 | 1149 | fseek (f, lpos, SEEK_SET); | ||
1843 | 1150 | tile_id++; | ||
1844 | 1151 | continue; | ||
1845 | 1152 | } | ||
1846 | 1153 | |||
1847 | 1154 | //decompress | ||
1848 | 1155 | if (compression == COMPRESSION_RLE) | ||
1849 | 1156 | rle_decode (f, pixels, tw*th, layer->type); | ||
1850 | 1157 | else {//COMPRESSION_NONE | ||
1851 | 1158 | int channels; | ||
1852 | 1159 | switch (layer->type) { | ||
1853 | 1160 | case LAYERTYPE_RGB : channels = 3; break; | ||
1854 | 1161 | case LAYERTYPE_RGBA: channels = 4; break; | ||
1855 | 1162 | case LAYERTYPE_GRAYSCALE: channels = 1; break; | ||
1856 | 1163 | case LAYERTYPE_GRAYSCALEA: channels = 2; break; | ||
1857 | 1164 | case LAYERTYPE_INDEXED: channels = 1; break; | ||
1858 | 1165 | case LAYERTYPE_INDEXEDA: channels = 2; break; | ||
1859 | 1166 | } | ||
1860 | 1167 | lfr = fread (pixels, sizeof(gchar), tw*th*channels, f); | ||
1861 | 1168 | } | ||
1862 | 1169 | |||
1863 | 1170 | //pad to rgba | ||
1864 | 1171 | to_rgba (pixels, tw*th, layer->type); | ||
1865 | 1172 | |||
1866 | 1173 | //apply mask | ||
1867 | 1174 | if (layer->layer_mask) | ||
1868 | 1175 | apply_mask (f, compression, pixels, tw*th, layer->layer_mask, tile_id); | ||
1869 | 1176 | |||
1870 | 1177 | //reduce the tile to its intersection with the canvas | ||
1871 | 1178 | intersect_tile (pixels, width, height, &ox, &oy, &tw, &th); | ||
1872 | 1179 | |||
1873 | 1180 | //apply layer opacity | ||
1874 | 1181 | apply_opacity (pixels, tw*th, layer->opacity); | ||
1875 | 1182 | |||
1876 | 1183 | //composite | ||
1877 | 1184 | composite (pixs, rowstride, pixels, ox, oy, tw, th, layer->mode); | ||
1878 | 1185 | |||
1879 | 1186 | //notify | ||
1880 | 1187 | if (context && context->update_func) | ||
1881 | 1188 | (* context->update_func) (pixbuf, ox, oy, tw, th, context->user_data); | ||
1882 | 1189 | |||
1883 | 1190 | |||
1884 | 1191 | fseek (f, lpos, SEEK_SET); | ||
1885 | 1192 | tile_id++; | ||
1886 | 1193 | } | ||
1887 | 1194 | } | ||
1888 | 1195 | |||
1889 | 1196 | //free the layers and masks | ||
1890 | 1197 | for (current = g_list_first (layers); current; current = g_list_next(current)) { | ||
1891 | 1198 | XcfLayer *layer = current->data; | ||
1892 | 1199 | if (layer->layer_mask) | ||
1893 | 1200 | g_free (layer->layer_mask); | ||
1894 | 1201 | } | ||
1895 | 1202 | g_list_free (layers); | ||
1896 | 1203 | |||
1897 | 1204 | return pixbuf; | ||
1898 | 1205 | } | ||
1899 | 1206 | |||
1900 | 1207 | /* Static Loader */ | ||
1901 | 1208 | |||
1902 | 1209 | static GdkPixbuf* | ||
1903 | 1210 | xcf_image_load (FILE *f, GError **error) | ||
1904 | 1211 | { | ||
1905 | 1212 | size_t lfr; | ||
1906 | 1213 | guchar buffer[4]; | ||
1907 | 1214 | lfr = fread (buffer, sizeof(guchar), 4, f); | ||
1908 | 1215 | rewind (f); | ||
1909 | 1216 | if (!strncmp (buffer, "BZh", 3)) { //Decompress the xcf.bz2 file to a temp file | ||
1910 | 1217 | gchar *tempname; | ||
1911 | 1218 | gint fd = g_file_open_tmp ("gdkpixbuf-xcf-tmp.XXXXXX", &tempname, NULL); | ||
1912 | 1219 | if (fd < 0) { | ||
1913 | 1220 | gint save_errno = errno; | ||
1914 | 1221 | g_set_error (error, | ||
1915 | 1222 | G_FILE_ERROR, | ||
1916 | 1223 | g_file_error_from_errno (save_errno), | ||
1917 | 1224 | "Failed to create temporary file when loading Xcf image"); | ||
1918 | 1225 | return NULL; | ||
1919 | 1226 | } | ||
1920 | 1227 | |||
1921 | 1228 | FILE *file = fdopen (fd, "w+"); | ||
1922 | 1229 | if (!file) { | ||
1923 | 1230 | gint save_errno = errno; | ||
1924 | 1231 | g_set_error (error, | ||
1925 | 1232 | G_FILE_ERROR, | ||
1926 | 1233 | g_file_error_from_errno (save_errno), | ||
1927 | 1234 | "Failed to open temporary file when loading Xcf image"); | ||
1928 | 1235 | g_free (tempname); | ||
1929 | 1236 | return NULL; | ||
1930 | 1237 | } | ||
1931 | 1238 | |||
1932 | 1239 | int bzerror; | ||
1933 | 1240 | BZFILE *b = BZ2_bzReadOpen (&bzerror, f, 0, 0, NULL, 0); | ||
1934 | 1241 | if (bzerror != BZ_OK) { | ||
1935 | 1242 | BZ2_bzReadClose (&bzerror, b); | ||
1936 | 1243 | fclose (file); | ||
1937 | 1244 | g_unlink (tempname); | ||
1938 | 1245 | g_free (tempname); | ||
1939 | 1246 | g_set_error (error, | ||
1940 | 1247 | GDK_PIXBUF_ERROR, | ||
1941 | 1248 | GDK_PIXBUF_ERROR_FAILED, | ||
1942 | 1249 | "Failed to initialize bz2 decompressor"); | ||
1943 | 1250 | return NULL; | ||
1944 | 1251 | } | ||
1945 | 1252 | |||
1946 | 1253 | bzerror = BZ_OK; | ||
1947 | 1254 | gchar buf [65536]; | ||
1948 | 1255 | gint nBuf; | ||
1949 | 1256 | while (bzerror == BZ_OK) { | ||
1950 | 1257 | nBuf = BZ2_bzRead (&bzerror, b, buf, 65536); | ||
1951 | 1258 | if (bzerror == BZ_OK || bzerror == BZ_STREAM_END) | ||
1952 | 1259 | if (fwrite (buf, sizeof (guchar), nBuf, file) != nBuf) { | ||
1953 | 1260 | gint save_errno = errno; | ||
1954 | 1261 | g_set_error (error, | ||
1955 | 1262 | G_FILE_ERROR, | ||
1956 | 1263 | g_file_error_from_errno (save_errno), | ||
1957 | 1264 | "Failed to write to temporary file when loading Xcf image"); | ||
1958 | 1265 | BZ2_bzReadClose (&bzerror, b); | ||
1959 | 1266 | fclose (file); | ||
1960 | 1267 | g_unlink (tempname); | ||
1961 | 1268 | g_free (tempname); | ||
1962 | 1269 | return NULL; | ||
1963 | 1270 | } | ||
1964 | 1271 | } | ||
1965 | 1272 | |||
1966 | 1273 | if (bzerror != BZ_STREAM_END) { | ||
1967 | 1274 | LOG ("bzerror = %d\n", bzerror); | ||
1968 | 1275 | BZ2_bzReadClose (&bzerror, b); | ||
1969 | 1276 | fclose (file); | ||
1970 | 1277 | g_unlink (tempname); | ||
1971 | 1278 | g_free (tempname); | ||
1972 | 1279 | g_set_error (error, | ||
1973 | 1280 | GDK_PIXBUF_ERROR, | ||
1974 | 1281 | GDK_PIXBUF_ERROR_FAILED, | ||
1975 | 1282 | "Decompression error while loading Xcf.bz2 file"); | ||
1976 | 1283 | return NULL; | ||
1977 | 1284 | } else { | ||
1978 | 1285 | LOG ("bzerror = %d\n", bzerror); | ||
1979 | 1286 | BZ2_bzReadClose (&bzerror, b); | ||
1980 | 1287 | } | ||
1981 | 1288 | |||
1982 | 1289 | fflush (file); | ||
1983 | 1290 | rewind (file); | ||
1984 | 1291 | g_unlink (tempname); | ||
1985 | 1292 | g_free (tempname); | ||
1986 | 1293 | |||
1987 | 1294 | GdkPixbuf *pixbuf = xcf_image_load_real (file, NULL, error); | ||
1988 | 1295 | fclose (file); | ||
1989 | 1296 | return pixbuf; | ||
1990 | 1297 | #if GIO_2_23 | ||
1991 | 1298 | } else if (!strncmp (buffer, "\x1f\x8b", 2)) { //Decompress the .gz to a temp file | ||
1992 | 1299 | GZlibDecompressor *compressor; | ||
1993 | 1300 | GInputStream *input, *stream; | ||
1994 | 1301 | |||
1995 | 1302 | compressor = g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP); | ||
1996 | 1303 | input = g_unix_input_stream_new (fileno (f), FALSE); | ||
1997 | 1304 | stream = (GInputStream *) g_converter_input_stream_new (input, (GConverter *) (compressor)); | ||
1998 | 1305 | g_object_unref (compressor); | ||
1999 | 1306 | g_object_unref (input); | ||
2000 | 1307 | |||
2001 | 1308 | gchar *tempname; | ||
2002 | 1309 | gint fd = g_file_open_tmp ("gdkpixbuf-xcf-tmp.XXXXXX", &tempname, NULL); | ||
2003 | 1310 | if (fd < 0) { | ||
2004 | 1311 | gint save_errno = errno; | ||
2005 | 1312 | g_set_error (error, | ||
2006 | 1313 | G_FILE_ERROR, | ||
2007 | 1314 | g_file_error_from_errno (save_errno), | ||
2008 | 1315 | "Failed to create temporary file when loading Xcf image"); | ||
2009 | 1316 | return NULL; | ||
2010 | 1317 | } | ||
2011 | 1318 | GOutputStream *output; | ||
2012 | 1319 | output = g_unix_output_stream_new (fd, TRUE); | ||
2013 | 1320 | if (!g_output_stream_splice (G_OUTPUT_STREAM (output), stream, | ||
2014 | 1321 | G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, | ||
2015 | 1322 | NULL, NULL)) { | ||
2016 | 1323 | LOG ("splicing failed\n"); | ||
2017 | 1324 | g_set_error (error, | ||
2018 | 1325 | GDK_PIXBUF_ERROR, | ||
2019 | 1326 | GDK_PIXBUF_ERROR_FAILED, | ||
2020 | 1327 | "Decompression error while loading Xcf.gz file"); | ||
2021 | 1328 | return NULL; | ||
2022 | 1329 | } | ||
2023 | 1330 | |||
2024 | 1331 | FILE *file; | ||
2025 | 1332 | file = fopen (tempname, "r"); | ||
2026 | 1333 | g_unlink (tempname); | ||
2027 | 1334 | g_free (tempname); | ||
2028 | 1335 | |||
2029 | 1336 | GdkPixbuf *pixbuf = xcf_image_load_real (file, NULL, error); | ||
2030 | 1337 | fclose (file); | ||
2031 | 1338 | |||
2032 | 1339 | return pixbuf; | ||
2033 | 1340 | #endif | ||
2034 | 1341 | } else | ||
2035 | 1342 | return xcf_image_load_real (f, NULL, error); | ||
2036 | 1343 | } | ||
2037 | 1344 | |||
2038 | 1345 | |||
2039 | 1346 | /* Progressive loader */ | ||
2040 | 1347 | |||
2041 | 1348 | /* | ||
2042 | 1349 | * as the layers are packed top down in the xcf format, and we have to render them bottom-up, | ||
2043 | 1350 | * we need the full file loaded to start rendering | ||
2044 | 1351 | */ | ||
2045 | 1352 | |||
2046 | 1353 | static gpointer | ||
2047 | 1354 | xcf_image_begin_load (GdkPixbufModuleSizeFunc size_func, | ||
2048 | 1355 | GdkPixbufModulePreparedFunc prepare_func, | ||
2049 | 1356 | GdkPixbufModuleUpdatedFunc update_func, | ||
2050 | 1357 | gpointer user_data, | ||
2051 | 1358 | GError **error) | ||
2052 | 1359 | { | ||
2053 | 1360 | LOG ("Begin\n"); | ||
2054 | 1361 | XcfContext *context; | ||
2055 | 1362 | gint fd; | ||
2056 | 1363 | |||
2057 | 1364 | context = g_new (XcfContext, 1); | ||
2058 | 1365 | context->size_func = size_func; | ||
2059 | 1366 | context->prepare_func = prepare_func; | ||
2060 | 1367 | context->update_func = update_func; | ||
2061 | 1368 | context->user_data = user_data; | ||
2062 | 1369 | context->type = FILETYPE_UNKNOWN; | ||
2063 | 1370 | context->bz_stream = NULL; | ||
2064 | 1371 | #if GIO_2_23 | ||
2065 | 1372 | context->stream = NULL; | ||
2066 | 1373 | context->input = NULL; | ||
2067 | 1374 | #endif | ||
2068 | 1375 | |||
2069 | 1376 | fd = g_file_open_tmp ("gdkpixbuf-xcf-tmp.XXXXXX", &context->tempname, NULL); | ||
2070 | 1377 | |||
2071 | 1378 | if (fd < 0) { | ||
2072 | 1379 | g_free (context); | ||
2073 | 1380 | return NULL; | ||
2074 | 1381 | } | ||
2075 | 1382 | |||
2076 | 1383 | context->file = fdopen (fd, "w+"); | ||
2077 | 1384 | if (!context->file) { | ||
2078 | 1385 | g_free (context->tempname); | ||
2079 | 1386 | g_free (context); | ||
2080 | 1387 | return NULL; | ||
2081 | 1388 | } | ||
2082 | 1389 | |||
2083 | 1390 | return context; | ||
2084 | 1391 | } | ||
2085 | 1392 | |||
2086 | 1393 | static gboolean | ||
2087 | 1394 | xcf_image_stop_load (gpointer data, GError **error) | ||
2088 | 1395 | { | ||
2089 | 1396 | LOG ("Stop\n"); | ||
2090 | 1397 | XcfContext *context = (XcfContext*) data; | ||
2091 | 1398 | gboolean retval = TRUE; | ||
2092 | 1399 | |||
2093 | 1400 | g_return_val_if_fail (data, TRUE); | ||
2094 | 1401 | |||
2095 | 1402 | if (context->type == FILETYPE_XCF || | ||
2096 | 1403 | context->type == FILETYPE_XCF_BZ2) { | ||
2097 | 1404 | fflush (context->file); | ||
2098 | 1405 | rewind (context->file); | ||
2099 | 1406 | if (context->tempname) { | ||
2100 | 1407 | g_unlink (context->tempname); | ||
2101 | 1408 | g_free (context->tempname); | ||
2102 | 1409 | context->tempname = NULL; | ||
2103 | 1410 | } | ||
2104 | 1411 | GdkPixbuf *pixbuf = xcf_image_load_real (context->file, context, error); | ||
2105 | 1412 | if (!pixbuf) | ||
2106 | 1413 | retval = FALSE; | ||
2107 | 1414 | else | ||
2108 | 1415 | g_object_unref (pixbuf); | ||
2109 | 1416 | #if GIO_2_23 | ||
2110 | 1417 | } else if (context->type == FILETYPE_XCF_GZ) { | ||
2111 | 1418 | g_object_unref (context->input); | ||
2112 | 1419 | context->input = NULL; | ||
2113 | 1420 | |||
2114 | 1421 | gchar buf [65536]; | ||
2115 | 1422 | gsize count; | ||
2116 | 1423 | GError *err = NULL; | ||
2117 | 1424 | while ((count = g_input_stream_read (G_INPUT_STREAM (context->stream), | ||
2118 | 1425 | &buf, sizeof (buf), NULL, error)) > 0) { | ||
2119 | 1426 | if (fwrite (buf, sizeof (gchar), count, context->file) != count) { | ||
2120 | 1427 | gint save_errno = errno; | ||
2121 | 1428 | g_set_error (error, | ||
2122 | 1429 | G_FILE_ERROR, | ||
2123 | 1430 | g_file_error_from_errno (save_errno), | ||
2124 | 1431 | "Failed to write to temporary file when loading Xcf image"); | ||
2125 | 1432 | retval = FALSE; | ||
2126 | 1433 | goto bail; | ||
2127 | 1434 | } | ||
2128 | 1435 | } | ||
2129 | 1436 | if (count == -1) { | ||
2130 | 1437 | /* error is already set */ | ||
2131 | 1438 | retval = FALSE; | ||
2132 | 1439 | goto bail; | ||
2133 | 1440 | } | ||
2134 | 1441 | #endif | ||
2135 | 1442 | } else { | ||
2136 | 1443 | g_assert_not_reached (); | ||
2137 | 1444 | } | ||
2138 | 1445 | |||
2139 | 1446 | fflush (context->file); | ||
2140 | 1447 | rewind (context->file); | ||
2141 | 1448 | if (context->tempname) { | ||
2142 | 1449 | g_unlink (context->tempname); | ||
2143 | 1450 | g_free (context->tempname); | ||
2144 | 1451 | context->tempname = NULL; | ||
2145 | 1452 | } | ||
2146 | 1453 | GdkPixbuf *pixbuf = xcf_image_load_real (context->file, context, error); | ||
2147 | 1454 | if (!pixbuf) | ||
2148 | 1455 | retval = FALSE; | ||
2149 | 1456 | else | ||
2150 | 1457 | g_object_unref (pixbuf); | ||
2151 | 1458 | |||
2152 | 1459 | bail: | ||
2153 | 1460 | #if GIO_2_23 | ||
2154 | 1461 | if (context->stream) | ||
2155 | 1462 | g_object_unref (context->stream); | ||
2156 | 1463 | #endif | ||
2157 | 1464 | fclose (context->file); | ||
2158 | 1465 | if (context->tempname) { | ||
2159 | 1466 | g_unlink (context->tempname); | ||
2160 | 1467 | g_free (context->tempname); | ||
2161 | 1468 | } | ||
2162 | 1469 | g_free (context); | ||
2163 | 1470 | |||
2164 | 1471 | return retval; | ||
2165 | 1472 | } | ||
2166 | 1473 | |||
2167 | 1474 | static gboolean | ||
2168 | 1475 | xcf_image_load_increment (gpointer data, | ||
2169 | 1476 | const guchar *buf, | ||
2170 | 1477 | guint size, | ||
2171 | 1478 | GError **error) | ||
2172 | 1479 | { | ||
2173 | 1480 | LOG ("Increment %d\n", size); | ||
2174 | 1481 | g_return_val_if_fail (data, FALSE); | ||
2175 | 1482 | XcfContext *context = (XcfContext*) data; | ||
2176 | 1483 | |||
2177 | 1484 | if (context->type == FILETYPE_STREAMCLOSED) { //end of compressed stream reached | ||
2178 | 1485 | g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE, "end of compressed stream reached before the end of the file"); | ||
2179 | 1486 | return FALSE; | ||
2180 | 1487 | } | ||
2181 | 1488 | |||
2182 | 1489 | if (context->type == FILETYPE_UNKNOWN) { // first chunk | ||
2183 | 1490 | if (!strncmp (buf, "gimp xcf ", 9)) | ||
2184 | 1491 | context->type = FILETYPE_XCF; | ||
2185 | 1492 | else if (!strncmp (buf, "BZh", 3)) { | ||
2186 | 1493 | context->type = FILETYPE_XCF_BZ2; | ||
2187 | 1494 | |||
2188 | 1495 | //Initialize bzlib | ||
2189 | 1496 | context->bz_stream = g_new (bz_stream, 1); | ||
2190 | 1497 | context->bz_stream->bzalloc = NULL; | ||
2191 | 1498 | context->bz_stream->bzfree = NULL; | ||
2192 | 1499 | context->bz_stream->opaque = NULL; | ||
2193 | 1500 | |||
2194 | 1501 | int ret = BZ2_bzDecompressInit (context->bz_stream, 0, 0); //Verbosity = 0, don't optimize for memory usage | ||
2195 | 1502 | if (ret != BZ_OK) { | ||
2196 | 1503 | g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, "Failed to initialize bz2 decompressor"); | ||
2197 | 1504 | g_free(context->bz_stream); | ||
2198 | 1505 | context->bz_stream = NULL; | ||
2199 | 1506 | return FALSE; | ||
2200 | 1507 | } | ||
2201 | 1508 | #if GIO_2_23 | ||
2202 | 1509 | } else if (!strncmp (buf, "\x1f\x8b", 2)) { | ||
2203 | 1510 | GZlibDecompressor *compressor; | ||
2204 | 1511 | |||
2205 | 1512 | context->type = FILETYPE_XCF_GZ; | ||
2206 | 1513 | compressor = g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP); | ||
2207 | 1514 | |||
2208 | 1515 | context->input = g_memory_input_stream_new (); | ||
2209 | 1516 | context->stream = (GInputStream *) g_converter_input_stream_new (context->input, (GConverter *) (compressor)); | ||
2210 | 1517 | g_object_unref (compressor); | ||
2211 | 1518 | #endif | ||
2212 | 1519 | } | ||
2213 | 1520 | LOG ("File type %d\n", context->type); | ||
2214 | 1521 | } | ||
2215 | 1522 | |||
2216 | 1523 | gchar *outbuf; | ||
2217 | 1524 | switch (context->type) { | ||
2218 | 1525 | case FILETYPE_XCF_BZ2: | ||
2219 | 1526 | outbuf = g_new (gchar, 65536); | ||
2220 | 1527 | context->bz_stream->next_in = (gchar*)buf; | ||
2221 | 1528 | context->bz_stream->avail_in = size; | ||
2222 | 1529 | while (context->bz_stream->avail_in > 0) { | ||
2223 | 1530 | context->bz_stream->next_out = outbuf; | ||
2224 | 1531 | context->bz_stream->avail_out = 65536; | ||
2225 | 1532 | int ret = BZ2_bzDecompress (context->bz_stream); | ||
2226 | 1533 | switch (ret) { | ||
2227 | 1534 | case BZ_OK: | ||
2228 | 1535 | break; | ||
2229 | 1536 | case BZ_STREAM_END: | ||
2230 | 1537 | LOG ("End of bz stream\n"); | ||
2231 | 1538 | BZ2_bzDecompressEnd (context->bz_stream); | ||
2232 | 1539 | context->type = FILETYPE_STREAMCLOSED; | ||
2233 | 1540 | break; | ||
2234 | 1541 | default: | ||
2235 | 1542 | BZ2_bzDecompressEnd (context->bz_stream); | ||
2236 | 1543 | context->type = FILETYPE_STREAMCLOSED; | ||
2237 | 1544 | g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, "Failed to decompress"); | ||
2238 | 1545 | g_free(outbuf); | ||
2239 | 1546 | context->bz_stream->next_out = NULL; | ||
2240 | 1547 | outbuf = NULL; | ||
2241 | 1548 | g_free(context->bz_stream); | ||
2242 | 1549 | context->bz_stream = NULL; | ||
2243 | 1550 | return FALSE; | ||
2244 | 1551 | } | ||
2245 | 1552 | |||
2246 | 1553 | int total_out = 65536 - context->bz_stream->avail_out; | ||
2247 | 1554 | LOG ("Wrote %d to file %s\n", total_out, context->tempname); | ||
2248 | 1555 | if (fwrite (outbuf, sizeof (guchar), total_out, context->file) != total_out) { | ||
2249 | 1556 | gint save_errno = errno; | ||
2250 | 1557 | g_set_error (error, | ||
2251 | 1558 | G_FILE_ERROR, | ||
2252 | 1559 | g_file_error_from_errno (save_errno), | ||
2253 | 1560 | "Failed to write to temporary file when loading Xcf image"); | ||
2254 | 1561 | g_free(outbuf); | ||
2255 | 1562 | context->bz_stream->next_out = NULL; | ||
2256 | 1563 | outbuf = NULL; | ||
2257 | 1564 | g_free(context->bz_stream); | ||
2258 | 1565 | context->bz_stream = NULL; | ||
2259 | 1566 | return FALSE; | ||
2260 | 1567 | } | ||
2261 | 1568 | } | ||
2262 | 1569 | g_free(outbuf); | ||
2263 | 1570 | context->bz_stream->next_out = NULL; | ||
2264 | 1571 | outbuf = NULL; | ||
2265 | 1572 | if (context->type == FILETYPE_STREAMCLOSED) | ||
2266 | 1573 | { | ||
2267 | 1574 | g_free(context->bz_stream); | ||
2268 | 1575 | context->bz_stream = NULL; | ||
2269 | 1576 | } | ||
2270 | 1577 | break; | ||
2271 | 1578 | #if GIO_2_23 | ||
2272 | 1579 | case FILETYPE_XCF_GZ: | ||
2273 | 1580 | g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (context->input), | ||
2274 | 1581 | buf, size, NULL); | ||
2275 | 1582 | break; | ||
2276 | 1583 | #endif | ||
2277 | 1584 | case FILETYPE_XCF: | ||
2278 | 1585 | default: | ||
2279 | 1586 | if (fwrite (buf, sizeof (guchar), size, context->file) != size) { | ||
2280 | 1587 | gint save_errno = errno; | ||
2281 | 1588 | g_set_error (error, | ||
2282 | 1589 | G_FILE_ERROR, | ||
2283 | 1590 | g_file_error_from_errno (save_errno), | ||
2284 | 1591 | "Failed to write to temporary file when loading Xcf image"); | ||
2285 | 1592 | return FALSE; | ||
2286 | 1593 | } | ||
2287 | 1594 | break; | ||
2288 | 1595 | } | ||
2289 | 1596 | |||
2290 | 1597 | return TRUE; | ||
2291 | 1598 | } | ||
2292 | 1599 | |||
2293 | 1600 | |||
2294 | 1601 | #define MODULE_ENTRY(function) G_MODULE_EXPORT void function | ||
2295 | 1602 | MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module) | ||
2296 | 1603 | { | ||
2297 | 1604 | module->load = xcf_image_load; | ||
2298 | 1605 | module->begin_load = xcf_image_begin_load; | ||
2299 | 1606 | module->stop_load = xcf_image_stop_load; | ||
2300 | 1607 | module->load_increment = xcf_image_load_increment; | ||
2301 | 1608 | } | ||
2302 | 1609 | |||
2303 | 1610 | MODULE_ENTRY (fill_info) (GdkPixbufFormat *info) | ||
2304 | 1611 | { | ||
2305 | 1612 | static GdkPixbufModulePattern signature[] = { | ||
2306 | 1613 | { "gimp xcf", NULL, 100 }, | ||
2307 | 1614 | { "BZh", NULL, 80 }, | ||
2308 | 1615 | #if GIO_2_23 | ||
2309 | 1616 | { "\x1f\x8b", NULL, 80 }, | ||
2310 | 1617 | #endif | ||
2311 | 1618 | { NULL, NULL, 0 } | ||
2312 | 1619 | }; | ||
2313 | 1620 | static gchar * mime_types[] = { | ||
2314 | 1621 | "image/x-xcf", | ||
2315 | 1622 | "image/x-compressed-xcf", | ||
2316 | 1623 | NULL | ||
2317 | 1624 | }; | ||
2318 | 1625 | static gchar * extensions[] = { | ||
2319 | 1626 | "xcf", | ||
2320 | 1627 | "xcf.bz2", | ||
2321 | 1628 | #if GIO_2_23 | ||
2322 | 1629 | "xcf.gz", | ||
2323 | 1630 | #endif | ||
2324 | 1631 | NULL | ||
2325 | 1632 | }; | ||
2326 | 1633 | |||
2327 | 1634 | info->name = "xcf"; | ||
2328 | 1635 | info->signature = signature; | ||
2329 | 1636 | info->description = "The XCF (The Gimp) image format"; | ||
2330 | 1637 | info->mime_types = mime_types; | ||
2331 | 1638 | info->extensions = extensions; | ||
2332 | 1639 | info->flags = 0; | ||
2333 | 1640 | info->license = "LGPL"; | ||
2334 | 1641 | } | ||
2335 | 1642 | 0 | ||
2336 | === modified file 'src/plugin-pixbuf/plugin-pixbuf.h' | |||
2337 | --- src/plugin-pixbuf/plugin-pixbuf.h 2010-05-31 14:57:37 +0000 | |||
2338 | +++ src/plugin-pixbuf/plugin-pixbuf.h 2014-12-26 04:45:12 +0000 | |||
2339 | @@ -48,12 +48,6 @@ | |||
2340 | 48 | } | 48 | } |
2341 | 49 | g_slist_free(suportedFormats); | 49 | g_slist_free(suportedFormats); |
2342 | 50 | 50 | ||
2343 | 51 | PluginManager::register_filetype("image/vnd.adobe.photoshop", 1); | ||
2344 | 52 | PluginManager::register_filetype("image/x-xcf", 1); | ||
2345 | 53 | PluginManager::register_filetype("image/x-compressed-xcf", 1); | ||
2346 | 54 | //PluginManager::register_filetype("image/x-icns", 2); | ||
2347 | 55 | //PluginManager::register_filetype("image/jpeg", 1); //TODO: do we need this? | ||
2348 | 56 | |||
2349 | 57 | #endif | 51 | #endif |
2350 | 58 | 52 | ||
2351 | 59 | #endif | 53 | #endif |