Handle INDEXA images if the indexed palette is full by looking for an

2002-09-10  Dave Neary  <bolsh@gimp.org>

        * plug-ins/common/png.c: Handle INDEXA images if the
        indexed palette is full by looking for an unused colour.
        Fixes bug #55700.
This commit is contained in:
Dave Neary 2002-09-10 16:46:41 +00:00 committed by David Neary
parent d7e0e05374
commit 734a786101
2 changed files with 141 additions and 18 deletions

View File

@ -1,3 +1,9 @@
2002-09-10 Dave Neary <bolsh@gimp.org>
* plug-ins/common/png.c: Handle INDEXA images if the
indexed palette is full by looking for an unused colour.
Fixes bug #55700.
2002-09-09 Jakub Steiner <jimmac@ximian.com>
* themes/Default/images/stock-grow-16.png:

View File

@ -98,14 +98,18 @@ static gint save_image (gchar *filename,
gint32 drawable_ID,
gint32 orig_image_ID);
static void respin_cmap (png_structp pp,
png_infop info,
gint32 image_ID);
static void respin_cmap (png_structp pp,
png_infop info,
gint32 image_ID,
GimpDrawable *drawable);
static gint save_dialog (void);
static void save_ok_callback (GtkWidget *widget,
gpointer data);
static int find_unused_ia_colour (guchar *pixels,
int numpixels,
int* colors);
/*
* Globals...
@ -134,6 +138,56 @@ static gboolean runme = FALSE;
MAIN()
/* Try to find a colour in the palette which isn't actually
* used in the image, so that we can use it as the transparency
* index. Taken from gif.c */
static int find_unused_ia_colour (guchar *pixels,
int numpixels,
int* colors)
{
int i;
gboolean ix_used[256];
g_print ("PNG: fuiac: Image claims to use %d/256 indices - finding free "
"index...\n", (*colors));
for (i = 0; i < 256; i++)
{
ix_used[i] = (gboolean)FALSE;
}
for (i = 0; i < numpixels; i++)
{
/* If there is no alpha, then the index associated with
* this pixel is taken */
if (pixels[i*2+1]) ix_used[pixels[i*2]] = (gboolean)TRUE;
}
for (i = 0; i < 256; i++)
{
if (ix_used[i] == (gboolean)FALSE)
{
g_print ("PNG: Found unused colour index %d.\n", i);
return i;
}
}
/* Couldn't find an unused colour index within the number of
bits per pixel we wanted. Will have to increment the number
of colours in the image and assign a transparent pixel there. */
if ((*colors) < 256)
{
(*colors)++;
g_print ("PNG: 2nd pass - Increasing bounds and using colour index %d.\n"
, (int) (*colors)-1);
return ((*colors)-1);
}
g_message (_("PNG: Couldn't simply reduce colors further.\nSaving as opaque.\n"));
return (-1);
}
/*
* 'query()' - Respond to a plug-in query...
*/
@ -827,7 +881,7 @@ save_image (gchar *filename, /* I - File to save to */
case GIMP_INDEXEDA_IMAGE :
bpp = 2;
info->color_type = PNG_COLOR_TYPE_PALETTE;
respin_cmap (pp, info, image_ID); /* fix up transparency */
respin_cmap (pp, info, image_ID, drawable); /* fix up transparency */
break;
default:
g_message ("%s\nImage type can't be saved as PNG", filename);
@ -999,31 +1053,94 @@ save_ok_callback (GtkWidget *widget,
are left at the FRONT, this is only needed to reduce the size of the
tRNS chunk when saving GIF-like transparent images with colormaps */
static void respin_cmap (png_structp pp, png_infop info, gint32 image_ID) {
static void respin_cmap (png_structp pp,
png_infop info,
gint32 image_ID,
GimpDrawable *drawable)
{
static const guchar trans[] = { 0 };
static guchar after[3 * 256];
gint colors;
guchar *before;
gint transparent;
gint cols, rows;
GimpPixelRgn pixel_rgn;
guchar *pixels;
before= gimp_image_get_cmap(image_ID, &colors);
cols = drawable->width;
rows = drawable->height;
gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0,
drawable->width, drawable->height,
FALSE, FALSE);
pixels = (guchar *) g_malloc (drawable->width *
drawable->height * 2);
gimp_pixel_rgn_get_rect (&pixel_rgn, pixels, 0, 0,
drawable->width, drawable->height);
/* Try to find an entry which isn't actually used in the
image, for a transparency index. */
transparent = find_unused_ia_colour(pixels,
drawable->width * drawable->height,
&colors);
g_free(pixels);
#if PNG_LIBPNG_VER > 99
if (colors < 256) { /* spare space in palette :) */
GimpRGB color;
if (transparent != -1) /* we have a winner for a transparent
* index */
{
GimpRGB color;
memcpy(after + 3, before, colors * 3);
/* Copy from index 0 to index transparent - 1 to index 1 to
* transparent of after, then from transparent+1 to colors-1
* unchanged, and finally from index transparent to index 0. */
/* Apps with no natural background will use this instead, see
elsewhere for the bKGD chunk being written to use index 0 */
gimp_palette_get_background (&color);
gimp_rgb_get_uchar (&color, after+0, after+1, after+2);
g_print ("PNG: Copying from index 0 to index %d of \"before\" ",
transparent - 1);
g_print ("to index 1 to index %d of \"after\".\n", transparent);
memcpy(after + 3, before, transparent * 3);
/* One transparent palette entry, alpha == 0 */
png_set_tRNS(pp, info, (png_bytep) trans, 1, NULL);
png_set_PLTE(pp, info, (png_colorp) after, colors + 1);
} else {
png_set_PLTE(pp, info, (png_colorp) before, colors);
}
/* We need a check that transparent != colors - 1 */
if ( transparent < colors - 1)
{
g_print ("PNG: Copying from index %d to index %d of \"before\" ",
transparent +1, colors - 1);
g_print ("to index %d to index %d of \"after\".\n",
transparent +1, colors - 1);
memcpy(after + 3 * (transparent + 1),
before + 3 * (transparent + 1),
(colors - transparent - 1) * 3);
}
g_print ("PNG: Copying from index %d of \"before\" ",
transparent );
g_print ("to index 0 of \"after\".\n");
memcpy(after, before + 3 * transparent, 3);
/* Apps with no natural background will use this instead, see
elsewhere for the bKGD chunk being written to use index 0 */
gimp_palette_get_background (&color);
gimp_rgb_get_uchar (&color, after+0, after+1, after+2);
/* One transparent palette entry, alpha == 0 */
png_set_tRNS(pp, info, (png_bytep) trans, 1, NULL);
png_set_PLTE(pp, info, (png_colorp) after, colors);
}
else
{
/* Inform the user that we couldn't losslessly save the
* transparency & just use the full palette */
g_message ( _("Couldn't losslessly save transparency, saving opacity instead.\n"));
png_set_PLTE (pp, info, (png_colorp) before, colors);
}
#else
info->valid |= PNG_INFO_PLTE;
info->palette= (png_colorp) before;