plug-ins: add support for 16 bit integer images in psp reader.

This commit is contained in:
Jacob Boerema 2020-09-08 22:14:50 -04:00
parent 84f06e976a
commit 7863d668e0
1 changed files with 146 additions and 38 deletions

View File

@ -547,14 +547,17 @@ typedef gboolean PSP_BOOLEAN;
*/
typedef struct
{
guint32 width, height;
gdouble resolution;
guchar metric;
guint16 compression;
guint16 depth;
guchar grayscale;
guint32 active_layer;
guint16 layer_count;
guint32 width, height;
gdouble resolution;
guchar metric;
guint16 compression;
guint16 depth;
guchar grayscale;
guint32 active_layer;
guint16 layer_count;
guint16 bytes_per_sample;
GimpImageBaseType base_type;
GimpPrecision precision;
} PSPimage;
@ -1034,7 +1037,55 @@ read_general_image_attribute_block (FILE *f,
}
ia->depth = GUINT16_FROM_LE (ia->depth);
if (ia->depth != 24)
switch (ia->depth)
{
case 24:
case 48:
ia->base_type = GIMP_RGB;
if (ia->depth == 24)
ia->precision = GIMP_PRECISION_U8_NON_LINEAR;
else
ia->precision = GIMP_PRECISION_U16_NON_LINEAR;
break;
case 1:
case 4:
case 8:
case 16:
if (ia->grayscale && ia->depth >= 8)
{
ia->base_type = GIMP_GRAY;
if (ia->depth == 8)
ia->precision = GIMP_PRECISION_U8_NON_LINEAR;
else
ia->precision = GIMP_PRECISION_U16_NON_LINEAR;
}
else if (ia->depth <= 8 && ! ia->grayscale)
{
ia->base_type = GIMP_INDEXED;
ia->precision = GIMP_PRECISION_U8_NON_LINEAR;
}
else
{
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Unsupported bit depth %d"), ia->depth);
return -1;
}
break;
default:
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Unsupported bit depth %d"), ia->depth);
return -1;
break;
}
if (ia->precision == GIMP_PRECISION_U16_NON_LINEAR)
ia->bytes_per_sample = 2;
else
ia->bytes_per_sample = 1;
if (ia->base_type != GIMP_RGB)
{
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Unsupported bit depth %d"), ia->depth);
@ -1418,31 +1469,55 @@ read_channel_data (FILE *f,
guchar runcount, byte;
z_stream zstream;
g_assert (ia->bytes_per_sample <= 2);
switch (ia->compression)
{
case PSP_COMP_NONE:
if (bytespp == 1)
{
fread (pixels[0], height * width, 1, f);
fread (pixels[0], height * width * ia->bytes_per_sample, 1, f);
}
else
{
buf = g_malloc (width);
for (y = 0; y < height; y++)
buf = g_malloc (width * ia->bytes_per_sample);
if (ia->bytes_per_sample == 1)
{
guchar *p, *q;
fread (buf, width, 1, f);
/* Contrary to what the PSP specification seems to suggest
scanlines are not stored on a 4-byte boundary. */
p = buf;
q = pixels[y] + offset;
for (i = 0; i < width; i++)
for (y = 0; y < height; y++)
{
*q = *p++;
q += bytespp;
guchar *p, *q;
fread (buf, width, 1, f);
/* Contrary to what the PSP specification seems to suggest
scanlines are not stored on a 4-byte boundary. */
p = buf;
q = pixels[y] + offset;
for (i = 0; i < width; i++)
{
*q = *p++;
q += bytespp;
}
}
}
else if (ia->bytes_per_sample == 2)
{
for (y = 0; y < height; y++)
{
guint16 *p, *q;
fread (buf, width * ia->bytes_per_sample, 1, f);
/* Contrary to what the PSP specification seems to suggest
scanlines are not stored on a 4-byte boundary. */
p = (guint16 *) buf;
q = (guint16 *) (pixels[y] + offset);
for (i = 0; i < width; i++)
{
*q = GUINT16_FROM_LE (*p++);
q += bytespp / 2;
}
}
}
g_free (buf);
}
break;
@ -1467,14 +1542,18 @@ read_channel_data (FILE *f,
fread (buf, runcount, 1, f);
/* prevent buffer overflow for bogus data */
runcount = MIN (runcount, (endq - q) / bytespp);
if (runcount > (endq - q) / bytespp + ia->bytes_per_sample - 1)
{
g_printerr ("Buffer overflow decompressing RLE data.\n");
break;
}
if (bytespp == 1)
{
memmove (q, buf, runcount);
q += runcount;
}
else
else if (ia->bytes_per_sample == 1)
{
guchar *p = buf;
@ -1484,6 +1563,18 @@ read_channel_data (FILE *f,
q += bytespp;
}
}
else if (ia->bytes_per_sample == 2)
{
guint16 *p = (guint16 *) buf;
guint16 *r = (guint16 *) q;
for (i = 0; i < runcount / 2; i++)
{
*r = GUINT16_FROM_LE (*p++);
r += bytespp / 2;
}
q = (guchar *) r;
}
}
g_free (buf);
}
@ -1507,10 +1598,10 @@ read_channel_data (FILE *f,
zstream.next_out = pixels[0];
else
{
buf2 = g_malloc (npixels);
buf2 = g_malloc (npixels * ia->bytes_per_sample);
zstream.next_out = buf2;
}
zstream.avail_out = npixels;
zstream.avail_out = npixels * ia->bytes_per_sample;
if (inflate (&zstream, Z_FINISH) != Z_STREAM_END)
{
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
@ -1523,16 +1614,32 @@ read_channel_data (FILE *f,
if (bytespp > 1)
{
guchar *p, *q;
p = buf2;
q = pixels[0] + offset;
for (i = 0; i < npixels; i++)
if (ia->bytes_per_sample == 1)
{
*q = *p++;
q += bytespp;
guchar *p, *q;
p = buf2;
q = pixels[0] + offset;
for (i = 0; i < npixels; i++)
{
*q = *p++;
q += bytespp;
}
g_free (buf2);
}
else if (ia->bytes_per_sample == 2)
{
guint16 *p, *q;
p = (guint16 *) buf2;
q = (guint16 *) (pixels[0] + offset);
for (i = 0; i < npixels; i++)
{
*q = GUINT16_FROM_LE (*p++);
q += bytespp / 2;
}
g_free (buf2);
}
g_free (buf2);
}
break;
}
@ -1831,6 +1938,7 @@ read_layer_block (FILE *f,
drawable_type = GIMP_RGB_IMAGE, bytespp = 3;
else
drawable_type = GIMP_RGBA_IMAGE, bytespp = 4;
bytespp *= ia->bytes_per_sample;
layer = gimp_layer_new (image, layer_name,
width, height,
@ -1937,9 +2045,9 @@ read_layer_block (FILE *f,
bytespp);
if (bitmap_type == PSP_DIB_TRANS_MASK)
offset = 3;
offset = bytespp - ia->bytes_per_sample;
else
offset = channel_type - PSP_CHANNEL_RED;
offset = (channel_type - PSP_CHANNEL_RED) * ia->bytes_per_sample;
if (!null_layer)
{
@ -2221,8 +2329,8 @@ load_image (GFile *file,
ia.width, ia.height,
compression_name (ia.compression));
image = gimp_image_new (ia.width, ia.height,
ia.grayscale ? GIMP_GRAY : GIMP_RGB);
image = gimp_image_new_with_precision (ia.width, ia.height,
ia.base_type, ia.precision);
if (! image)
{
goto error;