Merge lp:~ballogy/gloobus-preview/drop-loaders into lp:gloobus-preview

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
Reviewer Review Type Date Requested Status
Gloobus Developers Pending
Review via email: mp+245375@code.launchpad.net

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
=== modified file 'configure.ac'
--- configure.ac 2014-12-25 16:27:26 +0000
+++ configure.ac 2014-12-26 04:45:12 +0000
@@ -32,12 +32,8 @@
32AC_CHECK_LIB(gthread, g_thread_init)32AC_CHECK_LIB(gthread, g_thread_init)
33AC_CHECK_LIB(pthread, pthread_create)33AC_CHECK_LIB(pthread, pthread_create)
3434
35# To compile XCF loader ==> sudo apt-get install libtool libbz2-dev
36AC_CHECK_LIB(bz2,BZ2_bzDecompressInit,,AC_MSG_ERROR(Can not find libbz2))
37
38# *** checks for headers ***************************************************** #35# *** checks for headers ***************************************************** #
39AC_CHECK_HEADERS([stdlib.h string.h pthread.h])36AC_CHECK_HEADERS([stdlib.h string.h pthread.h])
40AC_CHECK_HEADER(bzlib.h,,AC_MSG_ERROR(Can not find bzlib header)) # To compile XCF loader
4137
42# *** checks for modules ***************************************************** #38# *** checks for modules ***************************************************** #
43PKG_CHECK_MODULES(ATK, atk)39PKG_CHECK_MODULES(ATK, atk)
@@ -57,9 +53,6 @@
57PKG_CHECK_MODULES(DBUS, dbus-glib-1)53PKG_CHECK_MODULES(DBUS, dbus-glib-1)
58PKG_CHECK_MODULES(X11, x11)54PKG_CHECK_MODULES(X11, x11)
5955
60PKG_CHECK_MODULES(GMODULE, gmodule-2.0) # To compile XCF loader
61PKG_CHECK_MODULES(GDKPIXBUF, gdk-pixbuf-2.0) # To compile XCF loader
62
63# Checks for typedefs, structures, and compiler characteristics.56# Checks for typedefs, structures, and compiler characteristics.
64AC_HEADER_STDBOOL57AC_HEADER_STDBOOL
6558
@@ -90,8 +83,6 @@
90 src/plugin-text/Makefile83 src/plugin-text/Makefile
91 src/plugin-ttf/Makefile84 src/plugin-ttf/Makefile
92 src/plugin-xps/Makefile85 src/plugin-xps/Makefile
93 src/loaders/PSD/Makefile
94 src/loaders/XCF/Makefile
95 src/gloobus-sushi/Makefile86 src/gloobus-sushi/Makefile
96 data/Makefile87 data/Makefile
97 data/images/Makefile88 data/images/Makefile
9889
=== modified file 'src/Makefile.am'
--- src/Makefile.am 2014-12-25 16:27:26 +0000
+++ src/Makefile.am 2014-12-26 04:45:12 +0000
@@ -1,7 +1,5 @@
1SUBDIRS = \1SUBDIRS = \
2 gloobus-sushi \2 gloobus-sushi \
3 loaders/PSD \
4 loaders/XCF \
5 plugin-comic \3 plugin-comic \
6 plugin-folder \4 plugin-folder \
7 plugin-compressed \5 plugin-compressed \
86
=== removed directory 'src/loaders'
=== removed directory 'src/loaders/PSD'
=== removed file 'src/loaders/PSD/Makefile.am'
--- src/loaders/PSD/Makefile.am 2010-08-21 18:06:49 +0000
+++ src/loaders/PSD/Makefile.am 1970-01-01 00:00:00 +0000
@@ -1,12 +0,0 @@
1#pluginexecdir = $(prefix)/lib/gtk-2.0/2.10.0/loaders/
2pluginexecdir = $(prefix)/lib/gdk-pixbuf-2.0/2.10.0/loaders/
3
4AM_CPPFLAGS += $(GTK_CFLAGS) -shared -fpic -std=c99 -DGDK_PIXBUF_ENABLE_BACKEND
5AM_LDFLAGS = $(GTK_LIBS)
6
7pluginexec_LTLIBRARIES = libpixbufloader-psd.la
8libpixbufloader_psd_la_SOURCES = io-psd.c
9libpixbufloader_psd_la_LDFLAGS = -module -export-dynamic $(AM_LDFLAGS)
10
11#install-exec-hook:
12# install -d $(prefix)/lib/gdk-pixbuf-2.0/2.10.0/loaders/
130
=== removed file 'src/loaders/PSD/io-psd.c'
--- src/loaders/PSD/io-psd.c 2009-12-23 17:50:28 +0000
+++ src/loaders/PSD/io-psd.c 1970-01-01 00:00:00 +0000
@@ -1,598 +0,0 @@
1/* -*- mode: C; c-file-style: "linux" -*- */
2/* GdkPixbuf library - PSD image loader
3 *
4 * Copyright (C) 2008 Jan Dudek
5 *
6 * Authors: Jan Dudek <jd@jandudek.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
21 */
22
23/*
24 * TODO
25 * - use http://library.gnome.org/devel/glib/unstable/glib-Byte-Order-Macros.html
26 * - report errors from parse_psd_header
27 * - other color modes (CMYK at least)
28 * - i18n
29 */
30
31#include <stdlib.h>
32#include <stdio.h>
33#include <string.h>
34#include <gdk-pixbuf/gdk-pixbuf-io.h>
35#include <glib/gstdio.h>
36
37
38typedef struct
39{
40 guchar signature[4]; /* file ID, always "8BPS" */
41 guint16 version; /* version number, always 1 */
42 guchar resetved[6];
43 guint16 channels; /* number of color channels (1-24) */
44 guint32 rows; /* height of image in pixels (1-30000) */
45 guint32 columns; /* width of image in pixels (1-30000) */
46 guint16 depth; /* number of bits per channel (1, 8, and 16) */
47 guint16 color_mode; /* color mode as defined below */
48} PsdHeader;
49
50#define PSD_HEADER_SIZE 26
51
52typedef enum
53{
54 PSD_MODE_MONO = 0,
55 PSD_MODE_GRAYSCALE = 1,
56 PSD_MODE_INDEXED = 2,
57 PSD_MODE_RGB = 3,
58 PSD_MODE_CMYK = 4,
59 PSD_MODE_MULTICHANNEL = 7,
60 PSD_MODE_DUOTONE = 8,
61 PSD_MODE_LAB = 9,
62} PsdColorMode;
63
64typedef enum
65{
66 PSD_COMPRESSION_NONE = 0,
67 PSD_COMPRESSION_RLE = 1
68} PsdCompressionType;
69
70typedef enum
71{
72 PSD_STATE_HEADER,
73 PSD_STATE_COLOR_MODE_BLOCK,
74 PSD_STATE_RESOURCES_BLOCK,
75 PSD_STATE_LAYERS_BLOCK,
76 PSD_STATE_COMPRESSION,
77 PSD_STATE_LINES_LENGTHS,
78 PSD_STATE_CHANNEL_DATA,
79 PSD_STATE_DONE
80} PsdReadState;
81
82typedef struct
83{
84 PsdReadState state;
85
86 GdkPixbuf* pixbuf;
87
88 GdkPixbufModuleSizeFunc size_func;
89 GdkPixbufModuleUpdatedFunc updated_func;
90 GdkPixbufModulePreparedFunc prepared_func;
91 gpointer user_data;
92
93 guchar* buffer;
94 guint bytes_read;
95 guint32 bytes_to_skip;
96 gboolean bytes_to_skip_known;
97
98 guint32 width; /* width of image in pixels (1-30000) */
99 guint32 height; /* height of image in pixels (1-30000) */
100 guint16 channels; /* number of color channels (1-24) */
101 guint16 depth; /* number of bits per channel (1/8/16) */
102 PsdColorMode color_mode;
103 PsdCompressionType compression;
104
105 guchar** ch_bufs; /* channels buffers */
106 guint curr_ch; /* current channel */
107 guint curr_row;
108 guint pos; // redundant?
109 guint16* lines_lengths;
110 gboolean finalized;
111 gboolean use_alpha;
112} PsdContext;
113
114
115static guint16
116read_uint16 (guchar* buf)
117{
118 return (buf[0] << 8) | buf[1];
119}
120
121static guint32
122read_uint32 (guchar* buf)
123{
124 return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
125}
126
127
128/*
129 * Parse Psdheader from buffer
130 *
131 * str is expected to be at least PSD_HEADER_SIZE long
132 */
133static PsdHeader
134psd_parse_header (guchar* str)
135{
136 PsdHeader hd;
137
138 memcpy(hd.signature, str, 4);
139 hd.version = read_uint16(str + 4);
140 hd.channels = read_uint16(str + 12);
141 hd.rows = read_uint32(str + 14);
142 hd.columns = read_uint32(str + 18);
143 hd.depth = read_uint16(str + 22);
144 hd.color_mode = read_uint16(str + 24);
145
146 return hd;
147}
148
149/*
150 * Attempts to read bytes_needed bytes from data and stores them in buffer.
151 *
152 * Returns true if there were enough bytes and false otherwise
153 * (which means we need to call feed_buffer again)
154 */
155static gboolean
156feed_buffer (guchar* buffer,
157 guint* bytes_read,
158 const guchar** data,
159 guint* size,
160 guint bytes_needed)
161{
162 gint how_many = bytes_needed - *bytes_read;
163 if (how_many > *size) {
164 how_many = *size;
165 }
166 memcpy(buffer + *bytes_read, *data, how_many);
167 *bytes_read += how_many;
168 *data += how_many;
169 *size -= how_many;
170 return (*bytes_read == bytes_needed);
171}
172
173/*
174 * Attempts to read size of the block and then skip this block.
175 *
176 * Returns true when finishes consuming block data, otherwise false
177 * (false means we need to call skip_block again)
178 */
179static gboolean
180skip_block (PsdContext* context, const guchar** data, guint* size)
181{
182 static guint counter;
183
184 if (!context->bytes_to_skip_known) {
185 context->bytes_read = 0;
186 if (feed_buffer(context->buffer, &context->bytes_read, data, size, 4)) {
187 context->bytes_to_skip = read_uint32(context->buffer);
188 context->bytes_to_skip_known = TRUE;
189 counter = 0;
190 } else {
191 return FALSE;
192 }
193 }
194 if (*size < context->bytes_to_skip) {
195 *data += *size;
196 context->bytes_to_skip -= *size;
197 counter += *size;
198 *size = 0;
199 return FALSE;
200 } else {
201 counter += context->bytes_to_skip;
202 *size -= context->bytes_to_skip;
203 *data += context->bytes_to_skip;
204 return TRUE;
205 }
206}
207
208/*
209 * Decodes RLE-compressed data
210 */
211static void
212decompress_line(const guchar* src, guint line_length, guchar* dest)
213{
214 guint16 bytes_read = 0;
215 while (bytes_read < line_length) {
216 gchar byte = src[bytes_read];
217 ++bytes_read;
218
219 if (byte == -128) {
220 continue;
221 } else if (byte > -1) {
222 gint count = byte + 1;
223
224 // copy next count bytes
225 for (int k = 0; k < count; ++k) {
226 *dest = src[bytes_read];
227 ++dest;
228 ++bytes_read;
229 }
230 } else {
231 gint count = -byte + 1;
232
233 // copy next byte count times
234 guchar next_byte = src[bytes_read];
235 ++bytes_read;
236 for (int k = 0; k < count; ++k) {
237 *dest = next_byte;
238 ++dest;
239 }
240 }
241 }
242}
243
244static void
245reset_context_buffer(PsdContext* ctx)
246{
247 ctx->bytes_read = 0;
248 ctx->bytes_to_skip = 0;
249 ctx->bytes_to_skip_known = FALSE;
250}
251
252static gpointer
253gdk_pixbuf__psd_image_begin_load (GdkPixbufModuleSizeFunc size_func,
254 GdkPixbufModulePreparedFunc prepared_func,
255 GdkPixbufModuleUpdatedFunc updated_func,
256 gpointer user_data,
257 GError **error)
258{
259 PsdContext* context = g_malloc(sizeof(PsdContext));
260 if (context == NULL) {
261 g_set_error (
262 error,
263 GDK_PIXBUF_ERROR,
264 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
265 ("Not enough memory"));
266 return NULL;
267 }
268 context->size_func = size_func;
269 context->prepared_func = prepared_func;
270 context->updated_func = updated_func;
271 context->user_data = user_data;
272
273 context->state = PSD_STATE_HEADER;
274
275 // we'll allocate larger buffer once we know image size
276 context->buffer = g_malloc(PSD_HEADER_SIZE);
277 reset_context_buffer(context);
278
279 context->ch_bufs = NULL;
280 context->curr_ch = 0;
281 context->curr_row = 0;
282 context->pos = 0;
283 context->lines_lengths = NULL;
284 context->finalized = FALSE;
285 context->use_alpha = FALSE;
286
287 return (gpointer) context;
288}
289
290static gboolean
291gdk_pixbuf__psd_image_stop_load (gpointer context_ptr, GError **error)
292{
293 PsdContext *ctx = (PsdContext *) context_ptr;
294 gboolean retval = TRUE;
295
296 if (ctx->state != PSD_STATE_DONE) {
297 g_set_error (
298 error,
299 GDK_PIXBUF_ERROR,
300 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
301 ("PSD file was corrupted or incomplete."));
302 retval = FALSE;
303 }
304
305 g_free(ctx->buffer);
306 g_free(ctx->lines_lengths);
307 if (ctx->ch_bufs) {
308 for (int i = 0; i < ctx->channels; i++) {
309 g_free(ctx->ch_bufs[i]);
310 }
311 }
312 g_free(ctx);
313
314 return retval;
315}
316
317
318static gboolean
319gdk_pixbuf__psd_image_load_increment (gpointer context_ptr,
320 const guchar *data,
321 guint size,
322 GError **error)
323{
324 PsdContext* ctx = (PsdContext*) context_ptr;
325
326 while (size > 0) {
327 switch (ctx->state) {
328 case PSD_STATE_HEADER:
329 if (feed_buffer(
330 ctx->buffer, &ctx->bytes_read,
331 &data, &size, PSD_HEADER_SIZE))
332 {
333 PsdHeader hd = psd_parse_header(ctx->buffer);
334
335 ctx->width = hd.columns;
336 ctx->height = hd.rows;
337 ctx->channels = hd.channels;
338 ctx->depth = hd.depth;
339 ctx->color_mode = hd.color_mode;
340
341 /*
342 if (ctx->color_mode == PSD_MODE_RGB && ctx->channels == 4) {
343 ctx->use_alpha = TRUE;
344 }*/
345
346 //g_message("color_mode=%d, channels=%d, depth=%d",
347 // ctx->color_mode, ctx->channels, ctx->depth);
348
349 if (ctx->color_mode != PSD_MODE_RGB
350 //&& ctx->color_mode != PSD_MODE_CMYK
351 ) {
352 g_set_error (error, GDK_PIXBUF_ERROR,
353 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
354 ("Unsupported color mode"));
355 return FALSE;
356 }
357
358 if (ctx->depth != 8) {
359 g_set_error (error, GDK_PIXBUF_ERROR,
360 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
361 ("Unsupported color depth"));
362 return FALSE;
363 }
364
365 if (ctx->size_func) {
366 gint w = ctx->width;
367 gint h = ctx->height;
368 ctx->size_func(&w, &h, ctx->user_data);
369 if (w == 0 || h == 0) {
370 return FALSE;
371 }
372 }
373
374 // we need buffer that can contain one channel data of one
375 // row in RLE compressed format. 2*width should be enough
376 g_free(ctx->buffer);
377 ctx->buffer = g_malloc(ctx->width * 2);
378
379 // this will be needed for RLE decompression
380 ctx->lines_lengths =
381 g_malloc(2 * ctx->channels * ctx->height);
382
383 ctx->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
384 ctx->use_alpha, 8, ctx->width, ctx->height);
385
386 if (ctx->lines_lengths == NULL || ctx->buffer == NULL ||
387 ctx->pixbuf == NULL)
388 {
389 g_set_error (error, GDK_PIXBUF_ERROR,
390 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
391 ("Insufficient memory to load PSD image file"));
392 return FALSE;
393 }
394
395 // create separate buffers for each channel
396 ctx->ch_bufs = g_malloc(sizeof(guchar*) * ctx->channels);
397 for (int i = 0; i < ctx->channels; i++) {
398 ctx->ch_bufs[i] =
399 g_malloc(ctx->width * ctx->height);
400
401 if (ctx->ch_bufs[i] == NULL) {
402 g_set_error (error, GDK_PIXBUF_ERROR,
403 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
404 ("Insufficient memory to load PSD image file"));
405 return FALSE;
406 }
407 }
408
409 ctx->prepared_func(ctx->pixbuf, NULL, ctx->user_data);
410
411 ctx->state = PSD_STATE_COLOR_MODE_BLOCK;
412 reset_context_buffer(ctx);
413 }
414 break;
415 case PSD_STATE_COLOR_MODE_BLOCK:
416 if (skip_block(ctx, &data, &size)) {
417 ctx->state = PSD_STATE_RESOURCES_BLOCK;
418 reset_context_buffer(ctx);
419 }
420 break;
421 case PSD_STATE_RESOURCES_BLOCK:
422 if (skip_block(ctx, &data, &size)) {
423 ctx->state = PSD_STATE_LAYERS_BLOCK;
424 reset_context_buffer(ctx);
425 }
426 break;
427 case PSD_STATE_LAYERS_BLOCK:
428 if (skip_block(ctx, &data, &size)) {
429 ctx->state = PSD_STATE_COMPRESSION;
430 reset_context_buffer(ctx);
431 }
432 break;
433 case PSD_STATE_COMPRESSION:
434 if (feed_buffer(ctx->buffer, &ctx->bytes_read, &data, &size, 2))
435 {
436 ctx->compression = read_uint16(ctx->buffer);
437
438 if (ctx->compression == PSD_COMPRESSION_RLE) {
439 ctx->state = PSD_STATE_LINES_LENGTHS;
440 reset_context_buffer(ctx);
441 } else if (ctx->compression == PSD_COMPRESSION_NONE) {
442 ctx->state = PSD_STATE_CHANNEL_DATA;
443 } else {
444 g_set_error (error, GDK_PIXBUF_ERROR,
445 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
446 ("Unsupported compression type"));
447 return FALSE;
448 }
449 }
450 break;
451 case PSD_STATE_LINES_LENGTHS:
452 if (feed_buffer(
453 (guchar*) ctx->lines_lengths, &ctx->bytes_read, &data,
454 &size, 2 * ctx->height * ctx->channels))
455 {
456 // convert from different endianness
457 for (int i = 0; i < ctx->height * ctx->channels; i++) {
458 ctx->lines_lengths[i] = read_uint16(
459 (guchar*) &ctx->lines_lengths[i]);
460 }
461 ctx->state = PSD_STATE_CHANNEL_DATA;
462 reset_context_buffer(ctx);
463 }
464 break;
465 case PSD_STATE_CHANNEL_DATA:
466 {
467 guint line_length = ctx->width;
468 if (ctx->compression == PSD_COMPRESSION_RLE) {
469 line_length = ctx->lines_lengths[
470 ctx->curr_ch * ctx->height + ctx->curr_row];
471 }
472
473 if (feed_buffer(ctx->buffer, &ctx->bytes_read, &data, &size,
474 line_length))
475 {
476 reset_context_buffer(ctx);
477
478 if (ctx->compression == PSD_COMPRESSION_RLE) {
479 decompress_line(ctx->buffer, line_length,
480 ctx->ch_bufs[ctx->curr_ch] + ctx->pos
481 );
482 } else {
483 memcpy(ctx->ch_bufs[ctx->curr_ch] + ctx->pos,
484 ctx->buffer, ctx->width);
485 }
486
487 ctx->pos += ctx->width;
488 ++ctx->curr_row;
489
490 if (ctx->curr_row >= ctx->height) {
491 ++ctx->curr_ch;
492 ctx->curr_row = 0;
493 ctx->pos = 0;
494 if (ctx->curr_ch >= ctx->channels) {
495 ctx->state = PSD_STATE_DONE;
496 }
497 }
498 }
499 }
500 break;
501 case PSD_STATE_DONE:
502 default:
503 size = 0;
504 break;
505 }
506 }
507
508 if (ctx->state == PSD_STATE_DONE && !ctx->finalized) {
509 // convert or copy channel buffers to our GdkPixbuf
510 if (ctx->color_mode == PSD_MODE_RGB && !ctx->use_alpha) {
511 guchar* pixels = gdk_pixbuf_get_pixels(ctx->pixbuf);
512 for (int i = 0; i < ctx->height; i++) {
513 for (int j = 0; j < ctx->width; j++) {
514 pixels[3*j+0] = ctx->ch_bufs[0][ctx->width*i + j];
515 pixels[3*j+1] = ctx->ch_bufs[1][ctx->width*i + j];
516 pixels[3*j+2] = ctx->ch_bufs[2][ctx->width*i + j];
517 }
518 pixels += gdk_pixbuf_get_rowstride(ctx->pixbuf);
519 }
520 } else if (ctx->color_mode == PSD_MODE_RGB && ctx->use_alpha) {
521 guchar* pixels = gdk_pixbuf_get_pixels(ctx->pixbuf);
522 for (int i = 0; i < ctx->height; i++) {
523 for (int j = 0; j < ctx->width; j++) {
524 pixels[4*j+0] = ctx->ch_bufs[0][ctx->width*i + j];
525 pixels[4*j+1] = ctx->ch_bufs[1][ctx->width*i + j];
526 pixels[4*j+2] = ctx->ch_bufs[2][ctx->width*i + j];
527 pixels[4*j+3] = ctx->ch_bufs[3][ctx->width*i + j];
528 }
529 pixels += gdk_pixbuf_get_rowstride(ctx->pixbuf);
530 }
531 } else if (ctx->color_mode == PSD_MODE_CMYK) {
532 // unfortunately, this doesn't seem to work correctly...
533
534 guchar* pixels = gdk_pixbuf_get_pixels(ctx->pixbuf);
535 for (int i = 0; i < ctx->height; i++) {
536 for (int j = 0; j < ctx->width; j++) {
537 double c = 1.0 -
538 (double) ctx->ch_bufs[0][ctx->width*i + j] / 255.0;
539 double m = 1.0 -
540 (double) ctx->ch_bufs[1][ctx->width*i + j] / 255.0;
541 double y = 1.0 -
542 (double) ctx->ch_bufs[2][ctx->width*i + j] / 255.0;
543 double k = 1.0 -
544 (double) ctx->ch_bufs[3][ctx->width*i + j] / 255.0;
545
546 pixels[3*j+0] = (1.0 - (c * (1.0 - k) + k)) * 255.0;
547 pixels[3*j+1] = (1.0 - (m * (1.0 - k) + k)) * 255.0;
548 pixels[3*j+2] = (1.0 - (y * (1.0 - k) + k)) * 255.0;
549 }
550 pixels += gdk_pixbuf_get_rowstride(ctx->pixbuf);
551 }
552 }
553 ctx->finalized = TRUE;
554 }
555
556 return TRUE;
557}
558
559
560#ifndef INCLUDE_psd
561#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
562#else
563#define MODULE_ENTRY(function) void _gdk_pixbuf__psd_ ## function
564#endif
565
566MODULE_ENTRY (fill_vtable) (GdkPixbufModule* module)
567{
568 module->begin_load = gdk_pixbuf__psd_image_begin_load;
569 module->stop_load = gdk_pixbuf__psd_image_stop_load;
570 module->load_increment = gdk_pixbuf__psd_image_load_increment;
571}
572
573MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
574{
575 static GdkPixbufModulePattern signature[] = {
576 { "8BPS", NULL, 100 },
577 { NULL, NULL, 0 }
578 };
579 static gchar * mime_types[] = {
580 "image/x-psd",
581 NULL
582 };
583 static gchar * extensions[] = {
584 "psd",
585 NULL
586 };
587
588 info->name = "psd";
589 info->signature = signature;
590 //info->description = N_("Adobe Photoshop format");
591 info->description = "Adobe Photoshop format";
592 info->mime_types = mime_types;
593 info->extensions = extensions;
594 info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
595 info->flags = 0;
596 info->license = "LGPL";
597}
598
5990
=== removed directory 'src/loaders/XCF'
=== removed file 'src/loaders/XCF/Makefile.am'
--- src/loaders/XCF/Makefile.am 2010-08-21 18:06:49 +0000
+++ src/loaders/XCF/Makefile.am 1970-01-01 00:00:00 +0000
@@ -1,13 +0,0 @@
1#pluginexecdir = $(prefix)/lib/gtk-2.0/2.10.0/loaders/
2pluginexecdir = $(prefix)/lib/gdk-pixbuf-2.0/2.10.0/loaders/
3
4AM_CPPFLAGS += $(GTK_CFLAGS) $(GDKPIXBUF_CFLAGS) $(GLIB_CFLAGS) -shared -fpic -g -std=c99 -DGDK_PIXBUF_ENABLE_BACKEND
5AM_LDFLAGS = $(GTK_LIBS) $(GDKPIXBUF_LIBS) $(GLIB_LIBS)
6
7
8pluginexec_LTLIBRARIES = libpixbufloader-xcf.la
9libpixbufloader_xcf_la_SOURCES = io-xcf.c
10libpixbufloader_xcf_la_LDFLAGS = -module -export-dynamic $(AM_LDFLAGS)
11
12#install-exec-hook:
13# install -d $(prefix)/lib/gdk-pixbuf-2.0/2.10.0/loaders/
140
=== removed file 'src/loaders/XCF/io-xcf.c'
--- src/loaders/XCF/io-xcf.c 2010-05-24 09:46:52 +0000
+++ src/loaders/XCF/io-xcf.c 1970-01-01 00:00:00 +0000
@@ -1,1641 +0,0 @@
1/*
2 * Pixbuf loader for xcf
3 *
4 * Author(s):
5 * Stephane Delcroix <stephane@delcroix.org>
6 *
7 * Copyright (C) 2009 Novell, Inc
8 *
9 * This is a clean room implementation, based solely on
10 * http://henning.makholm.net/xcftools/xcfspec.txt and hexdumps
11 * of existing .xcf files.
12 *
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the
25 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26 * Boston, MA 02111-1307, USA.
27 */
28
29/*
30 * TODO:
31 * - fix the spots/stains (where are they coming from) ?
32 * - indexed mode
33 * - if the bg layer mode is not Normal or Dissolve, change it to Normal
34 * - file an enhancement request to gdk-pixbuf
35 */
36
37//#define GDK_PIXBUF_ENABLE_BACKEND
38
39#include <gmodule.h>
40#include <gdk-pixbuf/gdk-pixbuf.h>
41#include <gio/gio.h>
42#if GIO_2_23
43#include <gio/gzlibcompressor.h>
44#include <gio/gunixinputstream.h>
45#include <gio/gunixoutputstream.h>
46#endif
47#include <stdio.h>
48#include <math.h>
49#include <string.h>
50#include <stdlib.h>
51#include <errno.h>
52#include <bzlib.h>
53#include <glib.h>
54#include <glib/gstdio.h>
55
56//#define LOG(...) printf (__VA_ARGS__);
57#define LOG(...)
58
59#define _GNU_SOURCE 1
60#define POSIX_SOURCE 1
61
62#define PROP_END 0
63#define PROP_COLORMAP 1
64#define PROP_FLOATING_SELECTION 5
65#define PROP_OPACITY 6
66#define PROP_MODE 7
67#define PROP_VISIBLE 8
68#define PROP_LINKED 9
69#define PROP_APPLY_MASK 11
70#define PROP_OFFSETS 15
71#define PROP_COMPRESSION 17
72#define PROP_GUIDES 18
73#define PROP_RESOLUTION 19
74#define PROP_TATOO 20
75#define PROP_PARASITES 21
76#define PROP_UNIT 22
77#define PROP_PATHS 23
78#define PROP_USER_UNIT 24
79#define PROP_VECTORS 25
80
81#define COMPRESSION_NONE 0
82#define COMPRESSION_RLE 1
83
84#define LAYERTYPE_RGB 0
85#define LAYERTYPE_RGBA 1
86#define LAYERTYPE_GRAYSCALE 2
87#define LAYERTYPE_GRAYSCALEA 3
88#define LAYERTYPE_INDEXED 4
89#define LAYERTYPE_INDEXEDA 5
90
91#define LAYERMODE_NORMAL 0
92#define LAYERMODE_DISSOLVE 1
93#define LAYERMODE_BEHIND 2
94#define LAYERMODE_MULTIPLY 3
95#define LAYERMODE_SCREEN 4
96#define LAYERMODE_OVERLAY 5
97#define LAYERMODE_DIFFERENCE 6
98#define LAYERMODE_ADDITION 7
99#define LAYERMODE_SUBTRACT 8
100#define LAYERMODE_DARKENONLY 9
101#define LAYERMODE_LIGHTENONLY 10
102#define LAYERMODE_HUE 11
103#define LAYERMODE_SATURATION 12
104#define LAYERMODE_COLOR 13
105#define LAYERMODE_VALUE 14
106#define LAYERMODE_DIVIDE 15
107#define LAYERMODE_DODGE 16
108#define LAYERMODE_BURN 17
109#define LAYERMODE_HARDLIGHT 18
110#define LAYERMODE_SOFTLIGHT 19
111#define LAYERMODE_GRAINEXTRACT 20
112#define LAYERMODE_GRAINMERGE 21
113
114#define FILETYPE_STREAMCLOSED -1
115#define FILETYPE_UNKNOWN 0
116#define FILETYPE_XCF 1
117#define FILETYPE_XCF_BZ2 2
118#if GIO_2_23
119#define FILETYPE_XCF_GZ 3
120#endif
121
122extern FILE *fdopen (int __fd, __const char *__modes) __THROW __wur;
123
124typedef struct _XcfContext XcfContext;
125struct _XcfContext {
126 GdkPixbufModuleSizeFunc size_func;
127 GdkPixbufModulePreparedFunc prepare_func;
128 GdkPixbufModuleUpdatedFunc update_func;
129 gpointer user_data;
130 gint type;
131 bz_stream *bz_stream;
132
133#if GIO_2_23
134 GInputStream *input, *stream;
135#endif
136
137 gchar *tempname;
138 FILE *file;
139};
140
141typedef struct _XcfChannel XcfChannel;
142struct _XcfChannel {
143 guint32 width;
144 guint32 height;
145 gboolean visible;
146 guint32 opacity;
147 guint32 lptr;
148};
149
150typedef struct _XcfLayer XcfLayer;
151struct _XcfLayer {
152 guint32 width;
153 guint32 height;
154 guint32 type;
155 guint32 mode;
156 gboolean apply_mask;
157 gboolean visible;
158 guint32 opacity;
159 gint32 dx;
160 gint32 dy;
161 XcfChannel* layer_mask;
162 guint32 lptr;;
163};
164
165void
166rle_decode (FILE *f, gchar *ptr, int count, int type)
167{
168 int channels;
169 switch (type) {
170 case LAYERTYPE_RGB : channels = 3; break;
171 case LAYERTYPE_RGBA: channels = 4; break;
172 case LAYERTYPE_GRAYSCALE: channels = 1; break;
173 case LAYERTYPE_GRAYSCALEA: channels = 2; break;
174 case LAYERTYPE_INDEXED: channels = 1; break;
175 case LAYERTYPE_INDEXEDA: channels = 2; break;
176 }
177
178 guchar opcode;
179 guchar buffer[3];
180 guchar ch[channels][count];
181 int channel;
182 size_t lfr;
183
184 //un-rle
185 for (channel = 0; channel < channels; channel++) {
186 int pixels_count = 0;
187 while (pixels_count < count) {
188 lfr = fread (&opcode, sizeof(guchar), 1, f);
189 if (opcode <= 126) {
190 lfr = fread (buffer, 1, 1, f);
191 opcode ++;
192 while (opcode --)
193 memcpy (ch[channel] + (pixels_count++), buffer, 1);
194 } else if (opcode == 127) {
195 lfr = fread (buffer, 3, 1, f);
196 int p = buffer[0];
197 int q = buffer[1];
198 int count = p*256+q;
199 while (count --)
200 memcpy (ch[channel] + (pixels_count++), buffer+2, 1);
201 } else if (opcode == 128) {
202 lfr = fread (buffer, 2, 1, f);
203 int p = buffer[0];
204 int q = buffer[1];
205 lfr = fread (ch[channel] + pixels_count, p*256+q, 1, f);
206 pixels_count += p*256+q;
207 } else if (opcode >= 129) {
208 lfr = fread (ch[channel] + pixels_count, 256 - opcode, 1, f);
209 pixels_count += 256 - opcode;
210 }
211 }
212 }
213
214 //reinterlace the channels
215 int i, j;
216 for (i=0; i <count; i++)
217 for (j=0; j<channels; j++)
218 memcpy (ptr + i * channels + j, ch[j] + i, 1);
219}
220
221void
222to_rgba (gchar *ptr, int count, int type)
223{
224 //pad to rgba
225 int i;
226
227 for (i=count-1; i>=0;i--)
228 switch (type) {
229 case LAYERTYPE_RGB:
230 memcpy (ptr + 4*i, ptr + 3*i, 3);
231 ptr[4*i + 3] = 0xff;
232 break;
233 case LAYERTYPE_RGBA:
234 ///nothing to do
235 break;
236 case LAYERTYPE_GRAYSCALE:
237 memcpy (ptr + 4*i, ptr + i, 1);
238 memcpy (ptr + 4*i + 1, ptr + i, 1);
239 memcpy (ptr + 4*i + 2, ptr + i, 1);
240 ptr[4*i + 3] = 0xff;
241 break;
242 case LAYERTYPE_GRAYSCALEA:
243 memcpy (ptr + 4*i, ptr + i, 1);
244 memcpy (ptr + 4*i + 1, ptr + i, 1);
245 memcpy (ptr + 4*i + 2, ptr + i, 1);
246 memcpy (ptr + 4+i + 3, ptr + i + 1, 1);
247 break;
248 }
249}
250
251void
252apply_opacity (guchar* ptr, int size, guint32 opacity)
253{
254 int i;
255 for (i=0; i<size; i++)
256 ptr[4*i + 3] = (guchar)((ptr[4*i+3] * opacity) / 0xff);
257}
258
259void
260apply_mask (FILE *f, gchar compression, guchar *ptr, int size, XcfChannel *mask, int tile_id)
261{
262 //save file position
263 long pos = ftell (f);
264 size_t lfr;
265
266 guint32 tptr = mask->lptr + (2 + tile_id) * sizeof(guint32); //skip width and height
267 fseek (f, tptr, SEEK_SET);
268 lfr = fread (&tptr, sizeof(guint32), 1, f);
269 fseek (f, GUINT32_FROM_BE(tptr), SEEK_SET);
270
271 gchar pixels[4096];
272 if (compression == COMPRESSION_RLE)
273 rle_decode (f, pixels, size, LAYERTYPE_GRAYSCALE);
274 else //COMPRESSION_NONE
275 lfr = fread (pixels, sizeof(gchar), size, f);
276
277 int i;
278 for (i = 0; i<size; i++)
279 ptr[4*i + 3] = ptr[4 * i + 3] * pixels[i] / 0xff;
280
281 //rewind
282 fseek (f, pos, SEEK_SET);
283}
284
285
286void
287intersect_tile (guchar* ptr, int im_width, int im_height, int *ox, int *oy, int *tw, int *th)
288{
289 int i;
290 if (*ox < 0) {
291 for (i=0; i<*th; i++) {
292 memmove (ptr + 4 * i * (*tw + *ox), ptr + 4 * i * (*tw), 4 * (*tw + *ox));
293 }
294 *tw = *tw + *ox;
295 *ox = 0;
296 }
297 if (*oy < 0) {
298 memmove (ptr, ptr + 4 * *tw * -*oy, 4 * *tw * (*th + *oy));
299 *th = *th + *oy;
300 *oy = 0;
301 }
302 if (*ox + *tw > im_width) {
303 for (i=0; i<*th; i++) {
304 memmove (ptr + 4 * i * (im_width - *ox), ptr + 4 * i * (*tw), 4 * (im_width - *ox));
305 }
306 *tw = im_width - *ox;
307 }
308 if (*oy + *th > im_height) {
309 *th = im_height - *oy;
310 }
311}
312
313void blend (guchar* rgba0, guchar* rgba1)
314{
315 if (rgba0[3] == 0 && rgba1[3] == 0)
316 return;
317
318 guchar k = 0xff * rgba1[3] / (0xff - (0xff-rgba0[3])*(0xff-rgba1[3])/0xff);
319 rgba0[0] = ((0xff - k) * rgba0[0] + k * rgba1[0]) / 0xff;
320 rgba0[1] = ((0xff - k) * rgba0[1] + k * rgba1[1]) / 0xff;
321 rgba0[2] = ((0xff - k) * rgba0[2] + k * rgba1[2]) / 0xff;
322}
323
324typedef void (*composite_func) (guchar* rgb0, guchar* rgb1);
325
326void
327multiply (guchar *rgb0, guchar *rgb1)
328{
329 rgb1[0] = (rgb0[0] * rgb1[0] ) / 0xff;
330 rgb1[1] = (rgb0[1] * rgb1[1] ) / 0xff;
331 rgb1[2] = (rgb0[2] * rgb1[2] ) / 0xff;
332}
333
334void
335screen (guchar *rgb0, guchar *rgb1)
336{
337 rgb1[0] = 0xff - (0xff - rgb0[0]) * (0xff - rgb1[0]) / 0xff;
338 rgb1[1] = 0xff - (0xff - rgb0[1]) * (0xff - rgb1[1]) / 0xff;
339 rgb1[2] = 0xff - (0xff - rgb0[2]) * (0xff - rgb1[2]) / 0xff;
340}
341
342void
343overlay (guchar *rgb0, guchar *rgb1)
344{
345 //FIXME
346 //LOG ("Overlay (%d %d %d) (%d %d %d) : ", rgb0[0], rgb0[1], rgb0[2], rgb1[0], rgb1[1], rgb1[2]);
347 rgb1[0] = MIN (0xff, ((0xff - rgb1[0]) * rgb0[0] * rgb0[0] / 0xff + rgb0[0] * (0xff - (0xff - rgb1[0]) * (0xff - rgb1[0]) / 0xff)) / 0xff);
348 rgb1[1] = MIN (0xff, ((0xff - rgb1[1]) * rgb0[1] * rgb0[1] / 0xff + rgb0[1] * (0xff - (0xff - rgb1[1]) * (0xff - rgb1[1]) / 0xff)) / 0xff);
349 rgb1[2] = MIN (0xff, ((0xff - rgb1[2]) * rgb0[2] * rgb0[2] / 0xff + rgb0[2] * (0xff - (0xff - rgb1[2]) * (0xff - rgb1[2]) / 0xff)) / 0xff);
350 //LOG ("(%d %d %d)\n", rgb1[0], rgb1[1], rgb1[2]);
351}
352
353void
354difference (guchar *rgb0, guchar *rgb1)
355{
356 rgb1[0] = (rgb0[0] > rgb1[0]) ? rgb0[0] - rgb1[0] : rgb1[0] - rgb0[0];
357 rgb1[1] = (rgb0[1] > rgb1[1]) ? rgb0[1] - rgb1[1] : rgb1[1] - rgb0[1];
358 rgb1[2] = (rgb0[2] > rgb1[2]) ? rgb0[2] - rgb1[2] : rgb1[2] - rgb0[2];
359}
360
361void
362addition (guchar *rgb0, guchar *rgb1)
363{
364// LOG ("addition (%d %d %d) (%d %d %d):", rgb0[0], rgb0[1], rgb0[2], rgb1[0], rgb1[1], rgb1[2]);
365 rgb1[0] = (rgb0[0] + rgb1[0]) > 0xff ? 0xff : rgb0[0] + rgb1[0];
366 rgb1[1] = (rgb0[1] + rgb1[1]) > 0xff ? 0xff : rgb0[1] + rgb1[1];
367 rgb1[2] = (rgb0[2] + rgb1[2]) > 0xff ? 0xff : rgb0[2] + rgb1[2];
368// LOG ("(%d %d %d)\n", rgb1[0], rgb1[1], rgb1[2]);
369}
370
371void
372subtract (guchar *rgb0, guchar *rgb1)
373{
374 rgb1[0] = (rgb0[0] - rgb1[0]) < 0 ? 0 : rgb0[0] - rgb1[0];
375 rgb1[1] = (rgb0[1] - rgb1[1]) < 0 ? 0 : rgb0[1] - rgb1[1];
376 rgb1[2] = (rgb0[2] - rgb1[2]) < 0 ? 0 : rgb0[2] - rgb1[2];
377}
378
379void
380min (guchar *rgb0, guchar *rgb1)
381{
382 rgb1[0] = MIN (rgb0[0], rgb1[0]);
383 rgb1[1] = MIN (rgb0[1], rgb1[1]);
384 rgb1[2] = MIN (rgb0[2], rgb1[2]);
385}
386
387void
388max (guchar *rgb0, guchar *rgb1)
389{
390 rgb1[0] = MAX (rgb0[0], rgb1[0]);
391 rgb1[1] = MAX (rgb0[1], rgb1[1]);
392 rgb1[2] = MAX (rgb0[2], rgb1[2]);
393}
394
395void
396divide (guchar *rgb0, guchar *rgb1)
397{
398 rgb1[0] = rgb1[0] == 0 ? (rgb0[0] == 0 ? 0 : 0xff) : MIN (0xff, 0xff * rgb0[0] / rgb1[0]);
399 rgb1[1] = rgb1[1] == 0 ? (rgb0[1] == 0 ? 0 : 0xff) : MIN (0xff, 0xff * rgb0[1] / rgb1[1]);
400 rgb1[2] = rgb1[2] == 0 ? (rgb0[2] == 0 ? 0 : 0xff) : MIN (0xff, 0xff * rgb0[2] / rgb1[2]);
401}
402
403void
404dodge (guchar *rgb0, guchar *rgb1)
405{
406 rgb1[0] = rgb1[0] == 0xff ? (rgb0[0] == 0 ? 0 : 0xff) : MIN (0xff, 0xff * rgb0[0] / (0xff - rgb1[0]));
407 rgb1[1] = rgb1[1] == 0xff ? (rgb0[1] == 0 ? 0 : 0xff) : MIN (0xff, 0xff * rgb0[1] / (0xff - rgb1[1]));
408 rgb1[2] = rgb1[2] == 0xff ? (rgb0[2] == 0 ? 0 : 0xff) : MIN (0xff, 0xff * rgb0[2] / (0xff - rgb1[2]));
409}
410
411void
412burn (guchar *rgb0, guchar *rgb1) // 1-(1-x1)/x2
413{
414 rgb1[0] = rgb1[0] == 0 ? (rgb0[0] == 0xff ? 0xff : 0) : 0xff - MIN (0xff, 0xff * (0xff - rgb0[0]) / rgb1[0]);
415 rgb1[1] = rgb1[1] == 0 ? (rgb0[1] == 0xff ? 0xff : 0) : 0xff - MIN (0xff, 0xff * (0xff - rgb0[1]) / rgb1[1]);
416 rgb1[2] = rgb1[2] == 0 ? (rgb0[2] == 0xff ? 0xff : 0) : 0xff - MIN (0xff, 0xff * (0xff - rgb0[2]) / rgb1[2]);
417}
418
419void
420hardlight (guchar *rgb0, guchar *rgb1) //if x2 < 0.5 then 2*x1*x2 else 1-2*(1-x1)(1-x2)
421{
422 rgb1[0] = rgb1[0] < 0x80 ? 2 * rgb0[0] * rgb1[0] / 0xff : 0xff - 2 * (0xff - rgb0[0]) * (0xff - rgb1[0])/ 0xff;
423 rgb1[1] = rgb1[1] < 0x80 ? 2 * rgb0[1] * rgb1[1] / 0xff : 0xff - 2 * (0xff - rgb0[1]) * (0xff - rgb1[1])/ 0xff;
424 rgb1[2] = rgb1[2] < 0x80 ? 2 * rgb0[2] * rgb1[2] / 0xff : 0xff - 2 * (0xff - rgb0[2]) * (0xff - rgb1[2])/ 0xff;
425}
426
427void
428softlight(guchar *rgb0, guchar *rgb1)
429{
430 //FIXME
431 //LOG ("Softlight (%d %d %d) (%d %d %d) : ", rgb0[0], rgb0[1], rgb0[2], rgb1[0], rgb1[1], rgb1[2]);
432 rgb1[0] = ((0xff - rgb0[0]) * rgb0[0] * rgb1[0] / 0xff + rgb0[0] * (0xff - (0xff - rgb1[0]) * (0xff - rgb0[0]) / 0x100)) / 0x100;
433 rgb1[1] = ((0xff - rgb0[1]) * rgb0[1] * rgb1[1] / 0xff + rgb0[1] * (0xff - (0xff - rgb1[1]) * (0xff - rgb0[1]) / 0x100)) / 0x100;
434 rgb1[2] = ((0xff - rgb0[2]) * rgb0[2] * rgb1[2] / 0xff + rgb0[2] * (0xff - (0xff - rgb1[2]) * (0xff - rgb0[2]) / 0x100)) / 0x100;
435 //LOG ("(%d %d %d)\n", rgb1[0], rgb1[1], rgb1[2]);
436}
437
438void
439grainextract (guchar *rgb0, guchar *rgb1) //x1-x2+.5
440{
441 rgb1[0] = MAX (0, MIN (0xff, rgb0[0] - rgb1[0] + 0x80));
442 rgb1[1] = MAX (0, MIN (0xff, rgb0[1] - rgb1[1] + 0x80));
443 rgb1[2] = MAX (0, MIN (0xff, rgb0[2] - rgb1[2] + 0x80));
444}
445
446void
447grainmerge (guchar *rgb0, guchar *rgb1)
448{
449 rgb1[0] = MAX (0, MIN (0xff, rgb0[0] + rgb1[0] - 0x80));
450 rgb1[1] = MAX (0, MIN (0xff, rgb0[1] + rgb1[1] - 0x80));
451 rgb1[2] = MAX (0, MIN (0xff, rgb0[2] + rgb1[2] - 0x80));
452}
453
454
455//FIXME: any way to do the following 4 ones in integer arithmetic ?
456void
457hue (guchar *rgb0, guchar *rgb1)
458{
459 if (rgb1[0] == rgb1[1] == rgb1[2]) {
460 rgb1[0] = rgb0[0];
461 rgb1[1] = rgb0[1];
462 rgb1[2] = rgb0[2];
463 return;
464 }
465 //hue of rgb1, value and saturation of rgb0
466 guchar min0 = MIN (MIN (rgb0[0], rgb0[1]), rgb0[2]);
467 guchar max0 = MAX (MAX (rgb0[0], rgb0[1]), rgb0[2]);
468 guchar min1 = MIN (MIN (rgb1[0], rgb1[1]), rgb1[2]);
469 guchar max1 = MAX (MAX (rgb1[0], rgb1[1]), rgb1[2]);
470 if (max0 == 0) {
471 rgb1[0] = 0x00;
472 rgb1[1] = 0x00;
473 rgb1[2] = 0x00;
474 return;
475 }
476 double p = max0 * (max0 - min0) / (max1*(max0-min0) - min1*max0 + max1*min0);
477 double q = - max0 * (min1*max0 - max1*min0) / (max1*(max0-min0) - min1*max0 + max1*min0);
478 rgb1[0] = (guchar)(rgb1[0] * p + q);
479 rgb1[1] = (guchar)(rgb1[1] * p + q);
480 rgb1[2] = (guchar)(rgb1[2] * p + q);
481}
482
483void
484saturation (guchar *rgb0, guchar *rgb1)
485{
486 //hue and value of rgb0, saturation of rgb1
487 guchar min0 = MIN (MIN (rgb0[0], rgb0[1]), rgb0[2]);
488 guchar max0 = MAX (MAX (rgb0[0], rgb0[1]), rgb0[2]);
489 guchar min1 = MIN (MIN (rgb1[0], rgb1[1]), rgb1[2]);
490 guchar max1 = MAX (MAX (rgb1[0], rgb1[1]), rgb1[2]);
491 if (max0 == 0) {
492 rgb1[0] = 0x00;
493 rgb1[1] = 0x00;
494 rgb1[2] = 0x00;
495 return;
496 }
497 if (max0 == min0) {
498 rgb1[0] = max0;
499 rgb1[1] = min1*max0 / max0;
500 rgb1[2] = rgb1[1];
501 return;
502 }
503 double p = max0 * (min1 - max1) / (max0*(min1-max1) - min1*max0 + max1*min0);
504 double q = - max0 * (min1*max0 - max1*min0) / (max0*(min1-max1) - min1*max0 + max1*min0);
505 rgb1[0] = (guchar)(rgb0[0] * p + q);
506 rgb1[1] = (guchar)(rgb0[1] * p + q);
507 rgb1[2] = (guchar)(rgb0[2] * p + q);
508
509}
510
511void
512value (guchar *rgb0, guchar *rgb1)
513{
514 //hue and saturation ov rgb0, value of rgb1
515 guchar min0 = MIN (MIN (rgb0[0], rgb0[1]), rgb0[2]);
516 guchar max0 = MAX (MAX (rgb0[0], rgb0[1]), rgb0[2]);
517 guchar min1 = MIN (MIN (rgb1[0], rgb1[1]), rgb1[2]);
518 guchar max1 = MAX (MAX (rgb1[0], rgb1[1]), rgb1[2]);
519 if (max0 == 0) {
520 rgb1[0] = 0x00;
521 rgb1[1] = 0x00;
522 rgb1[2] = 0x00;
523 return;
524 }
525 if (max0 == min0) {
526 rgb1[0] = max1;
527 rgb1[1] = max1;
528 rgb1[2] = max1;
529 return;
530 }
531
532 double p = max1 / max0;
533
534 rgb1[0] = (guchar)(rgb0[0] * p);
535 rgb1[1] = (guchar)(rgb0[1] * p);
536 rgb1[2] = (guchar)(rgb0[2] * p);
537}
538
539void
540color (guchar *rgb0, guchar *rgb1)
541{
542 //hue and hsl-saturation or rgb1, luminosity of rgb0
543 guchar min0 = MIN (MIN (rgb0[0], rgb0[1]), rgb0[2]);
544 guchar max0 = MAX (MAX (rgb0[0], rgb0[1]), rgb0[2]);
545 guchar min1 = MIN (MIN (rgb1[0], rgb1[1]), rgb1[2]);
546 guchar max1 = MAX (MAX (rgb1[0], rgb1[1]), rgb1[2]);
547
548 double p = MIN ((min0+max0)/2, 0xff - (min0+max0)/2) / MIN ((min1+max1)/2, 0xff - (min1+max1)/2);
549 double q = (min0 + max0 - (min1 + max1) * p) / 2.0;
550
551 rgb1[0] = (guchar)(rgb1[0] * p + q);
552 rgb1[1] = (guchar)(rgb1[1] * p + q);
553 rgb1[2] = (guchar)(rgb1[2] * p + q);
554}
555
556void
557composite (gchar *pixbuf_pixels, int rowstride, gchar *tile_pixels, int ox, int oy, int tw, int th, guint32 layer_mode)
558{
559 composite_func f = NULL;
560 int origin = 4 * ox + rowstride * oy;
561 int i, j;
562
563 switch (layer_mode) {
564 case LAYERMODE_NORMAL:
565 for (j=0;j<th;j++)
566 for (i=0;i<tw;i++) {
567 //a0 = 1 - (1-a0)*(a-a1)
568 //rgb0 = BLEND (rgba0, rgba1)
569 gchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i;
570 gchar *src = tile_pixels + j*tw*4 + i*4;
571 guchar alpha = 0xff - (0xff - dest[3]) * (0xff - src [3]);
572 blend (dest, src);
573 dest[3] = alpha;
574 }
575 break;
576 case LAYERMODE_DISSOLVE:
577 srand(time(0));
578 for (j=0;j<th;j++)
579 for (i=0;i<tw;i++) {
580 guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i;
581 guchar *src = tile_pixels + j*tw*4 + i*4;
582 guchar d = rand () % 0x100;
583 dest [0] = d <= src[3] ? src[0] : dest[0];
584 dest [1] = d <= src[3] ? src[1] : dest[1];
585 dest [2] = d <= src[3] ? src[2] : dest[2];
586 dest [3] = d <= src[3] ? 0xff : dest[3];
587 }
588 break;
589 case LAYERMODE_BEHIND: //ignore
590 break;
591 // 3<=mode<=10 || 15<=mode<=21
592 // a0 = a0
593 // rgba0 = blend (rgba0, F(rgb0, rgb1), MIN(a0, a1)
594 case LAYERMODE_MULTIPLY:
595 f = multiply;
596 for (j=0;j<th;j++)
597 for (i=0;i<tw;i++) {
598 guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i;
599 guchar *src = tile_pixels + j*tw*4 + i*4;
600 f (dest, src);
601 src[3] = MIN (dest[3], src[3]);
602 blend (dest, src);
603 }
604 break;
605 case LAYERMODE_SCREEN:
606 f = screen;
607 for (j=0;j<th;j++)
608 for (i=0;i<tw;i++) {
609 guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i;
610 guchar *src = tile_pixels + j*tw*4 + i*4;
611 f (dest, src);
612 src[3] = MIN (dest[3], src[3]);
613 blend (dest, src);
614 }
615 break;
616 case LAYERMODE_OVERLAY:
617 f = overlay;
618 for (j=0;j<th;j++)
619 for (i=0;i<tw;i++) {
620 guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i;
621 guchar *src = tile_pixels + j*tw*4 + i*4;
622 f (dest, src);
623 src[3] = MIN (dest[3], src[3]);
624 blend (dest, src);
625 }
626 break;
627 case LAYERMODE_SOFTLIGHT:
628 f = softlight;
629 for (j=0;j<th;j++)
630 for (i=0;i<tw;i++) {
631 guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i;
632 guchar *src = tile_pixels + j*tw*4 + i*4;
633 f (dest, src);
634 src[3] = MIN (dest[3], src[3]);
635 blend (dest, src);
636 }
637 break;
638 case LAYERMODE_DIFFERENCE:
639 f = difference;
640 for (j=0;j<th;j++)
641 for (i=0;i<tw;i++) {
642 guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i;
643 guchar *src = tile_pixels + j*tw*4 + i*4;
644 f (dest, src);
645 src[3] = MIN (dest[3], src[3]);
646 blend (dest, src);
647 }
648 break;
649 case LAYERMODE_ADDITION:
650 f = addition;
651 for (j=0;j<th;j++)
652 for (i=0;i<tw;i++) {
653 guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i;
654 guchar *src = tile_pixels + j*tw*4 + i*4;
655 f (dest, src);
656 src[3] = MIN (dest[3], src[3]);
657 blend (dest, src);
658 }
659 break;
660 case LAYERMODE_SUBTRACT:
661 f = subtract;
662 for (j=0;j<th;j++)
663 for (i=0;i<tw;i++) {
664 guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i;
665 guchar *src = tile_pixels + j*tw*4 + i*4;
666 f (dest, src);
667 src[3] = MIN (dest[3], src[3]);
668 blend (dest, src);
669 }
670 break;
671 case LAYERMODE_DARKENONLY:
672 f = min;
673 for (j=0;j<th;j++)
674 for (i=0;i<tw;i++) {
675 guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i;
676 guchar *src = tile_pixels + j*tw*4 + i*4;
677 f (dest, src);
678 src[3] = MIN (dest[3], src[3]);
679 blend (dest, src);
680 }
681 break;
682 case LAYERMODE_LIGHTENONLY:
683 f = max;
684 for (j=0;j<th;j++)
685 for (i=0;i<tw;i++) {
686 guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i;
687 guchar *src = tile_pixels + j*tw*4 + i*4;
688 f (dest, src);
689 src[3] = MIN (dest[3], src[3]);
690 blend (dest, src);
691 }
692 break;
693 case LAYERMODE_DIVIDE:
694 f = divide;
695 for (j=0;j<th;j++)
696 for (i=0;i<tw;i++) {
697 guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i;
698 guchar *src = tile_pixels + j*tw*4 + i*4;
699 f (dest, src);
700 src[3] = MIN (dest[3], src[3]);
701 blend (dest, src);
702 }
703 break;
704 case LAYERMODE_DODGE:
705 f = dodge;
706 for (j=0;j<th;j++)
707 for (i=0;i<tw;i++) {
708 guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i;
709 guchar *src = tile_pixels + j*tw*4 + i*4;
710 f (dest, src);
711 src[3] = MIN (dest[3], src[3]);
712 blend (dest, src);
713 }
714 break;
715 case LAYERMODE_BURN:
716 f = burn;
717 for (j=0;j<th;j++)
718 for (i=0;i<tw;i++) {
719 guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i;
720 guchar *src = tile_pixels + j*tw*4 + i*4;
721 f (dest, src);
722 src[3] = MIN (dest[3], src[3]);
723 blend (dest, src);
724 }
725 break;
726 case LAYERMODE_HARDLIGHT:
727 f = hardlight;
728 for (j=0;j<th;j++)
729 for (i=0;i<tw;i++) {
730 guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i;
731 guchar *src = tile_pixels + j*tw*4 + i*4;
732 f (dest, src);
733 src[3] = MIN (dest[3], src[3]);
734 blend (dest, src);
735 }
736 break;
737 case LAYERMODE_GRAINEXTRACT:
738 f = grainextract;
739 for (j=0;j<th;j++)
740 for (i=0;i<tw;i++) {
741 guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i;
742 guchar *src = tile_pixels + j*tw*4 + i*4;
743 f (dest, src);
744 src[3] = MIN (dest[3], src[3]);
745 blend (dest, src);
746 }
747 break;
748 case LAYERMODE_GRAINMERGE:
749 f = grainmerge;
750 for (j=0;j<th;j++)
751 for (i=0;i<tw;i++) {
752 guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i;
753 guchar *src = tile_pixels + j*tw*4 + i*4;
754 f (dest, src);
755 src[3] = MIN (dest[3], src[3]);
756 blend (dest, src);
757 }
758 break;
759 case LAYERMODE_HUE:
760 f = hue;
761 for (j=0;j<th;j++)
762 for (i=0;i<tw;i++) {
763 guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i;
764 guchar *src = tile_pixels + j*tw*4 + i*4;
765 f (dest, src);
766 src[3] = MIN (dest[3], src[3]);
767 blend (dest, src);
768 }
769 break;
770 case LAYERMODE_SATURATION:
771 f = saturation;
772 for (j=0;j<th;j++)
773 for (i=0;i<tw;i++) {
774 guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i;
775 guchar *src = tile_pixels + j*tw*4 + i*4;
776 f (dest, src);
777 src[3] = MIN (dest[3], src[3]);
778 blend (dest, src);
779 }
780 break;
781 case LAYERMODE_VALUE:
782 f = value;
783 for (j=0;j<th;j++)
784 for (i=0;i<tw;i++) {
785 guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i;
786 guchar *src = tile_pixels + j*tw*4 + i*4;
787 f (dest, src);
788 src[3] = MIN (dest[3], src[3]);
789 blend (dest, src);
790 }
791 break;
792 case LAYERMODE_COLOR:
793 f = color;
794 for (j=0;j<th;j++)
795 for (i=0;i<tw;i++) {
796 guchar *dest = pixbuf_pixels + origin + j * rowstride + 4 * i;
797 guchar *src = tile_pixels + j*tw*4 + i*4;
798 f (dest, src);
799 src[3] = MIN (dest[3], src[3]);
800 blend (dest, src);
801 }
802 break;
803
804 default: //Pack layer on top of each other, without any blending at all
805 for (j=0; j<th;j++) {
806 memcpy (pixbuf_pixels + origin + j * rowstride, tile_pixels + j*tw*4 , tw*4);
807 }
808 break;
809 }
810
811}
812
813static GdkPixbuf*
814xcf_image_load_real (FILE *f, XcfContext *context, GError **error)
815{
816 guint32 width;
817 guint32 height;
818 guint32 color_mode;
819 gchar compression = 0;
820 GList *layers = NULL;
821 GdkPixbuf *pixbuf = NULL;
822
823 guchar buffer[32];
824 guint32 data[3];
825 guint32 property[2];
826 size_t lfr;
827
828 //Magic and version
829 lfr = fread (buffer, sizeof(guchar), 9, f);
830 //LOG ("%s\n", buffer);
831 if (strncmp (buffer, "gimp xcf ", 9)) {
832 g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE, "Wrong magic");
833 return NULL;
834 }
835
836 lfr = fread (buffer, sizeof(guchar), 4, f);
837 if (strncmp (buffer, "file", 4) && strncmp (buffer, "v001", 4) && strncmp (buffer, "v002", 4)) {
838 g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_UNKNOWN_TYPE, "Unsupported version");
839 return NULL;
840 }
841 lfr = fread (buffer, sizeof(guchar), 1, f);
842
843 //Canvas size and Color mode
844 lfr = fread (data, sizeof(guint32), 3, f);
845
846 width = GUINT32_FROM_BE(data[0]);
847 height = GUINT32_FROM_BE(data[1]);
848 color_mode = GUINT32_FROM_BE(data[2]);
849 if (color_mode == 2) { //Indexed, not supported for now
850 g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_UNKNOWN_TYPE, "Indexed color mode unsupported");
851 return NULL;
852 }
853
854
855 LOG ("W: %d, H: %d, mode: %d\n", width, height, color_mode);
856
857 //Image Properties
858 while (1) {
859 lfr = fread (property, sizeof(guint32), 2, f); //read property and payload
860 if (!property[0])
861 break;
862 property[0] = GUINT32_FROM_BE(property[0]);
863 property[1] = GUINT32_FROM_BE(property[1]);
864 //LOG ("property %d, payload %d\n", property[0], property[1]);
865 switch (property[0]) {
866 case PROP_COMPRESSION:
867 lfr = fread (&compression, sizeof(gchar), 1, f);
868 LOG ("compression: %d\n", compression);
869 break;
870 case PROP_COLORMAP: //essential, need to parse this
871 case PROP_END:
872 default:
873 //skip the payload
874 fseek (f, property[1], SEEK_CUR);
875 break;
876 }
877 }
878
879 //Layer Pointer
880 guint32 layer_ptr;
881 while (1) {
882 lfr = fread (&layer_ptr, sizeof(guint32), 1, f);
883 layer_ptr = GUINT32_FROM_BE (layer_ptr);
884 if (!layer_ptr)
885 break;;
886
887 XcfLayer *layer = g_try_new (XcfLayer, 1);
888 if (!layer) {
889 g_set_error (error,
890 GDK_PIXBUF_ERROR,
891 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
892 "Cannot allocate memory for loading XCF image");
893 return NULL;
894 }
895
896 gboolean ignore_layer = FALSE;
897
898 layer->mode = 0;
899 layer->apply_mask = FALSE;
900 layer->layer_mask = NULL;
901 layer->dx = layer->dy = 0;
902 layer->visible = TRUE;
903 layer->opacity = 0xff;
904
905 //LOG ("layer_ptr: %d\n", layer_ptr);
906 long pos = ftell (f);
907 //jump to the layer
908 fseek(f, layer_ptr, SEEK_SET);
909
910 //layer width, height, type
911 lfr = fread (data, sizeof(guint32), 3, f);
912 layer->width = GUINT32_FROM_BE(data[0]);
913 layer->height = GUINT32_FROM_BE(data[1]);
914 layer->type = GUINT32_FROM_BE(data[2]);
915 LOG("\tLayer w:%d h:%d type:%d\n", layer->width, layer->height, layer->type);
916
917 //Layer name, ignore
918 guint32 string_size;
919 lfr = fread (&string_size, sizeof(guint32), 1, f);
920 fseek (f, GUINT32_FROM_BE(string_size), SEEK_CUR);
921
922 //Layer properties
923 while (1) {
924 lfr = fread (property, sizeof(guint32), 2, f); //property and payload
925 if (!property[0])
926 break; //break on PROP_END
927 property[0] = GUINT32_FROM_BE (property[0]);
928 property[1] = GUINT32_FROM_BE (property[1]);
929 //LOG ("\tproperty %d, payload %d\n", property[0], property[1]);
930 switch (property[0]) {
931 case PROP_OPACITY:
932 lfr = fread (data, sizeof(guint32), 1, f);
933 layer->opacity = GUINT32_FROM_BE(data[0]);
934 break;
935 case PROP_MODE:
936 lfr = fread (data, sizeof(guint32), 1, f);
937 layer->mode = GUINT32_FROM_BE (data[0]);
938 break;
939 case PROP_VISIBLE:
940 lfr = fread (data, sizeof(guint32), 1, f);
941 if (GUINT32_FROM_BE(data[0]) == 0) {
942 layer->visible = FALSE;
943 ignore_layer = TRUE;
944 }
945 break;
946 case PROP_APPLY_MASK:
947 lfr = fread (data, sizeof(guint32), 1, f);
948 if (GUINT32_FROM_BE(data[0]) == 1)
949 layer->apply_mask = TRUE;
950 break;
951 case PROP_OFFSETS:
952 lfr = fread(data, sizeof(gint32), 2, f);
953 layer->dx = GUINT32_FROM_BE(data[0]);
954 layer->dy = GUINT32_FROM_BE(data[1]);
955 break;
956 case PROP_FLOATING_SELECTION:
957 ignore_layer = TRUE;
958 default:
959 //skip the payload
960 fseek (f, property[1], SEEK_CUR);
961 break;
962 }
963 }
964
965 //Hierararchy Pointer
966 guint32 hptr;
967 lfr = fread (&hptr, sizeof(guint32), 1, f);
968 hptr = GUINT32_FROM_BE (hptr);
969 long pos1 = ftell (f);
970 //jump to hierarchy
971 fseek (f, hptr, SEEK_SET);
972
973 //Hierarchy w, h, bpp
974 lfr = fread (data, sizeof(guint32), 3, f);
975 data[0] = GUINT32_FROM_BE(data[0]);
976 data[1] = GUINT32_FROM_BE(data[1]);
977 data[2] = GUINT32_FROM_BE(data[2]);
978 //LOG ("\tHierarchy w:%d, h:%d, bpp:%d\n", data[0], data[1], data[2]);
979
980 guint32 lptr;
981 lfr = fread (&lptr, sizeof(guint32), 1, f);
982 layer->lptr = GUINT32_FROM_BE (lptr);
983 //Layer parsing is done at rendering time
984
985 //Here I could iterate over the unused dlevels and skip them
986
987 //rewind to the layer position
988 fseek (f, pos1, SEEK_SET);
989
990 //Mask Pointer
991 guint32 mptr;
992 lfr = fread (&mptr, sizeof(guint32), 1, f);
993 if (mptr)
994 mptr = GUINT32_FROM_BE(mptr);
995
996 //rewind to the previous position
997 fseek (f, pos, SEEK_SET);
998
999
1000 if (!ignore_layer)
1001 layers = g_list_prepend (layers, layer); //prepend so the layers are in a bottom-up order in the list
1002 else {
1003 g_free (layer);
1004 continue;
1005 }
1006
1007 if (!layer->apply_mask || !mptr)
1008 continue;
1009
1010 LOG ("\t\tthis layer has a mask\n");
1011 XcfChannel *mask = g_try_new (XcfChannel, 1);
1012 if (!mask) {
1013 g_set_error (error,
1014 GDK_PIXBUF_ERROR,
1015 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
1016 "Cannot allocate memory for loading XCF image");
1017 return NULL;
1018 }
1019
1020 mask->opacity = 0xff;
1021 mask->visible = TRUE;
1022
1023 //LOG ("\t\tchannel_ptr: %d\n", mptr);
1024 long mpos = ftell (f);
1025 //jump to the channel
1026 fseek(f, mptr, SEEK_SET);
1027
1028 //Channel w, h
1029 lfr = fread (data, sizeof(guint32), 2, f);
1030 data[0] = GUINT32_FROM_BE(data[0]);
1031 data[1] = GUINT32_FROM_BE(data[1]);
1032 LOG ("\t\tChannel w:%d, h:%d\n", data[0], data[1]);
1033
1034 //Channel name, ignore
1035 lfr = fread (&string_size, sizeof(guint32), 1, f);
1036 fseek (f, GUINT32_FROM_BE(string_size), SEEK_CUR);
1037
1038 //Channel properties
1039 while (1) {
1040 lfr = fread (property, sizeof(guint32), 2, f); //property and payload
1041 if (!property[0])
1042 break; //break on PROP_END
1043 property[0] = GUINT32_FROM_BE (property[0]);
1044 property[1] = GUINT32_FROM_BE (property[1]);
1045 //LOG ("\tproperty %d, payload %d\n", property[0], property[1]);
1046 switch (property[0]) {
1047 case PROP_OPACITY:
1048 lfr = fread (data, sizeof(guint32), 1, f);
1049 mask->opacity = GUINT32_FROM_BE(data[0]);
1050 break;
1051 case PROP_VISIBLE:
1052 lfr = fread (data, sizeof(guint32), 1, f);
1053 if (GUINT32_FROM_BE(data[0]) == 0)
1054 mask->visible = FALSE;
1055 break;
1056 default:
1057 //skip the payload
1058 fseek (f, property[1], SEEK_CUR);
1059 break;
1060 }
1061 }
1062
1063 //Hierararchy Pointer
1064 lfr = fread (&hptr, sizeof(guint32), 1, f);
1065 hptr = GUINT32_FROM_BE (hptr);
1066 long mpos1 = ftell (f);
1067 //jump to hierarchy
1068 fseek (f, hptr, SEEK_SET);
1069
1070 //Hierarchy w, h, bpp
1071 lfr = fread (data, sizeof(guint32), 3, f);
1072 data[0] = GUINT32_FROM_BE(data[0]);
1073 data[1] = GUINT32_FROM_BE(data[1]);
1074 data[2] = GUINT32_FROM_BE(data[2]);
1075 //LOG ("\tHierarchy w:%d, h:%d, bpp:%d\n", data[0], data[1], data[2]);
1076
1077 lfr = fread (&lptr, sizeof(guint32), 1, f);
1078 mask->lptr = GUINT32_FROM_BE (lptr);
1079 //level parsing is done at render time
1080
1081 if (mask->visible)
1082 layer->layer_mask = mask;
1083 else
1084 g_free (mask);
1085
1086 //rewind...
1087 fseek (f, mpos1, SEEK_SET);
1088
1089 //rewind to the previous position
1090 fseek (f, mpos, SEEK_SET);
1091 }
1092
1093 //Channels goes here, don't read
1094
1095 LOG("Done parsing\n");
1096
1097 //Compose the pixbuf
1098 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height);
1099 LOG ("pixbuf %d %d\n", gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf));
1100 LOG ("PrepareFunc\n");
1101 if (context && context->prepare_func)
1102 (* context->prepare_func) (pixbuf, NULL, context->user_data);
1103
1104 if (!pixbuf)
1105 g_set_error (error,
1106 GDK_PIXBUF_ERROR,
1107 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
1108 "Cannot allocate memory for loading XCF image");
1109
1110 gdk_pixbuf_fill (pixbuf, 0x00000000);
1111
1112 GList *current;
1113 gchar pixels[16384];
1114 for (current = g_list_first (layers); current; current = g_list_next(current)) {
1115 XcfLayer *layer = current->data;
1116 if (!layer->visible)
1117 continue;
1118
1119 fseek (f, layer->lptr, SEEK_SET);
1120 //Ignore Level w and h (same as hierarchy)
1121 fseek (f, 2 * sizeof(guint32), SEEK_CUR);
1122
1123
1124 //Iterate on the tiles
1125 guint32 tptr;
1126 int tile_id = 0;
1127 guchar *pixs = gdk_pixbuf_get_pixels (pixbuf);
1128 int rowstride = gdk_pixbuf_get_rowstride (pixbuf);
1129 int line_width = ceil ((layer->width) / 64.0);
1130
1131 while (1) {
1132 lfr = fread (&tptr, sizeof(guint32), 1, f);
1133 if (!tptr)
1134 break;
1135 tptr = GUINT32_FROM_BE(tptr);
1136 long lpos = ftell (f);
1137 fseek (f, tptr, SEEK_SET);
1138
1139 int ox = 64 * (tile_id % line_width);
1140 int oy = 64 * (tile_id / line_width);
1141 int tw = MIN (64, layer->width - ox);
1142 int th = MIN (64, layer->height - oy);
1143 ox += layer->dx;
1144 oy += layer->dy;
1145 //LOG("\tTile %d %d (%d %d) (%d %d)\n", tile_id, tptr, ox, oy, tw, th);
1146
1147 //if the tile doesn't intersect with the canvas, ignore
1148 if (ox + tw < 0 || oy + th < 0 || ox > (int)width || oy > (int)height ) {
1149 fseek (f, lpos, SEEK_SET);
1150 tile_id++;
1151 continue;
1152 }
1153
1154 //decompress
1155 if (compression == COMPRESSION_RLE)
1156 rle_decode (f, pixels, tw*th, layer->type);
1157 else {//COMPRESSION_NONE
1158 int channels;
1159 switch (layer->type) {
1160 case LAYERTYPE_RGB : channels = 3; break;
1161 case LAYERTYPE_RGBA: channels = 4; break;
1162 case LAYERTYPE_GRAYSCALE: channels = 1; break;
1163 case LAYERTYPE_GRAYSCALEA: channels = 2; break;
1164 case LAYERTYPE_INDEXED: channels = 1; break;
1165 case LAYERTYPE_INDEXEDA: channels = 2; break;
1166 }
1167 lfr = fread (pixels, sizeof(gchar), tw*th*channels, f);
1168 }
1169
1170 //pad to rgba
1171 to_rgba (pixels, tw*th, layer->type);
1172
1173 //apply mask
1174 if (layer->layer_mask)
1175 apply_mask (f, compression, pixels, tw*th, layer->layer_mask, tile_id);
1176
1177 //reduce the tile to its intersection with the canvas
1178 intersect_tile (pixels, width, height, &ox, &oy, &tw, &th);
1179
1180 //apply layer opacity
1181 apply_opacity (pixels, tw*th, layer->opacity);
1182
1183 //composite
1184 composite (pixs, rowstride, pixels, ox, oy, tw, th, layer->mode);
1185
1186 //notify
1187 if (context && context->update_func)
1188 (* context->update_func) (pixbuf, ox, oy, tw, th, context->user_data);
1189
1190
1191 fseek (f, lpos, SEEK_SET);
1192 tile_id++;
1193 }
1194 }
1195
1196 //free the layers and masks
1197 for (current = g_list_first (layers); current; current = g_list_next(current)) {
1198 XcfLayer *layer = current->data;
1199 if (layer->layer_mask)
1200 g_free (layer->layer_mask);
1201 }
1202 g_list_free (layers);
1203
1204 return pixbuf;
1205}
1206
1207/* Static Loader */
1208
1209static GdkPixbuf*
1210xcf_image_load (FILE *f, GError **error)
1211{
1212 size_t lfr;
1213 guchar buffer[4];
1214 lfr = fread (buffer, sizeof(guchar), 4, f);
1215 rewind (f);
1216 if (!strncmp (buffer, "BZh", 3)) { //Decompress the xcf.bz2 file to a temp file
1217 gchar *tempname;
1218 gint fd = g_file_open_tmp ("gdkpixbuf-xcf-tmp.XXXXXX", &tempname, NULL);
1219 if (fd < 0) {
1220 gint save_errno = errno;
1221 g_set_error (error,
1222 G_FILE_ERROR,
1223 g_file_error_from_errno (save_errno),
1224 "Failed to create temporary file when loading Xcf image");
1225 return NULL;
1226 }
1227
1228 FILE *file = fdopen (fd, "w+");
1229 if (!file) {
1230 gint save_errno = errno;
1231 g_set_error (error,
1232 G_FILE_ERROR,
1233 g_file_error_from_errno (save_errno),
1234 "Failed to open temporary file when loading Xcf image");
1235 g_free (tempname);
1236 return NULL;
1237 }
1238
1239 int bzerror;
1240 BZFILE *b = BZ2_bzReadOpen (&bzerror, f, 0, 0, NULL, 0);
1241 if (bzerror != BZ_OK) {
1242 BZ2_bzReadClose (&bzerror, b);
1243 fclose (file);
1244 g_unlink (tempname);
1245 g_free (tempname);
1246 g_set_error (error,
1247 GDK_PIXBUF_ERROR,
1248 GDK_PIXBUF_ERROR_FAILED,
1249 "Failed to initialize bz2 decompressor");
1250 return NULL;
1251 }
1252
1253 bzerror = BZ_OK;
1254 gchar buf [65536];
1255 gint nBuf;
1256 while (bzerror == BZ_OK) {
1257 nBuf = BZ2_bzRead (&bzerror, b, buf, 65536);
1258 if (bzerror == BZ_OK || bzerror == BZ_STREAM_END)
1259 if (fwrite (buf, sizeof (guchar), nBuf, file) != nBuf) {
1260 gint save_errno = errno;
1261 g_set_error (error,
1262 G_FILE_ERROR,
1263 g_file_error_from_errno (save_errno),
1264 "Failed to write to temporary file when loading Xcf image");
1265 BZ2_bzReadClose (&bzerror, b);
1266 fclose (file);
1267 g_unlink (tempname);
1268 g_free (tempname);
1269 return NULL;
1270 }
1271 }
1272
1273 if (bzerror != BZ_STREAM_END) {
1274 LOG ("bzerror = %d\n", bzerror);
1275 BZ2_bzReadClose (&bzerror, b);
1276 fclose (file);
1277 g_unlink (tempname);
1278 g_free (tempname);
1279 g_set_error (error,
1280 GDK_PIXBUF_ERROR,
1281 GDK_PIXBUF_ERROR_FAILED,
1282 "Decompression error while loading Xcf.bz2 file");
1283 return NULL;
1284 } else {
1285 LOG ("bzerror = %d\n", bzerror);
1286 BZ2_bzReadClose (&bzerror, b);
1287 }
1288
1289 fflush (file);
1290 rewind (file);
1291 g_unlink (tempname);
1292 g_free (tempname);
1293
1294 GdkPixbuf *pixbuf = xcf_image_load_real (file, NULL, error);
1295 fclose (file);
1296 return pixbuf;
1297#if GIO_2_23
1298 } else if (!strncmp (buffer, "\x1f\x8b", 2)) { //Decompress the .gz to a temp file
1299 GZlibDecompressor *compressor;
1300 GInputStream *input, *stream;
1301
1302 compressor = g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP);
1303 input = g_unix_input_stream_new (fileno (f), FALSE);
1304 stream = (GInputStream *) g_converter_input_stream_new (input, (GConverter *) (compressor));
1305 g_object_unref (compressor);
1306 g_object_unref (input);
1307
1308 gchar *tempname;
1309 gint fd = g_file_open_tmp ("gdkpixbuf-xcf-tmp.XXXXXX", &tempname, NULL);
1310 if (fd < 0) {
1311 gint save_errno = errno;
1312 g_set_error (error,
1313 G_FILE_ERROR,
1314 g_file_error_from_errno (save_errno),
1315 "Failed to create temporary file when loading Xcf image");
1316 return NULL;
1317 }
1318 GOutputStream *output;
1319 output = g_unix_output_stream_new (fd, TRUE);
1320 if (!g_output_stream_splice (G_OUTPUT_STREAM (output), stream,
1321 G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
1322 NULL, NULL)) {
1323 LOG ("splicing failed\n");
1324 g_set_error (error,
1325 GDK_PIXBUF_ERROR,
1326 GDK_PIXBUF_ERROR_FAILED,
1327 "Decompression error while loading Xcf.gz file");
1328 return NULL;
1329 }
1330
1331 FILE *file;
1332 file = fopen (tempname, "r");
1333 g_unlink (tempname);
1334 g_free (tempname);
1335
1336 GdkPixbuf *pixbuf = xcf_image_load_real (file, NULL, error);
1337 fclose (file);
1338
1339 return pixbuf;
1340#endif
1341 } else
1342 return xcf_image_load_real (f, NULL, error);
1343}
1344
1345
1346/* Progressive loader */
1347
1348/*
1349 * as the layers are packed top down in the xcf format, and we have to render them bottom-up,
1350 * we need the full file loaded to start rendering
1351 */
1352
1353static gpointer
1354xcf_image_begin_load (GdkPixbufModuleSizeFunc size_func,
1355 GdkPixbufModulePreparedFunc prepare_func,
1356 GdkPixbufModuleUpdatedFunc update_func,
1357 gpointer user_data,
1358 GError **error)
1359{
1360 LOG ("Begin\n");
1361 XcfContext *context;
1362 gint fd;
1363
1364 context = g_new (XcfContext, 1);
1365 context->size_func = size_func;
1366 context->prepare_func = prepare_func;
1367 context->update_func = update_func;
1368 context->user_data = user_data;
1369 context->type = FILETYPE_UNKNOWN;
1370 context->bz_stream = NULL;
1371#if GIO_2_23
1372 context->stream = NULL;
1373 context->input = NULL;
1374#endif
1375
1376 fd = g_file_open_tmp ("gdkpixbuf-xcf-tmp.XXXXXX", &context->tempname, NULL);
1377
1378 if (fd < 0) {
1379 g_free (context);
1380 return NULL;
1381 }
1382
1383 context->file = fdopen (fd, "w+");
1384 if (!context->file) {
1385 g_free (context->tempname);
1386 g_free (context);
1387 return NULL;
1388 }
1389
1390 return context;
1391}
1392
1393static gboolean
1394xcf_image_stop_load (gpointer data, GError **error)
1395{
1396 LOG ("Stop\n");
1397 XcfContext *context = (XcfContext*) data;
1398 gboolean retval = TRUE;
1399
1400 g_return_val_if_fail (data, TRUE);
1401
1402 if (context->type == FILETYPE_XCF ||
1403 context->type == FILETYPE_XCF_BZ2) {
1404 fflush (context->file);
1405 rewind (context->file);
1406 if (context->tempname) {
1407 g_unlink (context->tempname);
1408 g_free (context->tempname);
1409 context->tempname = NULL;
1410 }
1411 GdkPixbuf *pixbuf = xcf_image_load_real (context->file, context, error);
1412 if (!pixbuf)
1413 retval = FALSE;
1414 else
1415 g_object_unref (pixbuf);
1416#if GIO_2_23
1417 } else if (context->type == FILETYPE_XCF_GZ) {
1418 g_object_unref (context->input);
1419 context->input = NULL;
1420
1421 gchar buf [65536];
1422 gsize count;
1423 GError *err = NULL;
1424 while ((count = g_input_stream_read (G_INPUT_STREAM (context->stream),
1425 &buf, sizeof (buf), NULL, error)) > 0) {
1426 if (fwrite (buf, sizeof (gchar), count, context->file) != count) {
1427 gint save_errno = errno;
1428 g_set_error (error,
1429 G_FILE_ERROR,
1430 g_file_error_from_errno (save_errno),
1431 "Failed to write to temporary file when loading Xcf image");
1432 retval = FALSE;
1433 goto bail;
1434 }
1435 }
1436 if (count == -1) {
1437 /* error is already set */
1438 retval = FALSE;
1439 goto bail;
1440 }
1441#endif
1442 } else {
1443 g_assert_not_reached ();
1444 }
1445
1446 fflush (context->file);
1447 rewind (context->file);
1448 if (context->tempname) {
1449 g_unlink (context->tempname);
1450 g_free (context->tempname);
1451 context->tempname = NULL;
1452 }
1453 GdkPixbuf *pixbuf = xcf_image_load_real (context->file, context, error);
1454 if (!pixbuf)
1455 retval = FALSE;
1456 else
1457 g_object_unref (pixbuf);
1458
1459bail:
1460#if GIO_2_23
1461 if (context->stream)
1462 g_object_unref (context->stream);
1463#endif
1464 fclose (context->file);
1465 if (context->tempname) {
1466 g_unlink (context->tempname);
1467 g_free (context->tempname);
1468 }
1469 g_free (context);
1470
1471 return retval;
1472}
1473
1474static gboolean
1475xcf_image_load_increment (gpointer data,
1476 const guchar *buf,
1477 guint size,
1478 GError **error)
1479{
1480 LOG ("Increment %d\n", size);
1481 g_return_val_if_fail (data, FALSE);
1482 XcfContext *context = (XcfContext*) data;
1483
1484 if (context->type == FILETYPE_STREAMCLOSED) { //end of compressed stream reached
1485 g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE, "end of compressed stream reached before the end of the file");
1486 return FALSE;
1487 }
1488
1489 if (context->type == FILETYPE_UNKNOWN) { // first chunk
1490 if (!strncmp (buf, "gimp xcf ", 9))
1491 context->type = FILETYPE_XCF;
1492 else if (!strncmp (buf, "BZh", 3)) {
1493 context->type = FILETYPE_XCF_BZ2;
1494
1495 //Initialize bzlib
1496 context->bz_stream = g_new (bz_stream, 1);
1497 context->bz_stream->bzalloc = NULL;
1498 context->bz_stream->bzfree = NULL;
1499 context->bz_stream->opaque = NULL;
1500
1501 int ret = BZ2_bzDecompressInit (context->bz_stream, 0, 0); //Verbosity = 0, don't optimize for memory usage
1502 if (ret != BZ_OK) {
1503 g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, "Failed to initialize bz2 decompressor");
1504 g_free(context->bz_stream);
1505 context->bz_stream = NULL;
1506 return FALSE;
1507 }
1508#if GIO_2_23
1509 } else if (!strncmp (buf, "\x1f\x8b", 2)) {
1510 GZlibDecompressor *compressor;
1511
1512 context->type = FILETYPE_XCF_GZ;
1513 compressor = g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP);
1514
1515 context->input = g_memory_input_stream_new ();
1516 context->stream = (GInputStream *) g_converter_input_stream_new (context->input, (GConverter *) (compressor));
1517 g_object_unref (compressor);
1518#endif
1519 }
1520 LOG ("File type %d\n", context->type);
1521 }
1522
1523 gchar *outbuf;
1524 switch (context->type) {
1525 case FILETYPE_XCF_BZ2:
1526 outbuf = g_new (gchar, 65536);
1527 context->bz_stream->next_in = (gchar*)buf;
1528 context->bz_stream->avail_in = size;
1529 while (context->bz_stream->avail_in > 0) {
1530 context->bz_stream->next_out = outbuf;
1531 context->bz_stream->avail_out = 65536;
1532 int ret = BZ2_bzDecompress (context->bz_stream);
1533 switch (ret) {
1534 case BZ_OK:
1535 break;
1536 case BZ_STREAM_END:
1537 LOG ("End of bz stream\n");
1538 BZ2_bzDecompressEnd (context->bz_stream);
1539 context->type = FILETYPE_STREAMCLOSED;
1540 break;
1541 default:
1542 BZ2_bzDecompressEnd (context->bz_stream);
1543 context->type = FILETYPE_STREAMCLOSED;
1544 g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, "Failed to decompress");
1545 g_free(outbuf);
1546 context->bz_stream->next_out = NULL;
1547 outbuf = NULL;
1548 g_free(context->bz_stream);
1549 context->bz_stream = NULL;
1550 return FALSE;
1551 }
1552
1553 int total_out = 65536 - context->bz_stream->avail_out;
1554 LOG ("Wrote %d to file %s\n", total_out, context->tempname);
1555 if (fwrite (outbuf, sizeof (guchar), total_out, context->file) != total_out) {
1556 gint save_errno = errno;
1557 g_set_error (error,
1558 G_FILE_ERROR,
1559 g_file_error_from_errno (save_errno),
1560 "Failed to write to temporary file when loading Xcf image");
1561 g_free(outbuf);
1562 context->bz_stream->next_out = NULL;
1563 outbuf = NULL;
1564 g_free(context->bz_stream);
1565 context->bz_stream = NULL;
1566 return FALSE;
1567 }
1568 }
1569 g_free(outbuf);
1570 context->bz_stream->next_out = NULL;
1571 outbuf = NULL;
1572 if (context->type == FILETYPE_STREAMCLOSED)
1573 {
1574 g_free(context->bz_stream);
1575 context->bz_stream = NULL;
1576 }
1577 break;
1578#if GIO_2_23
1579 case FILETYPE_XCF_GZ:
1580 g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (context->input),
1581 buf, size, NULL);
1582 break;
1583#endif
1584 case FILETYPE_XCF:
1585 default:
1586 if (fwrite (buf, sizeof (guchar), size, context->file) != size) {
1587 gint save_errno = errno;
1588 g_set_error (error,
1589 G_FILE_ERROR,
1590 g_file_error_from_errno (save_errno),
1591 "Failed to write to temporary file when loading Xcf image");
1592 return FALSE;
1593 }
1594 break;
1595 }
1596
1597 return TRUE;
1598}
1599
1600
1601#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
1602MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
1603{
1604 module->load = xcf_image_load;
1605 module->begin_load = xcf_image_begin_load;
1606 module->stop_load = xcf_image_stop_load;
1607 module->load_increment = xcf_image_load_increment;
1608}
1609
1610MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
1611{
1612 static GdkPixbufModulePattern signature[] = {
1613 { "gimp xcf", NULL, 100 },
1614 { "BZh", NULL, 80 },
1615#if GIO_2_23
1616 { "\x1f\x8b", NULL, 80 },
1617#endif
1618 { NULL, NULL, 0 }
1619 };
1620 static gchar * mime_types[] = {
1621 "image/x-xcf",
1622 "image/x-compressed-xcf",
1623 NULL
1624 };
1625 static gchar * extensions[] = {
1626 "xcf",
1627 "xcf.bz2",
1628#if GIO_2_23
1629 "xcf.gz",
1630#endif
1631 NULL
1632 };
1633
1634 info->name = "xcf";
1635 info->signature = signature;
1636 info->description = "The XCF (The Gimp) image format";
1637 info->mime_types = mime_types;
1638 info->extensions = extensions;
1639 info->flags = 0;
1640 info->license = "LGPL";
1641}
16420
=== modified file 'src/plugin-pixbuf/plugin-pixbuf.h'
--- src/plugin-pixbuf/plugin-pixbuf.h 2010-05-31 14:57:37 +0000
+++ src/plugin-pixbuf/plugin-pixbuf.h 2014-12-26 04:45:12 +0000
@@ -48,12 +48,6 @@
48}48}
49g_slist_free(suportedFormats);49g_slist_free(suportedFormats);
5050
51PluginManager::register_filetype("image/vnd.adobe.photoshop", 1);
52PluginManager::register_filetype("image/x-xcf", 1);
53PluginManager::register_filetype("image/x-compressed-xcf", 1);
54//PluginManager::register_filetype("image/x-icns", 2);
55//PluginManager::register_filetype("image/jpeg", 1); //TODO: do we need this?
56
57#endif51#endif
5852
59#endif53#endif

Subscribers

People subscribed via source and target branches