diff options
Diffstat (limited to 'io-psd.c')
| -rw-r--r-- | io-psd.c | 62 |
1 files changed, 39 insertions, 23 deletions
| @@ -22,7 +22,6 @@ | |||
| 22 | 22 | ||
| 23 | /* | 23 | /* |
| 24 | * TODO | 24 | * TODO |
| 25 | * - use http://library.gnome.org/devel/glib/unstable/glib-Byte-Order-Macros.html | ||
| 26 | * - report errors from parse_psd_header | 25 | * - report errors from parse_psd_header |
| 27 | * - other color modes (CMYK at least) | 26 | * - other color modes (CMYK at least) |
| 28 | * - i18n | 27 | * - i18n |
| @@ -43,7 +42,7 @@ typedef struct | |||
| 43 | guint16 channels; /* number of color channels (1-24) */ | 42 | guint16 channels; /* number of color channels (1-24) */ |
| 44 | guint32 rows; /* height of image in pixels (1-30000) */ | 43 | guint32 rows; /* height of image in pixels (1-30000) */ |
| 45 | guint32 columns; /* width of image in pixels (1-30000) */ | 44 | guint32 columns; /* width of image in pixels (1-30000) */ |
| 46 | guint16 depth; /* number of bits per channel (1, 8, and 16) */ | 45 | guint16 depth; /* number of bits per channel (1, 8, 16 or 32) */ |
| 47 | guint16 color_mode; /* color mode as defined below */ | 46 | guint16 color_mode; /* color mode as defined below */ |
| 48 | } PsdHeader; | 47 | } PsdHeader; |
| 49 | 48 | ||
| @@ -95,10 +94,11 @@ typedef struct | |||
| 95 | guint32 bytes_to_skip; | 94 | guint32 bytes_to_skip; |
| 96 | gboolean bytes_to_skip_known; | 95 | gboolean bytes_to_skip_known; |
| 97 | 96 | ||
| 98 | guint32 width; /* width of image in pixels (1-30000) */ | 97 | guint32 width; |
| 99 | guint32 height; /* height of image in pixels (1-30000) */ | 98 | guint32 height; |
| 100 | guint16 channels; /* number of color channels (1-24) */ | 99 | guint16 channels; |
| 101 | guint16 depth; /* number of bits per channel (1/8/16) */ | 100 | guint16 depth; |
| 101 | guint16 depth_bytes; | ||
| 102 | PsdColorMode color_mode; | 102 | PsdColorMode color_mode; |
| 103 | PsdCompressionType compression; | 103 | PsdCompressionType compression; |
| 104 | 104 | ||
| @@ -336,6 +336,7 @@ gdk_pixbuf__psd_image_load_increment (gpointer context_ptr, | |||
| 336 | ctx->height = hd.rows; | 336 | ctx->height = hd.rows; |
| 337 | ctx->channels = hd.channels; | 337 | ctx->channels = hd.channels; |
| 338 | ctx->depth = hd.depth; | 338 | ctx->depth = hd.depth; |
| 339 | ctx->depth_bytes = (ctx->depth/8 > 0 ? ctx->depth/8 : 1); | ||
| 339 | ctx->color_mode = hd.color_mode; | 340 | ctx->color_mode = hd.color_mode; |
| 340 | 341 | ||
| 341 | /* | 342 | /* |
| @@ -347,7 +348,8 @@ gdk_pixbuf__psd_image_load_increment (gpointer context_ptr, | |||
| 347 | // ctx->color_mode, ctx->channels, ctx->depth); | 348 | // ctx->color_mode, ctx->channels, ctx->depth); |
| 348 | 349 | ||
| 349 | if (ctx->color_mode != PSD_MODE_RGB | 350 | if (ctx->color_mode != PSD_MODE_RGB |
| 350 | //&& ctx->color_mode != PSD_MODE_CMYK | 351 | && ctx->color_mode != PSD_MODE_GRAYSCALE |
| 352 | && ctx->color_mode != PSD_MODE_CMYK | ||
| 351 | ) { | 353 | ) { |
| 352 | g_set_error (error, GDK_PIXBUF_ERROR, | 354 | g_set_error (error, GDK_PIXBUF_ERROR, |
| 353 | GDK_PIXBUF_ERROR_UNKNOWN_TYPE, | 355 | GDK_PIXBUF_ERROR_UNKNOWN_TYPE, |
| @@ -355,7 +357,7 @@ gdk_pixbuf__psd_image_load_increment (gpointer context_ptr, | |||
| 355 | return FALSE; | 357 | return FALSE; |
| 356 | } | 358 | } |
| 357 | 359 | ||
| 358 | if (ctx->depth != 8) { | 360 | if (ctx->depth != 8 && ctx->depth != 16) { |
| 359 | g_set_error (error, GDK_PIXBUF_ERROR, | 361 | g_set_error (error, GDK_PIXBUF_ERROR, |
| 360 | GDK_PIXBUF_ERROR_UNKNOWN_TYPE, | 362 | GDK_PIXBUF_ERROR_UNKNOWN_TYPE, |
| 361 | ("Unsupported color depth")); | 363 | ("Unsupported color depth")); |
| @@ -371,10 +373,10 @@ gdk_pixbuf__psd_image_load_increment (gpointer context_ptr, | |||
| 371 | } | 373 | } |
| 372 | } | 374 | } |
| 373 | 375 | ||
| 374 | // we need buffer that can contain one channel data of one | 376 | // we need buffer that can contain one channel data for one |
| 375 | // row in RLE compressed format. 2*width should be enough | 377 | // row in RLE compressed format. 2*width should be enough |
| 376 | g_free(ctx->buffer); | 378 | g_free(ctx->buffer); |
| 377 | ctx->buffer = g_malloc(ctx->width * 2); | 379 | ctx->buffer = g_malloc(ctx->width * 2 * ctx->depth_bytes); |
| 378 | 380 | ||
| 379 | // this will be needed for RLE decompression | 381 | // this will be needed for RLE decompression |
| 380 | ctx->lines_lengths = | 382 | ctx->lines_lengths = |
| @@ -396,7 +398,7 @@ gdk_pixbuf__psd_image_load_increment (gpointer context_ptr, | |||
| 396 | ctx->ch_bufs = g_malloc(sizeof(guchar*) * ctx->channels); | 398 | ctx->ch_bufs = g_malloc(sizeof(guchar*) * ctx->channels); |
| 397 | for (int i = 0; i < ctx->channels; i++) { | 399 | for (int i = 0; i < ctx->channels; i++) { |
| 398 | ctx->ch_bufs[i] = | 400 | ctx->ch_bufs[i] = |
| 399 | g_malloc(ctx->width * ctx->height); | 401 | g_malloc(ctx->width*ctx->height*ctx->depth_bytes); |
| 400 | 402 | ||
| 401 | if (ctx->ch_bufs[i] == NULL) { | 403 | if (ctx->ch_bufs[i] == NULL) { |
| 402 | g_set_error (error, GDK_PIXBUF_ERROR, | 404 | g_set_error (error, GDK_PIXBUF_ERROR, |
| @@ -440,6 +442,7 @@ gdk_pixbuf__psd_image_load_increment (gpointer context_ptr, | |||
| 440 | reset_context_buffer(ctx); | 442 | reset_context_buffer(ctx); |
| 441 | } else if (ctx->compression == PSD_COMPRESSION_NONE) { | 443 | } else if (ctx->compression == PSD_COMPRESSION_NONE) { |
| 442 | ctx->state = PSD_STATE_CHANNEL_DATA; | 444 | ctx->state = PSD_STATE_CHANNEL_DATA; |
| 445 | reset_context_buffer(ctx); | ||
| 443 | } else { | 446 | } else { |
| 444 | g_set_error (error, GDK_PIXBUF_ERROR, | 447 | g_set_error (error, GDK_PIXBUF_ERROR, |
| 445 | GDK_PIXBUF_ERROR_UNKNOWN_TYPE, | 448 | GDK_PIXBUF_ERROR_UNKNOWN_TYPE, |
| @@ -464,7 +467,7 @@ gdk_pixbuf__psd_image_load_increment (gpointer context_ptr, | |||
| 464 | break; | 467 | break; |
| 465 | case PSD_STATE_CHANNEL_DATA: | 468 | case PSD_STATE_CHANNEL_DATA: |
| 466 | { | 469 | { |
| 467 | guint line_length = ctx->width; | 470 | guint line_length = ctx->width * ctx->depth_bytes; |
| 468 | if (ctx->compression == PSD_COMPRESSION_RLE) { | 471 | if (ctx->compression == PSD_COMPRESSION_RLE) { |
| 469 | line_length = ctx->lines_lengths[ | 472 | line_length = ctx->lines_lengths[ |
| 470 | ctx->curr_ch * ctx->height + ctx->curr_row]; | 473 | ctx->curr_ch * ctx->height + ctx->curr_row]; |
| @@ -473,18 +476,16 @@ gdk_pixbuf__psd_image_load_increment (gpointer context_ptr, | |||
| 473 | if (feed_buffer(ctx->buffer, &ctx->bytes_read, &data, &size, | 476 | if (feed_buffer(ctx->buffer, &ctx->bytes_read, &data, &size, |
| 474 | line_length)) | 477 | line_length)) |
| 475 | { | 478 | { |
| 476 | reset_context_buffer(ctx); | ||
| 477 | |||
| 478 | if (ctx->compression == PSD_COMPRESSION_RLE) { | 479 | if (ctx->compression == PSD_COMPRESSION_RLE) { |
| 479 | decompress_line(ctx->buffer, line_length, | 480 | decompress_line(ctx->buffer, line_length, |
| 480 | ctx->ch_bufs[ctx->curr_ch] + ctx->pos | 481 | ctx->ch_bufs[ctx->curr_ch] + ctx->pos |
| 481 | ); | 482 | ); |
| 482 | } else { | 483 | } else { |
| 483 | memcpy(ctx->ch_bufs[ctx->curr_ch] + ctx->pos, | 484 | memcpy(ctx->ch_bufs[ctx->curr_ch] + ctx->pos, |
| 484 | ctx->buffer, ctx->width); | 485 | ctx->buffer, line_length); |
| 485 | } | 486 | } |
| 486 | 487 | ||
| 487 | ctx->pos += ctx->width; | 488 | ctx->pos += ctx->width * ctx->depth_bytes; |
| 488 | ++ctx->curr_row; | 489 | ++ctx->curr_row; |
| 489 | 490 | ||
| 490 | if (ctx->curr_row >= ctx->height) { | 491 | if (ctx->curr_row >= ctx->height) { |
| @@ -495,6 +496,8 @@ gdk_pixbuf__psd_image_load_increment (gpointer context_ptr, | |||
| 495 | ctx->state = PSD_STATE_DONE; | 496 | ctx->state = PSD_STATE_DONE; |
| 496 | } | 497 | } |
| 497 | } | 498 | } |
| 499 | |||
| 500 | reset_context_buffer(ctx); | ||
| 498 | } | 501 | } |
| 499 | } | 502 | } |
| 500 | break; | 503 | break; |
| @@ -507,17 +510,29 @@ gdk_pixbuf__psd_image_load_increment (gpointer context_ptr, | |||
| 507 | 510 | ||
| 508 | if (ctx->state == PSD_STATE_DONE && !ctx->finalized) { | 511 | if (ctx->state == PSD_STATE_DONE && !ctx->finalized) { |
| 509 | // convert or copy channel buffers to our GdkPixbuf | 512 | // convert or copy channel buffers to our GdkPixbuf |
| 513 | guchar* pixels = gdk_pixbuf_get_pixels(ctx->pixbuf); | ||
| 514 | guint b = ctx->depth_bytes; | ||
| 515 | |||
| 510 | if (ctx->color_mode == PSD_MODE_RGB && !ctx->use_alpha) { | 516 | 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++) { | 517 | for (int i = 0; i < ctx->height; i++) { |
| 513 | for (int j = 0; j < ctx->width; j++) { | 518 | for (int j = 0; j < ctx->width; j++) { |
| 514 | pixels[3*j+0] = ctx->ch_bufs[0][ctx->width*i + j]; | 519 | pixels[3*j+0] = ctx->ch_bufs[0][ctx->width*i*b + j*b]; |
| 515 | pixels[3*j+1] = ctx->ch_bufs[1][ctx->width*i + j]; | 520 | pixels[3*j+1] = ctx->ch_bufs[1][ctx->width*i*b + j*b]; |
| 516 | pixels[3*j+2] = ctx->ch_bufs[2][ctx->width*i + j]; | 521 | pixels[3*j+2] = ctx->ch_bufs[2][ctx->width*i*b + j*b]; |
| 517 | } | 522 | } |
| 518 | pixels += gdk_pixbuf_get_rowstride(ctx->pixbuf); | 523 | pixels += gdk_pixbuf_get_rowstride(ctx->pixbuf); |
| 519 | } | 524 | } |
| 520 | } else if (ctx->color_mode == PSD_MODE_RGB && ctx->use_alpha) { | 525 | } else if (ctx->color_mode == PSD_MODE_GRAYSCALE) { |
| 526 | for (int i = 0; i < ctx->height; i++) { | ||
| 527 | for (int j = 0; j < ctx->width; j++) { | ||
| 528 | pixels[3*j+0] = pixels[3*j+1] = pixels[3*j+2] = | ||
| 529 | ctx->ch_bufs[0][ctx->width*i*b + j*b]; | ||
| 530 | } | ||
| 531 | pixels += gdk_pixbuf_get_rowstride(ctx->pixbuf); | ||
| 532 | } | ||
| 533 | } | ||
| 534 | #if 0 | ||
| 535 | else if (ctx->color_mode == PSD_MODE_RGB && ctx->use_alpha) { | ||
| 521 | guchar* pixels = gdk_pixbuf_get_pixels(ctx->pixbuf); | 536 | guchar* pixels = gdk_pixbuf_get_pixels(ctx->pixbuf); |
| 522 | for (int i = 0; i < ctx->height; i++) { | 537 | for (int i = 0; i < ctx->height; i++) { |
| 523 | for (int j = 0; j < ctx->width; j++) { | 538 | for (int j = 0; j < ctx->width; j++) { |
| @@ -528,7 +543,8 @@ gdk_pixbuf__psd_image_load_increment (gpointer context_ptr, | |||
| 528 | } | 543 | } |
| 529 | pixels += gdk_pixbuf_get_rowstride(ctx->pixbuf); | 544 | pixels += gdk_pixbuf_get_rowstride(ctx->pixbuf); |
| 530 | } | 545 | } |
| 531 | } else if (ctx->color_mode == PSD_MODE_CMYK) { | 546 | #endif |
| 547 | else if (ctx->color_mode == PSD_MODE_CMYK) { | ||
| 532 | // unfortunately, this doesn't seem to work correctly... | 548 | // unfortunately, this doesn't seem to work correctly... |
| 533 | 549 | ||
| 534 | guchar* pixels = gdk_pixbuf_get_pixels(ctx->pixbuf); | 550 | guchar* pixels = gdk_pixbuf_get_pixels(ctx->pixbuf); |
