a915a015e1bc8eedf6913fb9f550ef3435dc1d0b
[geeqie.git] / src / image_load_psd.c
1 /*
2  * Copyright (C) 20019 - The Geeqie Team
3  *
4  * Author: Colin Clark
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  *
20  * 
21  * Derived from:
22  * 
23  * GdkPixbuf library - PSD image loader
24  *
25  * Copyright (C) 2008 Jan Dudek
26  *
27  * Authors: Jan Dudek <jd@jandudek.com>
28  *
29  * This library is free software; you can redistribute it and/or
30  * modify it under the terms of the GNU Lesser General Public
31  * License as published by the Free Software Foundation; either
32  * version 2 of the License, or (at your option) any later version.
33  *
34  * This library is distributed in the hope that it will be useful,
35  * but WITHOUT ANY WARRANTY; without even the implied warranty of
36  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
37  * Lesser General Public License for more
38  * You should have received a copy of the GNU Lesser General Public
39  * License along with this library; if not, write to the
40  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
41  * Boston, MA 02111-1307, USA.
42  */
43
44 /*
45  * TODO
46  * - report errors from parse_psd_header
47  * - other color modes (CMYK at least)
48  * - i18n
49  */
50
51 #include "main.h"
52
53 #include "image-load.h"
54 #include "image_load_psd.h"
55
56 typedef struct _ImageLoaderPSD ImageLoaderPSD;
57 struct _ImageLoaderPSD {
58         ImageLoaderBackendCbAreaUpdated area_updated_cb;
59         ImageLoaderBackendCbSize size_cb;
60         ImageLoaderBackendCbAreaPrepared area_prepared_cb;
61         gpointer data;
62         GdkPixbuf *pixbuf;
63         guint requested_width;
64         guint requested_height;
65         gboolean abort;
66 };
67
68 typedef struct
69 {
70         guchar  signature[4];  /* file ID, always "8BPS" */
71         guint16 version;       /* version number, always 1 */
72         guchar  resetved[6];
73         guint16 channels;      /* number of color channels (1-24) */
74         guint32 rows;          /* height of image in pixels (1-30000) */
75         guint32 columns;       /* width of image in pixels (1-30000) */
76         guint16 depth;         /* number of bits per channel (1, 8, 16 or 32) */
77         guint16 color_mode;    /* color mode as defined below */
78 } PsdHeader;
79
80 #define PSD_HEADER_SIZE 26
81
82 typedef enum
83 {
84         PSD_MODE_MONO = 0,
85         PSD_MODE_GRAYSCALE = 1,
86         PSD_MODE_INDEXED = 2,
87         PSD_MODE_RGB = 3,
88         PSD_MODE_CMYK = 4,
89         PSD_MODE_MULTICHANNEL = 7,
90         PSD_MODE_DUOTONE = 8,
91         PSD_MODE_LAB = 9,
92 } PsdColorMode;
93
94 typedef enum
95 {
96         PSD_COMPRESSION_NONE = 0,
97         PSD_COMPRESSION_RLE = 1
98 } PsdCompressionType;
99
100 typedef enum
101 {
102         PSD_STATE_HEADER,
103         PSD_STATE_COLOR_MODE_BLOCK,
104         PSD_STATE_RESOURCES_BLOCK,
105         PSD_STATE_LAYERS_BLOCK,
106         PSD_STATE_COMPRESSION,
107         PSD_STATE_LINES_LENGTHS,
108         PSD_STATE_CHANNEL_DATA,
109         PSD_STATE_DONE
110 } PsdReadState;
111
112 typedef struct
113 {
114         PsdReadState       state;
115         
116         GdkPixbuf*                  pixbuf;
117         gpointer                    user_data;
118
119         guchar*            buffer;
120         guint              bytes_read;
121         guint32            bytes_to_skip;
122         gboolean           bytes_to_skip_known;
123
124         guint32            width;
125         guint32            height;
126         guint16            channels;
127         guint16            depth;
128         guint16            depth_bytes;
129         PsdColorMode       color_mode;
130         PsdCompressionType compression;
131
132         guchar**           ch_bufs;       /* channels buffers */
133         guint              curr_ch;       /* current channel */
134         guint              curr_row;
135         guint              pos;
136         guint16*           lines_lengths;
137         gboolean           finalized;
138 } PsdContext;
139
140
141 static guint16
142 read_uint16 (guchar* buf)
143 {
144         return (buf[0] << 8) | buf[1];
145 }
146
147 static guint32
148 read_uint32 (guchar* buf)
149 {
150         return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
151 }
152
153
154 /*
155  * Parse Psdheader from buffer
156  *
157  * str is expected to be at least PSD_HEADER_SIZE long
158  */
159 static PsdHeader
160 psd_parse_header (guchar* str)
161 {
162         PsdHeader hd;
163         
164         memcpy(hd.signature, str, 4);
165         hd.version = read_uint16(str + 4);
166         hd.channels = read_uint16(str + 12);
167         hd.rows = read_uint32(str + 14);
168         hd.columns = read_uint32(str + 18);
169         hd.depth = read_uint16(str + 22);
170         hd.color_mode = read_uint16(str + 24);
171
172         return hd;
173 }
174
175 /*
176  * Attempts to read bytes_needed bytes from data and stores them in buffer.
177  *
178  * Returns true if there were enough bytes and false otherwise
179  * (which means we need to call feed_buffer again)
180  */
181 static gboolean
182 feed_buffer (guchar*        buffer,
183              guint*         bytes_read,
184              const guchar** data,
185              guint*         size,
186              guint          bytes_needed)
187 {
188         gint how_many = bytes_needed - *bytes_read;
189         if (how_many > *size) {
190                 how_many = *size;
191         }
192         memcpy(buffer + *bytes_read, *data, how_many);
193         *bytes_read += how_many;
194         *data += how_many;
195         *size -= how_many;
196         return (*bytes_read == bytes_needed);
197 }
198
199 /*
200  * Attempts to read size of the block and then skip this block.
201  *
202  * Returns true when finishes consuming block data, otherwise false
203  * (false means we need to call skip_block again)
204  */
205 static gboolean
206 skip_block (PsdContext* context, const guchar** data, guint* size)
207 {
208         static guint counter;
209
210         if (!context->bytes_to_skip_known) {
211                 context->bytes_read = 0;
212                 if (feed_buffer(context->buffer, &context->bytes_read, data, size, 4)) {
213                         context->bytes_to_skip = read_uint32(context->buffer);
214                         context->bytes_to_skip_known = TRUE;
215                         counter = 0;
216                 } else {
217                         return FALSE;
218                 }
219         }
220         if (*size < context->bytes_to_skip) {
221                 *data += *size;
222                 context->bytes_to_skip -= *size;
223                 counter += *size;
224                 *size = 0;
225                 return FALSE;
226         } else {
227                 counter += context->bytes_to_skip;
228                 *size -= context->bytes_to_skip;
229                 *data += context->bytes_to_skip;
230                 return TRUE;
231         }
232 }
233
234 /*
235  * Decodes RLE-compressed data
236  */
237 static void
238 decompress_line(const guchar* src, guint line_length, guchar* dest)
239 {
240         guint16 bytes_read = 0;
241         int k;
242         while (bytes_read < line_length) {
243                 gchar byte = src[bytes_read];
244                 ++bytes_read;
245         
246                 if (byte == -128) {
247                         continue;
248                 } else if (byte > -1) {
249                         gint count = byte + 1;
250                 
251                         /* copy next count bytes */
252                         for (k = 0; k < count; ++k) {
253                                 *dest = src[bytes_read];
254                                 ++dest;
255                                 ++bytes_read;
256                         }
257                 } else {
258                         gint count = -byte + 1;
259                 
260                         /* copy next byte count times */
261                         guchar next_byte = src[bytes_read];
262                         ++bytes_read; 
263                         for (k = 0; k < count; ++k) {
264                                 *dest = next_byte;
265                                 ++dest;
266                         }
267                 }
268         }
269 }
270
271 static void
272 reset_context_buffer(PsdContext* ctx)
273 {
274         ctx->bytes_read = 0;
275         ctx->bytes_to_skip = 0;
276         ctx->bytes_to_skip_known = FALSE;
277 }
278
279 static void free_context(PsdContext *ctx)
280 {
281         g_free(ctx->buffer);
282         g_free(ctx->lines_lengths);
283         if (ctx->ch_bufs) {
284                 int i;
285                 for (i = 0; i < ctx->channels; i++) {
286                         g_free(ctx->ch_bufs[i]);
287                 }
288         }
289         g_free(ctx);
290 }
291
292 static gboolean image_loader_psd_load(gpointer loader, const guchar *buf, gsize count, GError **error)
293 {
294         ImageLoaderPSD *ld = (ImageLoaderPSD *) loader;
295         PsdContext* ctx = g_new0(PsdContext, 1);
296         int i, j;
297         guint size = count;
298
299         ctx->state = PSD_STATE_HEADER;
300
301         /* we'll allocate larger buffer once we know image size */
302         ctx->buffer = g_malloc(PSD_HEADER_SIZE);
303         reset_context_buffer(ctx);
304
305         ctx->ch_bufs = NULL;
306         ctx->curr_ch = 0;
307         ctx->curr_row = 0;
308         ctx->pos = 0;
309         ctx->lines_lengths = NULL;
310         ctx->finalized = FALSE;
311
312         while (size > 0) {
313                 switch (ctx->state) {
314                         case PSD_STATE_HEADER:
315                                 if (feed_buffer(
316                                                 ctx->buffer, &ctx->bytes_read,
317                                                 &buf, &size, PSD_HEADER_SIZE))
318                                 {
319                                         PsdHeader hd = psd_parse_header(ctx->buffer);
320
321                                         ctx->width = hd.columns;
322                                         ctx->height = hd.rows;
323                                         ctx->channels = hd.channels;
324                                         ctx->depth = hd.depth;
325                                         ctx->depth_bytes = (ctx->depth/8 > 0 ? ctx->depth/8 : 1);
326                                         ctx->color_mode = hd.color_mode;
327                                         
328                                         if (ctx->color_mode != PSD_MODE_RGB
329                                             && ctx->color_mode != PSD_MODE_GRAYSCALE
330                                             && ctx->color_mode != PSD_MODE_CMYK
331                                             && ctx->color_mode != PSD_MODE_DUOTONE
332                                         ) {
333                                                 log_printf("warning: psd - Unsupported color mode\n");
334                                                 free_context(ctx);
335                                                 return FALSE;
336                                         }
337                                         
338                                         if (ctx->depth != 8 && ctx->depth != 16) {
339                                                 log_printf("warning: psd - Unsupported color depth\n");
340                                                 free_context(ctx);
341                                                 return FALSE;
342                                         }
343
344                                         /* we need buffer that can contain one channel data for one
345                                            row in RLE compressed format. 2*width should be enough */
346                                         g_free(ctx->buffer);
347                                         ctx->buffer = g_malloc(ctx->width * 2 * ctx->depth_bytes);
348                                         
349                                         /* this will be needed for RLE decompression */
350                                         ctx->lines_lengths =
351                                                 g_malloc(2 * ctx->channels * ctx->height);
352                                         
353                                         ctx->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
354                                                 FALSE, 8, ctx->width, ctx->height);
355
356                                         if (ctx->lines_lengths == NULL || ctx->buffer == NULL ||
357                                                 ctx->pixbuf == NULL)
358                                         {
359                                                 log_printf("warning: Insufficient memory to load PSD image file\n");
360                                                 free_context(ctx);
361                                                 return FALSE;
362                                         }
363                                         
364                                         /* create separate buffers for each channel */
365                                         ctx->ch_bufs = g_malloc(sizeof(guchar*) * ctx->channels);
366                                         for (i = 0; i < ctx->channels; i++) {
367                                                 ctx->ch_bufs[i] =
368                                                         g_malloc(ctx->width*ctx->height*ctx->depth_bytes);
369
370                                                 if (ctx->ch_bufs[i] == NULL) {
371                                                 log_printf("warning: Insufficient memory to load PSD image file\n");
372                                                 free_context(ctx);
373                                                 return FALSE;
374                                                 }       
375                                         }
376
377                                         ctx->state = PSD_STATE_COLOR_MODE_BLOCK;
378                                         reset_context_buffer(ctx);
379                                 }
380                                 break;
381                         case PSD_STATE_COLOR_MODE_BLOCK:
382                                 if (skip_block(ctx, &buf, &size)) {
383                                         ctx->state = PSD_STATE_RESOURCES_BLOCK;
384                                         reset_context_buffer(ctx);
385                                 }
386                                 break;
387                         case PSD_STATE_RESOURCES_BLOCK:
388                                 if (skip_block(ctx, &buf, &size)) {
389                                         ctx->state = PSD_STATE_LAYERS_BLOCK;
390                                         reset_context_buffer(ctx);
391                                 }
392                                 break;
393                         case PSD_STATE_LAYERS_BLOCK:
394                                 if (skip_block(ctx, &buf, &size)) {
395                                         ctx->state = PSD_STATE_COMPRESSION;
396                                         reset_context_buffer(ctx);
397                                 }
398                                 break;
399                         case PSD_STATE_COMPRESSION:
400                                 if (feed_buffer(ctx->buffer, &ctx->bytes_read, &buf, &size, 2))
401                                 {
402                                         ctx->compression = read_uint16(ctx->buffer);
403
404                                         if (ctx->compression == PSD_COMPRESSION_RLE) {
405                                                 ctx->state = PSD_STATE_LINES_LENGTHS;
406                                                 reset_context_buffer(ctx);
407                                         } else if (ctx->compression == PSD_COMPRESSION_NONE) {
408                                                 ctx->state = PSD_STATE_CHANNEL_DATA;
409                                                 reset_context_buffer(ctx);
410                                         } else {
411                                                 log_printf("warning: psd - Unsupported compression type\n");
412                                                 return FALSE;
413                                         }
414                                 }
415                                 break;
416                         case PSD_STATE_LINES_LENGTHS:
417                                 if (feed_buffer(
418                                                 (guchar*) ctx->lines_lengths, &ctx->bytes_read, &buf,
419                                                  &size, 2 * ctx->height * ctx->channels))
420                                 {
421                                         /* convert from different endianness */
422                                         for (i = 0; i < ctx->height * ctx->channels; i++) {
423                                                 ctx->lines_lengths[i] = read_uint16(
424                                                         (guchar*) &ctx->lines_lengths[i]);
425                                         }
426                                         ctx->state = PSD_STATE_CHANNEL_DATA;
427                                         reset_context_buffer(ctx);
428                                 }
429                                 break;
430                         case PSD_STATE_CHANNEL_DATA:
431                                 {
432                                         guint line_length = ctx->width * ctx->depth_bytes;
433                                         if (ctx->compression == PSD_COMPRESSION_RLE) {
434                                                 line_length = ctx->lines_lengths[
435                                                         ctx->curr_ch * ctx->height + ctx->curr_row];
436                                         }
437                                         
438                                         if (feed_buffer(ctx->buffer, &ctx->bytes_read, &buf, &size,
439                                                         line_length))
440                                         {
441                                                 if (ctx->compression == PSD_COMPRESSION_RLE) {
442                                                         decompress_line(ctx->buffer, line_length,
443                                                                 ctx->ch_bufs[ctx->curr_ch] + ctx->pos
444                                                         );
445                                                 } else {
446                                                         memcpy(ctx->ch_bufs[ctx->curr_ch] + ctx->pos,
447                                                                 ctx->buffer, line_length);
448                                                 }
449                                                 
450                                                 ctx->pos += ctx->width * ctx->depth_bytes;
451                                                 ++ctx->curr_row;
452                                         
453                                                 if (ctx->curr_row >= ctx->height) {
454                                                         ++ctx->curr_ch;
455                                                         ctx->curr_row = 0;
456                                                         ctx->pos = 0;
457                                                         if (ctx->curr_ch >= ctx->channels) {
458                                                                 ctx->state = PSD_STATE_DONE;
459                                                         }
460                                                 }
461                                                 
462                                                 reset_context_buffer(ctx);
463                                         }
464                                 }
465                                 break;
466                         case PSD_STATE_DONE:
467                         default:
468                                 size = 0;
469                                 break;
470                 }
471         }
472         
473         if (ctx->state == PSD_STATE_DONE && !ctx->finalized) {
474                 /* convert or copy channel buffers to our GdkPixbuf */
475                 guchar* pixels = gdk_pixbuf_get_pixels(ctx->pixbuf);
476                 guint b = ctx->depth_bytes;
477
478                 if (ctx->color_mode == PSD_MODE_RGB) {
479                         for (i = 0; i < ctx->height; i++) {
480                                 for (j = 0; j < ctx->width; j++) {
481                                         pixels[3*j+0] = ctx->ch_bufs[0][ctx->width*i*b + j*b];
482                                         pixels[3*j+1] = ctx->ch_bufs[1][ctx->width*i*b + j*b];
483                                         pixels[3*j+2] = ctx->ch_bufs[2][ctx->width*i*b + j*b];
484                                 }
485                                 pixels += gdk_pixbuf_get_rowstride(ctx->pixbuf);
486                         }
487                 } else if (ctx->color_mode == PSD_MODE_GRAYSCALE ||
488                            ctx->color_mode == PSD_MODE_DUOTONE)
489                 {
490                         for (i = 0; i < ctx->height; i++) {
491                                 for (j = 0; j < ctx->width; j++) {
492                                         pixels[3*j+0] = pixels[3*j+1] = pixels[3*j+2] =
493                                                 ctx->ch_bufs[0][ctx->width*i*b + j*b];
494                                 }
495                                 pixels += gdk_pixbuf_get_rowstride(ctx->pixbuf);
496                         }
497                 } else if (ctx->color_mode == PSD_MODE_CMYK) {
498                         /* unfortunately, this doesn't work 100% correctly...
499                            CMYK-RGB conversion distorts colors significantly  */
500                 
501                         guchar* pixels = gdk_pixbuf_get_pixels(ctx->pixbuf);
502                         for (i = 0; i < ctx->height; i++) {
503                                 for (j = 0; j < ctx->width; j++) {
504                                         double c = 1.0 -
505                                                 (double) ctx->ch_bufs[0][ctx->width*i + j] / 255.0;
506                                         double m = 1.0 -
507                                                 (double) ctx->ch_bufs[1][ctx->width*i + j] / 255.0;
508                                         double y = 1.0 -
509                                                 (double) ctx->ch_bufs[2][ctx->width*i + j] / 255.0;
510                                         double k = 1.0 -
511                                                 (double) ctx->ch_bufs[3][ctx->width*i + j] / 255.0;
512                                         
513                                         pixels[3*j+0] = (1.0 - (c * (1.0 - k) + k)) * 255.0;
514                                         pixels[3*j+1] = (1.0 - (m * (1.0 - k) + k)) * 255.0;
515                                         pixels[3*j+2] = (1.0 - (y * (1.0 - k) + k)) * 255.0;
516                                 }
517                                 pixels += gdk_pixbuf_get_rowstride(ctx->pixbuf);
518                         }
519                 }
520                 ctx->finalized = TRUE;
521                 ld->pixbuf = ctx->pixbuf;
522                 ld->area_updated_cb(loader, 0, 0, ctx->width, ctx->height, ld->data);
523                 free_context(ctx);
524
525                 return TRUE;
526         }
527
528         free_context(ctx);
529         return FALSE;
530 }
531
532 /* ------- Geeqie ------------ */
533
534 static gpointer image_loader_psd_new(ImageLoaderBackendCbAreaUpdated area_updated_cb, ImageLoaderBackendCbSize size_cb, ImageLoaderBackendCbAreaPrepared area_prepared_cb, gpointer data)
535 {
536         ImageLoaderPSD *loader = g_new0(ImageLoaderPSD, 1);
537         loader->area_updated_cb = area_updated_cb;
538         loader->size_cb = size_cb;
539         loader->area_prepared_cb = area_prepared_cb;
540         loader->data = data;
541         return (gpointer) loader;
542 }
543
544 static void image_loader_psd_set_size(gpointer loader, int width, int height)
545 {
546         ImageLoaderPSD *ld = (ImageLoaderPSD *) loader;
547         ld->requested_width = width;
548         ld->requested_height = height;
549 }
550
551 static GdkPixbuf* image_loader_psd_get_pixbuf(gpointer loader)
552 {
553         ImageLoaderPSD *ld = (ImageLoaderPSD *) loader;
554         return ld->pixbuf;
555 }
556
557 static gchar* image_loader_psd_get_format_name(gpointer loader)
558 {
559         return g_strdup("psd");
560 }
561
562 static gchar** image_loader_psd_get_format_mime_types(gpointer loader)
563 {
564         static gchar *mime[] = {"application/psd", NULL};
565         return g_strdupv(mime);
566 }
567
568 static gboolean image_loader_psd_close(gpointer loader, GError **error)
569 {
570         return TRUE;
571 }
572
573 static void image_loader_psd_abort(gpointer loader)
574 {
575         ImageLoaderPSD *ld = (ImageLoaderPSD *) loader;
576         ld->abort = TRUE;
577 }
578
579 static void image_loader_psd_free(gpointer loader)
580 {
581         ImageLoaderPSD *ld = (ImageLoaderPSD *) loader;
582         if (ld->pixbuf) g_object_unref(ld->pixbuf);
583         g_free(ld);
584 }
585
586 void image_loader_backend_set_psd(ImageLoaderBackend *funcs)
587 {
588         funcs->loader_new = image_loader_psd_new;
589         funcs->set_size = image_loader_psd_set_size;
590         funcs->load = image_loader_psd_load;
591         funcs->write = NULL;
592         funcs->get_pixbuf = image_loader_psd_get_pixbuf;
593         funcs->close = image_loader_psd_close;
594         funcs->abort = image_loader_psd_abort;
595         funcs->free = image_loader_psd_free;
596         funcs->get_format_name = image_loader_psd_get_format_name;
597         funcs->get_format_mime_types = image_loader_psd_get_format_mime_types;
598 }
599 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */