summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--io-psd.c472
1 files changed, 459 insertions, 13 deletions
diff --git a/io-psd.c b/io-psd.c
index 664d42f..275f66a 100644
--- a/io-psd.c
+++ b/io-psd.c
@@ -20,8 +20,17 @@
20 * Boston, MA 02111-1307, USA. 20 * Boston, MA 02111-1307, USA.
21 */ 21 */
22 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
28 * - ...
29 */
30
23#include <stdlib.h> 31#include <stdlib.h>
24#include <stdio.h> 32#include <stdio.h>
33#include <string.h>
25#include <gdk-pixbuf/gdk-pixbuf-io.h> 34#include <gdk-pixbuf/gdk-pixbuf-io.h>
26#include <glib/gstdio.h> 35#include <glib/gstdio.h>
27 36
@@ -31,13 +40,15 @@ typedef struct
31 guchar signature[4]; /* file ID, always "8BPS" */ 40 guchar signature[4]; /* file ID, always "8BPS" */
32 guint16 version; /* version number, always 1 */ 41 guint16 version; /* version number, always 1 */
33 guchar reserved[6]; 42 guchar reserved[6];
34 guint8 channels; /* number of color channels (1-24) */ 43 guint16 channels; /* number of color channels (1-24) */
35 guint32 rows; /* height of image in pixels (1-30000) */ 44 guint32 rows; /* height of image in pixels (1-30000) */
36 guint32 columns; /* width of image in pixels (1-30000) */ 45 guint32 columns; /* width of image in pixels (1-30000) */
37 guint16 depth; /* number of bits per channel (1, 8, and 16) */ 46 guint16 depth; /* number of bits per channel (1, 8, and 16) */
38 guint16 color_mode; /* color mode as defined below */ 47 guint16 color_mode; /* color mode as defined below */
39} PsdHeader; 48} PsdHeader;
40 49
50#define PSD_HEADER_SIZE 26
51
41typedef enum 52typedef enum
42{ 53{
43 PSD_MODE_MONO = 0, 54 PSD_MODE_MONO = 0,
@@ -56,6 +67,49 @@ typedef enum
56 PSD_COMPRESSION_RLE = 1 67 PSD_COMPRESSION_RLE = 1
57} PsdCompressionType; 68} PsdCompressionType;
58 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 //PsdHeader hd;
99 guint32 width; /* width of image in pixels (1-30000) */
100 guint32 height; /* height of image in pixels (1-30000) */
101 guint16 channels; /* number of color channels (1-24) */
102 guint16 depth; /* number of bits per channel (1, 8, and 16) */
103 PsdColorMode color_mode;
104 PsdCompressionType compression;
105
106 guchar** channels_buffers;
107 guint current_channel;
108 guint current_row;
109 guint position; // ? redundant?
110 guint16* lines_lengths;
111} PsdContext;
112
59static guint16 113static guint16
60read_uint16 (FILE *fp) 114read_uint16 (FILE *fp)
61{ 115{
@@ -76,6 +130,19 @@ read_uint32 (FILE *fp)
76 return t; 130 return t;
77} 131}
78 132
133static guint16
134parse_uint16 (guchar* buf)
135{
136 return (buf[0] << 8) | buf[1];
137}
138
139static guint32
140parse_uint32 (guchar* buf)
141{
142 return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
143}
144
145
79static PsdHeader 146static PsdHeader
80psd_read_header (FILE *fp) 147psd_read_header (FILE *fp)
81{ 148{
@@ -106,6 +173,28 @@ psd_read_header (FILE *fp)
106 return hd; 173 return hd;
107} 174}
108 175
176/*
177 * Parse Psdheader from buffer
178 * str is expected to be at least PSD_HEADER_SIZE long
179 */
180static PsdHeader
181psd_parse_header (guchar* str)
182{
183 PsdHeader hd;
184
185 memcpy(hd.signature, str, 4);
186 hd.version = parse_uint16(str + 4);
187 hd.channels = parse_uint16(str + 12);
188 hd.rows = parse_uint32(str + 14);
189 hd.columns = parse_uint32(str + 18);
190 hd.depth = parse_uint16(str + 22);
191 hd.color_mode = parse_uint16(str + 24);
192
193 return hd;
194}
195
196// -- non-progressive loading --------------------------------------------------
197
109static GdkPixbuf* 198static GdkPixbuf*
110gdk_pixbuf__psd_image_load (FILE *fp, 199gdk_pixbuf__psd_image_load (FILE *fp,
111 GError **error) 200 GError **error)
@@ -117,7 +206,7 @@ gdk_pixbuf__psd_image_load (FILE *fp,
117 guchar **buffers; 206 guchar **buffers;
118 207
119 PsdHeader hd = psd_read_header(fp); 208 PsdHeader hd = psd_read_header(fp);
120 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, hd.columns, hd.rows); 209 pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, hd.columns, hd.rows);
121 210
122 if (pixbuf == NULL) { 211 if (pixbuf == NULL) {
123 g_set_error (error, GDK_PIXBUF_ERROR, 212 g_set_error (error, GDK_PIXBUF_ERROR,
@@ -167,7 +256,7 @@ gdk_pixbuf__psd_image_load (FILE *fp,
167 gchar byte = fgetc(fp); 256 gchar byte = fgetc(fp);
168 ++bytes_read; 257 ++bytes_read;
169 258
170 if (byte == -128) { 259 if (byte == -128) {
171 continue; 260 continue;
172 } else if (byte > -1) { 261 } else if (byte > -1) {
173 gint count = byte + 1; 262 gint count = byte + 1;
@@ -199,9 +288,9 @@ gdk_pixbuf__psd_image_load (FILE *fp,
199 if (hd.color_mode == PSD_MODE_RGB) { 288 if (hd.color_mode == PSD_MODE_RGB) {
200 for (int i = 0; i < hd.rows; ++i) { 289 for (int i = 0; i < hd.rows; ++i) {
201 for (int j = 0; j < hd.columns; ++j) { 290 for (int j = 0; j < hd.columns; ++j) {
202 pixels[i * rowstride + 3 * j + 0] = buffers[0][i * hd.columns + j]; 291 pixels[i*rowstride + 3*j + 0] = buffers[0][i*hd.columns + j];
203 pixels[i * rowstride + 3 * j + 1] = buffers[1][i * hd.columns + j]; 292 pixels[i*rowstride + 3*j + 1] = buffers[1][i*hd.columns + j];
204 pixels[i * rowstride + 3 * j + 2] = buffers[2][i * hd.columns + j]; 293 pixels[i*rowstride + 3*j + 2] = buffers[2][i*hd.columns + j];
205 } 294 }
206 } 295 }
207 } 296 }
@@ -210,16 +299,373 @@ gdk_pixbuf__psd_image_load (FILE *fp,
210 return pixbuf; 299 return pixbuf;
211} 300}
212 301
302
303// --- progressive loading -----------------------------------------------------
304
305// Attempts to read bytes_needed bytes from data and stores them
306// in buffer.
307// Returns true if there were enough bytes and false otherwise
308// (which means we need to call feed_buffer again)
309
310static gboolean
311feed_buffer (guchar* buffer,
312 guint* bytes_read,
313 const guchar** data,
314 guint* size,
315 guint bytes_needed)
316{
317 gint how_many = bytes_needed - *bytes_read;
318 if (how_many > *size) {
319 how_many = *size;
320 }
321 memcpy(buffer + *bytes_read, *data, how_many);
322 *bytes_read += how_many;
323 *data += how_many;
324 *size -= how_many;
325 return (*bytes_read == bytes_needed);
326}
327
328// Attempts to read size of the block and then skip this block.
329// Returns true when finishes consuming block data, otherwise false
330// (false means we must call skip_block once again)
331
332static gboolean
333skip_block (PsdContext* context, const guchar** data, guint* size)
334{
335 static guint counter;
336
337 if (!context->bytes_to_skip_known) {
338 context->bytes_read = 0;
339 if (feed_buffer(context->buffer, &context->bytes_read, data, size, 4)) {
340 context->bytes_to_skip = parse_uint32(context->buffer);
341 context->bytes_to_skip_known = TRUE;
342 counter = 0;
343 } else {
344 return FALSE;
345 }
346 }
347 if (*size < context->bytes_to_skip) {
348 *data += *size;
349 context->bytes_to_skip -= *size;
350 counter += *size;
351 *size = 0;
352 return FALSE;
353 } else {
354 counter += context->bytes_to_skip;
355 *size -= context->bytes_to_skip;
356 *data += context->bytes_to_skip;
357 return TRUE;
358 }
359}
360
361// Decodes RLE-compressed data
362static void
363decompress_line(const guchar* src, guint line_length, guchar* dest)
364{
365 guint16 bytes_read = 0;
366 while (bytes_read < line_length) {
367 gchar byte = src[bytes_read];
368 ++bytes_read;
369
370 if (byte == -128) {
371 continue;
372 } else if (byte > -1) {
373 gint count = byte + 1;
374
375 // copy next count bytes
376 for (int k = 0; k < count; ++k) {
377 *dest = src[bytes_read];
378 ++dest;
379 ++bytes_read;
380 }
381 } else {
382 gint count = -byte + 1;
383
384 // copy next byte count times
385 guchar next_byte = src[bytes_read];
386 ++bytes_read;
387 for (int k = 0; k < count; ++k) {
388 *dest = next_byte;
389 ++dest;
390 }
391 }
392 }
393}
394
395static void
396reset_context(PsdContext* ctx)
397{
398 ctx->bytes_read = 0;
399 ctx->bytes_to_skip = 0;
400 ctx->bytes_to_skip_known = FALSE;
401}
402
403static gpointer
404gdk_pixbuf__psd_image_begin_load (GdkPixbufModuleSizeFunc size_func,
405 GdkPixbufModulePreparedFunc prepared_func,
406 GdkPixbufModuleUpdatedFunc updated_func,
407 gpointer user_data,
408 GError **error)
409{
410 PsdContext* context = g_malloc(sizeof(PsdContext));
411 if (context == NULL) {
412 g_set_error (
413 error,
414 GDK_PIXBUF_ERROR,
415 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
416 ("Not enough memory"));
417 return NULL;
418 }
419 context->size_func = size_func;
420 context->prepared_func = prepared_func;
421 context->updated_func = updated_func;
422 context->user_data = user_data;
423
424 context->state = PSD_STATE_HEADER;
425
426 // we'll allocate larger buffer once we know image size
427 context->buffer = g_malloc(256);
428 reset_context(context);
429
430 //context->bytes_read = 0;
431 //context->bytes_to_skip = 0;
432 //context->bytes_to_skip_known = FALSE;
433
434 context->channels_buffers = NULL;
435 context->current_channel = 0;
436 context->current_row = 0;
437 context->position = 0;
438 context->lines_lengths = NULL;
439
440 return (gpointer) context;
441}
442
443static gboolean
444gdk_pixbuf__psd_image_stop_load (gpointer context_ptr, GError **error)
445{
446 PsdContext *ctx = (PsdContext *) context_ptr;
447 gboolean retval = TRUE;
448
449 if (ctx->state != PSD_STATE_DONE) {
450 g_set_error (
451 error,
452 GDK_PIXBUF_ERROR,
453 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
454 ("PSD file was corrupted or incomplete."));
455 retval = FALSE;
456 } else {
457 // convert or copy channel buffers to our GdkPixbuf
458
459 //for (int i = 0; i < ctx->channels; i++) {
460 guchar* pixels = gdk_pixbuf_get_pixels(ctx->pixbuf);
461 for (int i = 0; i < ctx->height; i++) {
462 for (int j = 0; j < ctx->width; j++) {
463 pixels[3*j+0] = 0x00;
464 pixels[3*j+1] = 0x00;
465 pixels[3*j+2] = 0x00;
466 }
467 pixels += gdk_pixbuf_get_rowstride(ctx->pixbuf);
468 }
469
470 for (int i = 0; i < 3; i++) {
471 guchar* pixels = gdk_pixbuf_get_pixels(ctx->pixbuf);
472 for (int j = 0; j < ctx->height; j++) {
473 guchar* src_buf = &ctx->channels_buffers[i][ctx->width * j];
474 for (int k = 0; k < ctx->width; k++) {
475 pixels[3 * k + i] = src_buf[k];
476 }
477 pixels += gdk_pixbuf_get_rowstride(ctx->pixbuf);
478 }
479 }
480 }
481
482 g_free (ctx->buffer); // TODO a few more buffers need freeing
483 g_free (ctx);
484
485 return retval;
486}
487
488
489static gboolean
490gdk_pixbuf__psd_image_load_increment (gpointer context_ptr,
491 const guchar *data,
492 guint size,
493 GError **error)
494{
495
496 PsdContext* context = (PsdContext*) context_ptr;
497 PsdContext* ctx = context;
498
499 while (size > 0) {
500 switch (context->state) {
501 case PSD_STATE_HEADER:
502 if (feed_buffer(
503 context->buffer, &context->bytes_read,
504 &data, &size, PSD_HEADER_SIZE))
505 {
506 PsdHeader hd = psd_parse_header(ctx->buffer);
507
508 ctx->width = hd.columns;
509 ctx->height = hd.rows;
510 ctx->channels = hd.channels;
511 ctx->depth = hd.depth;
512 ctx->color_mode = hd.color_mode;
513
514 if (ctx->size_func) {
515 gint w = ctx->width;
516 gint h = ctx->height;
517 ctx->size_func(&w, &h, ctx->user_data);
518 if (w == 0 || h == 0) {
519 return FALSE;
520 }
521 }
522
523 // we need buffer that can contain one channel data of one
524 // row in RLE compressed format. 2*width should be enough
525 g_free(ctx->buffer);
526 ctx->buffer = g_malloc(ctx->width * 2);
527
528 // this will be needed for RLE decompression
529 ctx->lines_lengths =
530 g_malloc(2 * ctx->channels * ctx->height);
531
532 ctx->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE,
533 8, ctx->width, ctx->height);
534
535 if (ctx->lines_lengths == NULL || ctx->buffer == NULL ||
536 ctx->pixbuf == NULL)
537 {
538 g_set_error (error, GDK_PIXBUF_ERROR,
539 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
540 ("Insufficient memory to load PSD image file"));
541 return FALSE;
542 }
543
544 // create separate buffers for each channel
545 context->channels_buffers =
546 g_malloc(sizeof(guchar*) * ctx->channels);
547 for (int i = 0; i < ctx->channels; i++) {
548 ctx->channels_buffers[i] =
549 g_malloc(ctx->width * ctx->height);
550
551 if (ctx->channels_buffers[i] == NULL) {
552 g_set_error (error, GDK_PIXBUF_ERROR,
553 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
554 ("Insufficient memory to load PSD image file"));
555 return FALSE;
556 }
557 }
558
559 ctx->prepared_func(ctx->pixbuf, NULL, ctx->user_data);
560
561 ctx->state = PSD_STATE_COLOR_MODE_BLOCK;
562 reset_context(ctx);
563 }
564 break;
565 case PSD_STATE_COLOR_MODE_BLOCK:
566 if (skip_block(ctx, &data, &size)) {
567 ctx->state = PSD_STATE_RESOURCES_BLOCK;
568 reset_context(ctx);
569 }
570 break;
571 case PSD_STATE_RESOURCES_BLOCK:
572 if (skip_block(ctx, &data, &size)) {
573 ctx->state = PSD_STATE_LAYERS_BLOCK;
574 reset_context(ctx);
575 }
576 break;
577 case PSD_STATE_LAYERS_BLOCK:
578 if (skip_block(ctx, &data, &size)) {
579 ctx->state = PSD_STATE_COMPRESSION;
580 reset_context(ctx);
581 }
582 break;
583 case PSD_STATE_COMPRESSION:
584 if (feed_buffer(ctx->buffer, &ctx->bytes_read, &data, &size, 2))
585 {
586 ctx->compression = parse_uint16(ctx->buffer);
587
588 if (ctx->compression == PSD_COMPRESSION_RLE) {
589 ctx->state = PSD_STATE_LINES_LENGTHS;
590 reset_context(ctx);
591 } else if (ctx->compression == PSD_COMPRESSION_NONE) {
592 ctx->state = PSD_STATE_CHANNEL_DATA;
593 } else {
594 g_set_error (error, GDK_PIXBUF_ERROR,
595 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
596 ("Unsupported compression type"));
597 return FALSE;
598 }
599 }
600 break;
601 case PSD_STATE_LINES_LENGTHS:
602 if (feed_buffer(
603 (guchar*) ctx->lines_lengths, &ctx->bytes_read, &data,
604 &size, 2 * ctx->height * ctx->channels))
605 {
606 // convert from different endianness
607 for (int i = 0; i < ctx->height * ctx->channels; i++) {
608 ctx->lines_lengths[i] = parse_uint16(
609 (guchar*) &ctx->lines_lengths[i]);
610 }
611 ctx->state = PSD_STATE_CHANNEL_DATA;
612 reset_context(ctx);
613 }
614 break;
615 case PSD_STATE_CHANNEL_DATA:
616 if (context->compression == PSD_COMPRESSION_RLE)
617 {
618 guint line_length = ctx->lines_lengths[
619 ctx->current_channel * ctx->height + ctx->current_row];
620 if (feed_buffer(ctx->buffer, &ctx->bytes_read, &data,
621 &size, line_length))
622 {
623 ctx->bytes_read = 0;
624 decompress_line(
625 ctx->buffer,
626 line_length,
627 ctx->channels_buffers[ctx->current_channel]
628 + ctx->position
629 );
630 context->position += context->width;
631 ++context->current_row;
632
633 if (ctx->current_row >= ctx->height) {
634 ++ctx->current_channel;
635 ctx->current_row = 0;
636 ctx->position = 0;
637 if (ctx->current_channel >= ctx->channels) {
638 ctx->state = PSD_STATE_DONE;
639 }
640 }
641 }
642 } else {
643 if (feed_buffer(
644 context->buffer, &context->bytes_read,
645 &data, &size, context->width))
646 {
647 //memcpy(dest, context->buffer, context->hd.columns);
648 // TODO
649 }
650 }
651 break;
652 case PSD_STATE_DONE:
653 default:
654 size = 0;
655 break;
656 }
657 }
658 return TRUE;
659}
660
661
213void 662void
214fill_vtable (GdkPixbufModule* module) 663fill_vtable (GdkPixbufModule* module)
215{ 664{
216/* module->load = gdk_pixbuf__xbm_image_load; 665 //module->load = gdk_pixbuf__psd_image_load;
217 module->begin_load = gdk_pixbuf__xbm_image_begin_load; 666 module->begin_load = gdk_pixbuf__psd_image_begin_load;
218 module->stop_load = gdk_pixbuf__xbm_image_stop_loads 667 module->stop_load = gdk_pixbuf__psd_image_stop_load;
219 module->load_increment = gdk_pixbuf__xbm_image_load_increment;*/ 668 module->load_increment = gdk_pixbuf__psd_image_load_increment;
220 // TODO progressive loading
221
222 module->load = gdk_pixbuf__psd_image_load;
223} 669}
224 670
225void 671void