summaryrefslogtreecommitdiffstats
path: root/io-psd.c
diff options
context:
space:
mode:
Diffstat (limited to 'io-psd.c')
-rw-r--r--io-psd.c301
1 files changed, 75 insertions, 226 deletions
diff --git a/io-psd.c b/io-psd.c
index 363b2ef..6470f71 100644
--- a/io-psd.c
+++ b/io-psd.c
@@ -26,6 +26,7 @@
* - report errors from parse_psd_header
* - other color modes
* - ...
+ * - MODULE_ENTRY stuff
*/
#include <stdlib.h>
@@ -39,7 +40,7 @@ typedef struct
{
guchar signature[4]; /* file ID, always "8BPS" */
guint16 version; /* version number, always 1 */
- guchar reserved[6];
+ guchar resetved[6];
guint16 channels; /* number of color channels (1-24) */
guint32 rows; /* height of image in pixels (1-30000) */
guint32 columns; /* width of image in pixels (1-30000) */
@@ -95,7 +96,6 @@ typedef struct
guint32 bytes_to_skip;
gboolean bytes_to_skip_known;
- //PsdHeader hd;
guint32 width; /* width of image in pixels (1-30000) */
guint32 height; /* height of image in pixels (1-30000) */
guint16 channels; /* number of color channels (1-24) */
@@ -103,79 +103,31 @@ typedef struct
PsdColorMode color_mode;
PsdCompressionType compression;
- guchar** channels_buffers;
- guint current_channel;
- guint current_row;
- guint position; // ? redundant?
+ guchar** ch_bufs; /* channels buffers */
+ guint curr_ch; /* current channel */
+ guint curr_row;
+ guint pos; // redundant?
guint16* lines_lengths;
gboolean finalized;
} PsdContext;
-static guint16
-read_uint16 (FILE *fp)
-{
- guint16 t;
- t = fgetc(fp) << 8;
- t |= fgetc(fp);
- return t;
-}
-
-static guint32
-read_uint32 (FILE *fp)
-{
- guint32 t;
- t = fgetc(fp) << 24;
- t |= fgetc(fp) << 16;
- t |= fgetc(fp) << 8;
- t |= fgetc(fp);
- return t;
-}
static guint16
-parse_uint16 (guchar* buf)
+read_uint16 (guchar* buf)
{
return (buf[0] << 8) | buf[1];
}
static guint32
-parse_uint32 (guchar* buf)
+read_uint32 (guchar* buf)
{
return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
}
-static PsdHeader
-psd_read_header (FILE *fp)
-{
- PsdHeader hd;
- int t;
-
- fread(hd.signature, 1, 4, fp);
- hd.version = read_uint16(fp);
- fread(hd.reserved, 1, 6, fp);
- hd.channels = read_uint16(fp);
- hd.rows = read_uint32(fp);
- hd.columns = read_uint32(fp);
- hd.depth = read_uint16(fp);
- hd.color_mode = read_uint16(fp);
-
- // skip Color Mode Data Block
- t = read_uint32(fp);
- fseek(fp, t, SEEK_CUR);
-
- // skip Image Resources Block
- t = read_uint32(fp);
- fseek(fp, t, SEEK_CUR);
-
- // skip Layer and Mask Information Block
- t = read_uint32(fp);
- fseek(fp, t, SEEK_CUR);
-
- return hd;
-}
-
/*
* Parse Psdheader from buffer
+ *
* str is expected to be at least PSD_HEADER_SIZE long
*/
static PsdHeader
@@ -184,130 +136,22 @@ psd_parse_header (guchar* str)
PsdHeader hd;
memcpy(hd.signature, str, 4);
- hd.version = parse_uint16(str + 4);
- hd.channels = parse_uint16(str + 12);
- hd.rows = parse_uint32(str + 14);
- hd.columns = parse_uint32(str + 18);
- hd.depth = parse_uint16(str + 22);
- hd.color_mode = parse_uint16(str + 24);
+ hd.version = read_uint16(str + 4);
+ hd.channels = read_uint16(str + 12);
+ hd.rows = read_uint32(str + 14);
+ hd.columns = read_uint32(str + 18);
+ hd.depth = read_uint16(str + 22);
+ hd.color_mode = read_uint16(str + 24);
return hd;
}
-// -- non-progressive loading --------------------------------------------------
-
-static GdkPixbuf*
-gdk_pixbuf__psd_image_load (FILE *fp,
- GError **error)
-{
- guint rowstride;
- guint16 compression_type;
- guchar *pixels;
- GdkPixbuf *pixbuf;
- guchar **buffers;
-
- PsdHeader hd = psd_read_header(fp);
- pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, hd.columns, hd.rows);
-
- if (pixbuf == NULL) {
- g_set_error (error, GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
- ("Insufficient memory to load PSD image file"));
- return NULL;
- }
-
- pixels = gdk_pixbuf_get_pixels (pixbuf);
- rowstride = gdk_pixbuf_get_rowstride (pixbuf);
-
- compression_type = read_uint16(fp);
-
- if (compression_type != PSD_COMPRESSION_NONE &&
- compression_type != PSD_COMPRESSION_RLE) {
- g_set_error (error, GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
- ("Unsupported compression type"));
- return NULL;
- }
-
- if (hd.color_mode != PSD_MODE_RGB) {
- g_set_error (error, GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
- ("Unsupported color mode"));
- return NULL;
- }
-
- //g_message("mode=%d, channels=%d", hd.color_mode, hd.channels);
-
- buffers = g_malloc(sizeof(guchar*) * hd.channels);
-
- if (compression_type == PSD_COMPRESSION_RLE) {
- guint16 *line_lengths = g_malloc(2 * hd.rows * hd.channels);
-
- for (int i = 0; i < hd.rows * hd.channels; ++i) {
- line_lengths[i] = read_uint16(fp);
- }
-
- for (int i = 0; i < hd.channels; ++i) {
- buffers[i] = g_malloc(hd.rows * hd.columns);
- gint position = 0;
-
- for (int j = 0; j < hd.rows; ++j) {
- guint16 bytes_read = 0;
- while (bytes_read < line_lengths[i * hd.rows + j]) {
- gchar byte = fgetc(fp);
- ++bytes_read;
-
- if (byte == -128) {
- continue;
- } else if (byte > -1) {
- gint count = byte + 1;
-
- // copy next count bytes
- for (int k = 0; k < count; ++k) {
- buffers[i][position] = fgetc(fp);
- ++bytes_read;
- ++position;
- }
- } else {
- gint count = -byte + 1;
-
- // copy next byte count times
- guchar next_byte = fgetc(fp);
- ++bytes_read;
- for (int k = 0; k < count; ++k) {
- buffers[i][position] = next_byte;
- ++position;
- }
- }
- }
- }
- }
-
- g_free(line_lengths);
- }
-
- if (hd.color_mode == PSD_MODE_RGB) {
- for (int i = 0; i < hd.rows; ++i) {
- for (int j = 0; j < hd.columns; ++j) {
- pixels[i*rowstride + 3*j + 0] = buffers[0][i*hd.columns + j];
- pixels[i*rowstride + 3*j + 1] = buffers[1][i*hd.columns + j];
- pixels[i*rowstride + 3*j + 2] = buffers[2][i*hd.columns + j];
- }
- }
- }
- // TODO: other color modes, CMYK at least
-
- return pixbuf;
-}
-
-
-// --- progressive loading -----------------------------------------------------
-
-// Attempts to read bytes_needed bytes from data and stores them
-// in buffer.
-// Returns true if there were enough bytes and false otherwise
-// (which means we need to call feed_buffer again)
-
+/*
+ * Attempts to read bytes_needed bytes from data and stores them in buffer.
+ *
+ * Returns true if there were enough bytes and false otherwise
+ * (which means we need to call feed_buffer again)
+ */
static gboolean
feed_buffer (guchar* buffer,
guint* bytes_read,
@@ -326,10 +170,12 @@ feed_buffer (guchar* buffer,
return (*bytes_read == bytes_needed);
}
-// Attempts to read size of the block and then skip this block.
-// Returns true when finishes consuming block data, otherwise false
-// (false means we must call skip_block once again)
-
+/*
+ * Attempts to read size of the block and then skip this block.
+ *
+ * Returns true when finishes consuming block data, otherwise false
+ * (false means we must call skip_block once again)
+ */
static gboolean
skip_block (PsdContext* context, const guchar** data, guint* size)
{
@@ -338,7 +184,7 @@ skip_block (PsdContext* context, const guchar** data, guint* size)
if (!context->bytes_to_skip_known) {
context->bytes_read = 0;
if (feed_buffer(context->buffer, &context->bytes_read, data, size, 4)) {
- context->bytes_to_skip = parse_uint32(context->buffer);
+ context->bytes_to_skip = read_uint32(context->buffer);
context->bytes_to_skip_known = TRUE;
counter = 0;
} else {
@@ -359,7 +205,9 @@ skip_block (PsdContext* context, const guchar** data, guint* size)
}
}
-// Decodes RLE-compressed data
+/*
+ * Decodes RLE-compressed data
+ */
static void
decompress_line(const guchar* src, guint line_length, guchar* dest)
{
@@ -394,7 +242,7 @@ decompress_line(const guchar* src, guint line_length, guchar* dest)
}
static void
-reset_context(PsdContext* ctx)
+reset_context_buffer(PsdContext* ctx)
{
ctx->bytes_read = 0;
ctx->bytes_to_skip = 0;
@@ -426,12 +274,12 @@ gdk_pixbuf__psd_image_begin_load (GdkPixbufModuleSizeFunc size_func,
// we'll allocate larger buffer once we know image size
context->buffer = g_malloc(PSD_HEADER_SIZE);
- reset_context(context);
+ reset_context_buffer(context);
- context->channels_buffers = NULL;
- context->current_channel = 0;
- context->current_row = 0;
- context->position = 0;
+ context->ch_bufs = NULL;
+ context->curr_ch = 0;
+ context->curr_row = 0;
+ context->pos = 0;
context->lines_lengths = NULL;
context->finalized = FALSE;
@@ -449,12 +297,16 @@ gdk_pixbuf__psd_image_stop_load (gpointer context_ptr, GError **error)
error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
- ("PSD file was corrupted or incomplete. (not PSD_STATE_DONE)"));
+ ("PSD file was corrupted or incomplete."));
retval = FALSE;
}
- g_free (ctx->buffer); // TODO a few more buffers need freeing
- g_free (ctx);
+ g_free(ctx->buffer);
+ g_free(ctx->lines_lengths);
+ for (int i = 0; i < ctx->channels; i++) {
+ g_free(ctx->ch_bufs[i]);
+ }
+ g_free(ctx);
return retval;
}
@@ -467,14 +319,13 @@ gdk_pixbuf__psd_image_load_increment (gpointer context_ptr,
GError **error)
{
- PsdContext* context = (PsdContext*) context_ptr;
- PsdContext* ctx = context;
+ PsdContext* ctx = (PsdContext*) context_ptr;
while (size > 0) {
- switch (context->state) {
+ switch (ctx->state) {
case PSD_STATE_HEADER:
if (feed_buffer(
- context->buffer, &context->bytes_read,
+ ctx->buffer, &ctx->bytes_read,
&data, &size, PSD_HEADER_SIZE))
{
PsdHeader hd = psd_parse_header(ctx->buffer);
@@ -485,8 +336,8 @@ gdk_pixbuf__psd_image_load_increment (gpointer context_ptr,
ctx->depth = hd.depth;
ctx->color_mode = hd.color_mode;
- g_message("color_mode=%d, channels=%d, depth=%d",
- ctx->color_mode, ctx->channels, ctx->depth);
+ //g_message("color_mode=%d, channels=%d, depth=%d",
+ // ctx->color_mode, ctx->channels, ctx->depth);
if (ctx->color_mode != PSD_MODE_RGB/* &&
ctx->color_mode != PSD_MODE_CMYK*/
@@ -535,13 +386,12 @@ gdk_pixbuf__psd_image_load_increment (gpointer context_ptr,
}
// create separate buffers for each channel
- context->channels_buffers =
- g_malloc(sizeof(guchar*) * ctx->channels);
+ ctx->ch_bufs = g_malloc(sizeof(guchar*) * ctx->channels);
for (int i = 0; i < ctx->channels; i++) {
- ctx->channels_buffers[i] =
+ ctx->ch_bufs[i] =
g_malloc(ctx->width * ctx->height);
- if (ctx->channels_buffers[i] == NULL) {
+ if (ctx->ch_bufs[i] == NULL) {
g_set_error (error, GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
("Insufficient memory to load PSD image file"));
@@ -552,35 +402,35 @@ gdk_pixbuf__psd_image_load_increment (gpointer context_ptr,
ctx->prepared_func(ctx->pixbuf, NULL, ctx->user_data);
ctx->state = PSD_STATE_COLOR_MODE_BLOCK;
- reset_context(ctx);
+ reset_context_buffer(ctx);
}
break;
case PSD_STATE_COLOR_MODE_BLOCK:
if (skip_block(ctx, &data, &size)) {
ctx->state = PSD_STATE_RESOURCES_BLOCK;
- reset_context(ctx);
+ reset_context_buffer(ctx);
}
break;
case PSD_STATE_RESOURCES_BLOCK:
if (skip_block(ctx, &data, &size)) {
ctx->state = PSD_STATE_LAYERS_BLOCK;
- reset_context(ctx);
+ reset_context_buffer(ctx);
}
break;
case PSD_STATE_LAYERS_BLOCK:
if (skip_block(ctx, &data, &size)) {
ctx->state = PSD_STATE_COMPRESSION;
- reset_context(ctx);
+ reset_context_buffer(ctx);
}
break;
case PSD_STATE_COMPRESSION:
if (feed_buffer(ctx->buffer, &ctx->bytes_read, &data, &size, 2))
{
- ctx->compression = parse_uint16(ctx->buffer);
+ ctx->compression = read_uint16(ctx->buffer);
if (ctx->compression == PSD_COMPRESSION_RLE) {
ctx->state = PSD_STATE_LINES_LENGTHS;
- reset_context(ctx);
+ reset_context_buffer(ctx);
} else if (ctx->compression == PSD_COMPRESSION_NONE) {
ctx->state = PSD_STATE_CHANNEL_DATA;
} else {
@@ -598,11 +448,11 @@ gdk_pixbuf__psd_image_load_increment (gpointer context_ptr,
{
// convert from different endianness
for (int i = 0; i < ctx->height * ctx->channels; i++) {
- ctx->lines_lengths[i] = parse_uint16(
+ ctx->lines_lengths[i] = read_uint16(
(guchar*) &ctx->lines_lengths[i]);
}
ctx->state = PSD_STATE_CHANNEL_DATA;
- reset_context(ctx);
+ reset_context_buffer(ctx);
}
break;
case PSD_STATE_CHANNEL_DATA:
@@ -610,32 +460,31 @@ gdk_pixbuf__psd_image_load_increment (gpointer context_ptr,
guint line_length = ctx->width;
if (ctx->compression == PSD_COMPRESSION_RLE) {
line_length = ctx->lines_lengths[
- ctx->current_channel * ctx->height + ctx->current_row];
+ ctx->curr_ch * ctx->height + ctx->curr_row];
}
if (feed_buffer(ctx->buffer, &ctx->bytes_read, &data, &size,
line_length))
{
- ctx->bytes_read = 0;
+ reset_context_buffer(ctx);
if (ctx->compression == PSD_COMPRESSION_RLE) {
decompress_line(ctx->buffer, line_length,
- ctx->channels_buffers[ctx->current_channel]
- + ctx->position
+ ctx->ch_bufs[ctx->curr_ch] + ctx->pos
);
} else {
- memcpy(ctx->channels_buffers[ctx->current_channel]
- + ctx->position, ctx->buffer, ctx->width);
+ memcpy(ctx->ch_bufs[ctx->curr_ch] + ctx->pos,
+ ctx->buffer, ctx->width);
}
- ctx->position += ctx->width;
- ++ctx->current_row;
+ ctx->pos += ctx->width;
+ ++ctx->curr_row;
- if (ctx->current_row >= ctx->height) {
- ++ctx->current_channel;
- ctx->current_row = 0;
- ctx->position = 0;
- if (ctx->current_channel >= ctx->channels) {
+ if (ctx->curr_row >= ctx->height) {
+ ++ctx->curr_ch;
+ ctx->curr_row = 0;
+ ctx->pos = 0;
+ if (ctx->curr_ch >= ctx->channels) {
ctx->state = PSD_STATE_DONE;
}
}
@@ -655,9 +504,9 @@ gdk_pixbuf__psd_image_load_increment (gpointer context_ptr,
guchar* pixels = gdk_pixbuf_get_pixels(ctx->pixbuf);
for (int i = 0; i < ctx->height; i++) {
for (int j = 0; j < ctx->width; j++) {
- pixels[3*j+0] = ctx->channels_buffers[0][ctx->width*i + j];
- pixels[3*j+1] = ctx->channels_buffers[1][ctx->width*i + j];
- pixels[3*j+2] = ctx->channels_buffers[2][ctx->width*i + j];
+ pixels[3*j+0] = ctx->ch_bufs[0][ctx->width*i + j];
+ pixels[3*j+1] = ctx->ch_bufs[1][ctx->width*i + j];
+ pixels[3*j+2] = ctx->ch_bufs[2][ctx->width*i + j];
}
pixels += gdk_pixbuf_get_rowstride(ctx->pixbuf);
}