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