Commit 5d6799eb authored by Tor Lillqvist's avatar Tor Lillqvist
Browse files

Yet another intermediate version.

parent 770d8cad
......@@ -36,8 +36,8 @@
#include "config.h"
#include <glib.h> /* We want glib.h first for some pretty obscure
* Win32 compilation issues.
#include <glib.h> /* We want glib.h first because of some
* pretty obscure Win32 compilation issues.
*/
#include <stdio.h>
#include <stdlib.h>
......@@ -277,9 +277,10 @@ typedef struct
{
guint32 width, height;
gdouble resolution;
PSPCompression compression;
guchar metric;
guint16 compression;
guint16 depth;
gboolean greyscale;
guchar greyscale;
guint32 active_layer;
guint16 layer_count;
} PSPimage;
......@@ -331,7 +332,7 @@ static PSPSaveInterface psint =
};
static guint16 major, minor;
static guint tile_height;
MAIN()
......@@ -573,7 +574,7 @@ read_block_header (FILE *f,
long header_start;
guint32 len;
IFDBG(2) header_start = ftell (f);
IFDBG(3) header_start = ftell (f);
if (fread (buf, 4, 1, f) < 1
|| fread (&id, 2, 1, f) < 1
......@@ -591,7 +592,7 @@ read_block_header (FILE *f,
return -1;
}
IFDBG(2) gimp_message_printf (("PSP: %s at %d", block_name (id),
IFDBG(3) gimp_message_printf (("PSP: %s at %d", block_name (id),
header_start));
if (major < 4)
......@@ -604,7 +605,8 @@ read_block_header (FILE *f,
/* Version 4.0 seems to have dropped the initial data chunk length
* field.
*/
*total_len = *init_len = GUINT32_FROM_LE (len);
*init_len = 0xDEADBEEF; /* Intentionally bogus, should not be used */
*total_len = GUINT32_FROM_LE (len);
}
return id;
......@@ -622,9 +624,6 @@ read_general_image_attribute_block (FILE *f,
#else
guchar res[8];
#endif
guchar metric;
guint16 compression;
guchar greyscale;
if (init_len < 38 || total_len < 38)
{
......@@ -639,11 +638,11 @@ read_general_image_attribute_block (FILE *f,
if (fread (&ia->width, 4, 1, f) < 1
|| fread (&ia->height, 4, 1, f) < 1
|| fread (res, 8, 1, f) < 1
|| fread (&metric, 1, 1, f) < 1
|| fread (&compression, 1, 1, f) < 1
|| fread (&ia->metric, 1, 1, f) < 1
|| fread (&ia->compression, 2, 1, f) < 1
|| fread (&ia->depth, 2, 1, f) < 1
|| fread (buf, 2+4, 1, f) < 1 /* Skip plane and colour count */
|| fread (&greyscale, 1, 1, f) < 1
|| fread (&ia->greyscale, 1, 1, f) < 1
|| fread (buf, 4, 1, f) < 1 /* Skip total image size */
|| fread (&ia->active_layer, 4, 1, f) < 1
|| fread (&ia->layer_count, 2, 1, f) < 1)
......@@ -654,7 +653,7 @@ read_general_image_attribute_block (FILE *f,
}
ia->height = GUINT32_FROM_LE (ia->height);
ia->width = GUINT32_FROM_LE (ia->width);
ia->width = GUINT32_FROM_LE (ia->width);
ia->depth = GUINT16_FROM_LE (ia->depth);
#ifdef G_HAVE_GINT64
res[0] = GUINT64_FROM_LE (res[0]);
......@@ -679,10 +678,19 @@ read_general_image_attribute_block (FILE *f,
#endif
#endif
memcpy (&ia->resolution, res, 8);
if (metric == PSP_METRIC_CM)
if (ia->metric == PSP_METRIC_CM)
ia->resolution /= 2.54;
ia->compression = compression;
ia->compression = GUINT16_FROM_LE (ia->compression);
if (ia->compression > PSP_COMP_LZ77)
{
gimp_message_printf (("PSP: Unknown compression type %d",
ia->compression));
fclose (f);
return -1;
}
ia->active_layer = GUINT32_FROM_LE (ia->active_layer);
ia->layer_count = GUINT16_FROM_LE (ia->layer_count);
return 0;
}
......@@ -849,6 +857,8 @@ gimp_layer_mode_from_psp_blend_mode (PSPLayerBlendModes mode)
return NORMAL_MODE;
case PSP_BLEND_DARKEN:
return DARKEN_ONLY_MODE;
case PSP_BLEND_LIGHTEN:
return LIGHTEN_ONLY_MODE;
case PSP_BLEND_HUE:
return HUE_MODE;
case PSP_BLEND_SATURATION:
......@@ -907,17 +917,120 @@ blend_mode_name (PSPLayerBlendModes mode)
return blend_mode_names[mode];
g_free (err_name);
err_name = g_strdup_printf ("%d", mode);
err_name = g_strdup_printf ("unknown layer blend mode %d", mode);
return err_name;
}
static char *
bitmap_type_name (int type)
{
static char *bitmap_type_names[] =
{
"IMAGE",
"TRANS_MASK",
"USER_MASK",
"SELECTION",
"ALPHA_MASK",
"THUMBNAIL"
};
static gchar *err_name = NULL;
if (type >= 0 && type <= PSP_DIB_THUMBNAIL)
return bitmap_type_names[type];
g_free (err_name);
err_name = g_strdup_printf ("unknown bitmap type %d", type);
return err_name;
}
static char *
channel_type_name (int type)
{
static char *channel_type_names[] =
{
"COMPOSITE",
"RED",
"GREEN",
"BLUE"
};
static gchar *err_name = NULL;
if (type >= 0 && type <= PSP_DIB_THUMBNAIL)
return channel_type_names[type];
g_free (err_name);
err_name = g_strdup_printf ("unknown channel type %d", type);
return err_name;
}
static void
read_channel_data (FILE *f,
PSPCompression compression,
guchar **pixels,
guint bpp,
GDrawable *drawable,
GPixelRgn *pixel_rgn,
PSPDIBType bitmap_type,
PSPChannelType channel_type,
guint32 compressed_len)
{
gint i, k, y, width = drawable->width, height = drawable->height;
guchar *scanline, *p, *q;
switch (compression)
{
case PSP_COMP_NONE:
if (bpp == 1)
{
gimp_tile_cache_size (tile_height * width);
y = 0;
while (y < height)
{
fread (pixels[y], width, 1, f);
if (width % 4)
fseek (f, 4 - (width % 4), SEEK_CUR);
y++;
}
}
else
{
gimp_tile_cache_size (height * width * bpp);
scanline = g_malloc (width);
if (channel_type == PSP_CHANNEL_COMPOSITE)
k = 3;
else
k = channel_type - PSP_CHANNEL_RED;
y = 0;
while (y < height)
{
fread (scanline, width, 1, f);
if (width % 4)
fseek (f, 4 - (width % 4), SEEK_CUR);
p = scanline;
q = pixels[y] + k;
for (i = 0; i < width; i++)
{
*q = *p;
q += bpp;
p++;
}
y++;
}
g_free (scanline);
}
}
}
static int
read_layer_block (FILE *f,
gint image_ID,
guint total_len,
PSPimage *ia)
{
int i;
long block_start, sub_block_start, channel_start;
int sub_id;
guint32 sub_init_len, sub_total_len;
......@@ -926,13 +1039,18 @@ read_layer_block (FILE *f,
guchar type, opacity, blend_mode, visibility, transparency_protected;
guchar link_group_id, mask_linked, mask_disabled;
guint32 image_rect[4], saved_image_rect[4], mask_rect[4], saved_mask_rect[4];
gboolean width_bumped = FALSE, height_bumped = FALSE;
gboolean null_layer = FALSE;
guint16 bitmap_count, channel_count;
GDrawableType drawable_type;
guint32 layer_ID;
GLayerMode layer_mode;
guint32 channel_init_len, channel_total_len;
guint32 compressed_len, uncompressed_len;
guint16 bitmap_type, channel_type;
gint width, height, bpp;
guchar **pixels, *pixel;
GDrawable *drawable;
GPixelRgn pixel_rgn;
block_start = ftell (f);
......@@ -977,9 +1095,9 @@ read_layer_block (FILE *f,
|| fread (&saved_mask_rect, 16, 1, f) < 1
|| fread (&mask_linked, 1, 1, f) < 1
|| fread (&mask_disabled, 1, 1, f) < 1
|| fseek (f, 43, SEEK_CUR) < 0
|| fread (&bitmap_count, 1, 1, f) < 1
|| fread (&channel_count, 1, 1, f) < 1)
|| fseek (f, 47, SEEK_CUR) < 0
|| fread (&bitmap_count, 2, 1, f) < 1
|| fread (&channel_count, 2, 1, f) < 1)
{
gimp_message ("PSP: Error reading layer information chunk");
fclose (f);
......@@ -1007,10 +1125,11 @@ read_layer_block (FILE *f,
|| fread (&mask_linked, 1, 1, f) < 1
|| fread (&mask_disabled, 1, 1, f) < 1
|| fseek (f, 43, SEEK_CUR) < 0
|| fread (&bitmap_count, 1, 1, f) < 1
|| fread (&channel_count, 1, 1, f) < 1)
|| fread (&bitmap_count, 2, 1, f) < 1
|| fread (&channel_count, 2, 1, f) < 1)
{
gimp_message ("PSP: Error reading layer information chunk");
g_free (name);
fclose (f);
gimp_image_delete (image_ID);
return -1;
......@@ -1024,6 +1143,8 @@ read_layer_block (FILE *f,
swab_rect (saved_image_rect);
swab_rect (mask_rect);
swab_rect (saved_mask_rect);
bitmap_count = GUINT16_FROM_LE (bitmap_count);
channel_count = GUINT16_FROM_LE (channel_count);
layer_mode = gimp_layer_mode_from_psp_blend_mode (blend_mode);
if ((int) layer_mode == -1)
......@@ -1035,32 +1156,44 @@ read_layer_block (FILE *f,
visibility = FALSE;
}
width = saved_image_rect[2] - saved_image_rect[0];
height = saved_image_rect[3] - saved_image_rect[1];
IFDBG(2) gimp_message_printf
(("PSP: layer: %s %dx%d (%dx%d) opacity %d blend_mode %d", name,
image_rect[2] - image_rect[0],
image_rect[3] - image_rect[1],
saved_image_rect[2] - saved_image_rect[0],
saved_image_rect[3] - saved_image_rect[1],
opacity, blend_mode));
if (saved_image_rect[0] == saved_image_rect[2])
(("PSP: layer: %s %dx%d (%dx%d) opacity %d blend_mode %s "
"%d bitmaps %d channels",
name,
image_rect[2] - image_rect[0], image_rect[3] - image_rect[1],
width, height,
opacity, blend_mode_name (blend_mode),
bitmap_count, channel_count));
if (width == 0)
{
saved_image_rect[2]++;
width_bumped = TRUE;
width++;
null_layer = TRUE;
}
if (saved_image_rect[1] == saved_image_rect[3])
if (height == 0)
{
saved_image_rect[3]++;
height_bumped = TRUE;
height++;
null_layer = TRUE;
}
if (ia->greyscale)
if (!null_layer && bitmap_count == 1)
drawable_type = GRAY_IMAGE, bpp = 1;
else
drawable_type = GRAYA_IMAGE, bpp = 1;
else
if (!null_layer && bitmap_count == 1)
drawable_type = RGB_IMAGE, bpp = 3;
else
drawable_type = RGBA_IMAGE, bpp = 4;
layer_ID = gimp_layer_new (image_ID, name,
saved_image_rect[2] - saved_image_rect[0],
saved_image_rect[3] - saved_image_rect[1],
/* XXX */
ia->greyscale ? GRAYA_IMAGE : RGBA_IMAGE,
width, height,
drawable_type,
opacity / 255.0,
/* XXX */
layer_mode);
if (layer_ID == -1)
{
......@@ -1070,6 +1203,7 @@ read_layer_block (FILE *f,
return -1;
}
g_free (name);
if (saved_image_rect[0] != 0 || saved_image_rect[1] != 0)
gimp_layer_set_offsets (layer_ID,
saved_image_rect[0], saved_image_rect[1]);
......@@ -1081,11 +1215,25 @@ read_layer_block (FILE *f,
gimp_image_add_layer (image_ID, layer_ID, -1);
if (try_fseek (f, sub_block_start + sub_init_len, SEEK_SET) < 0)
{
gimp_image_delete (image_ID);
return -1;
}
if (major < 4)
if (try_fseek (f, sub_block_start + sub_init_len, SEEK_SET) < 0)
{
gimp_image_delete (image_ID);
return -1;
}
if (null_layer)
pixel = g_malloc0 (height * width * bpp);
else
pixel = g_malloc0 (height * width * bpp);
pixels = g_new(guchar *, height);
for (i = 0; i < height; i++)
pixels[i] = pixel + width * bpp * i;
drawable = gimp_drawable_get (layer_ID);
gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0,
width, height, TRUE, FALSE);
/* Read the layer channel sub-blocks */
while (ftell (f) < sub_block_start + sub_total_len)
......@@ -1110,6 +1258,9 @@ read_layer_block (FILE *f,
channel_start = ftell (f);
if (major == 4)
fseek (f, 4, SEEK_CUR); /* Unknown field */
if (fread (&compressed_len, 4, 1, f) < 1
|| fread (&uncompressed_len, 4, 1, f) < 1
|| fread (&bitmap_type, 2, 1, f) < 1
......@@ -1121,33 +1272,48 @@ read_layer_block (FILE *f,
return -1;
}
if (GUINT16_FROM_LE (bitmap_type) > PSP_DIB_USER_MASK)
compressed_len = GUINT32_FROM_LE (compressed_len);
uncompressed_len = GUINT32_FROM_LE (uncompressed_len);
bitmap_type = GUINT16_FROM_LE (bitmap_type);
channel_type = GUINT16_FROM_LE (channel_type);
if (bitmap_type > PSP_DIB_USER_MASK)
{
gimp_message ("PSP: Invalid bitmap type "
"in channel information chunk");
gimp_message_printf (("PSP: Invalid bitmap type %d "
"in channel information chunk",
bitmap_type));
fclose (f);
gimp_image_delete (image_ID);
return -1;
}
if (GUINT16_FROM_LE (channel_type) > PSP_CHANNEL_BLUE)
if (channel_type > PSP_CHANNEL_BLUE)
{
gimp_message ("PSP: Invalid channel type "
"in channel information chunk");
gimp_message_printf (("PSP: Invalid channel type %d "
"in channel information chunk",
channel_type));
fclose (f);
gimp_image_delete (image_ID);
return -1;
}
if (try_fseek (f, channel_start + channel_init_len, SEEK_SET) < 0)
{
gimp_image_delete (image_ID);
return -1;
}
/* Read channel data */
IFDBG(2) gimp_message_printf (("PSP: channel: %s %s %d (%d) bytes",
bitmap_type_name (bitmap_type),
channel_type_name (channel_type),
uncompressed_len, compressed_len));
if (major < 4)
if (try_fseek (f, channel_start + channel_init_len, SEEK_SET) < 0)
{
gimp_image_delete (image_ID);
return -1;
}
if (!null_layer)
read_channel_data (f, ia->compression, pixels,
bpp, drawable, &pixel_rgn,
bitmap_type, channel_type,
compressed_len);
if (try_fseek (f, channel_start + channel_total_len, SEEK_SET) < 0)
{
......@@ -1155,15 +1321,36 @@ read_layer_block (FILE *f,
return -1;
}
}
gimp_pixel_rgn_set_rect (&pixel_rgn, pixel, 0, 0, width, height);
g_free (pixels);
g_free (pixel);
}
if (try_fseek (f, block_start + total_len, SEEK_SET) < 0)
{
gimp_image_delete (image_ID);
return -1;
}
return layer_ID;
}
static char *
compression_name (int compression)
{
switch (compression)
{
case PSP_COMP_NONE:
return "no compression";
case PSP_COMP_RLE:
return "RLE";
case PSP_COMP_LZ77:
return "LZ77";
}
g_assert_not_reached ();
}
static gint32
load_image (char *filename)
{
......@@ -1256,10 +1443,10 @@ load_image (char *filename)
block_total_len, &ia) == -1)
return -1;
IFDBG(2) gimp_message_printf (("PSP: resolution: %d dpi "
"width: %d height %d",
IFDBG(3) gimp_message_printf (("PSP: %d dpi %dx%d %s",
(int) ia.resolution,
ia.width, ia.height));
ia.width, ia.height,
compression_name (ia.compression)));
image_ID = gimp_image_new (ia.width, ia.height,
ia.greyscale ? GRAY : RGB);
......@@ -1359,6 +1546,8 @@ run (char *name,
GStatusType status = STATUS_SUCCESS;
gint32 image_ID;
tile_height = gimp_tile_height ();
run_mode = param[0].data.d_int32;
*nreturn_vals = 1;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment