Reorganized and revised PNG encoder to avoid emitting some spurious warnings.
diff --git a/ChangeLog b/ChangeLog
index 7536875..df285c4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,6 @@
+2010-10-29 6.6.5-9 Glenn Randers-Pehrson <glennrp@image...>
+ * Revised PNG encoder to avoid emitting some spurious warnings.
+
2010-11-08 6.6.5-8 Nicolas robidoux <nicolas.robidoux@gmail...>
* Missing logical operator in tiff.c.
diff --git a/coders/png.c b/coders/png.c
index 0aa7ece..3f6de67 100644
--- a/coders/png.c
+++ b/coders/png.c
@@ -6155,8 +6155,8 @@
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
-% OptimizePNGColormap compresses an image colormap removing
-% any duplicate and unused color entries and putting the transparent colors
+% OptimizePNGColormap compresses an image colormap removing any
+% duplicate and unused color entries and putting the transparent colors
% first. Returns MagickTrue on success, MagickFalse on error.
%
% The format of the OptimizePNGColormap method is:
@@ -6166,13 +6166,17 @@
% A description of each parameter follows:
%
% o image: the address of a structure of type Image.
-% This function updates image->colors and image->colormap.
+%
+% o ping_plte_map: a mapping of indexes in image->colormap to those in
+% the revised colormap
+%
+% o opacity: opacity of pixels corresponding to the revised colormap
%
*/
-static MagickBooleanType OptimizePNGColormap(Image *image, IndexPacket *opt_map)
+static MagickBooleanType OptimizePNGColormap(Image *image, IndexPacket
+ *ping_plte_map, IndexPacket *opacity)
{
int
- remap_needed,
k;
ssize_t
@@ -6181,9 +6185,6 @@
number_colors,
y;
- PixelPacket
- *colormap;
-
register const IndexPacket
*indexes;
@@ -6193,15 +6194,15 @@
IndexPacket
top_used;
+ MagickBooleanType
+ remap_needed;
+
register ssize_t
i,
x;
- IndexPacket
- *opacity;
-
unsigned char
- *marker,
+ marker[256],
have_transparency;
/*
@@ -6209,34 +6210,36 @@
*/
assert(image != (Image *) NULL);
assert(image->signature == MagickSignature);
+
+ remap_needed=MagickFalse;
+
if (image->debug != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" OptimizePNGColormap %s (%.20g colors)",image->filename,
(double) image->colors);
- if (image->storage_class != PseudoClass || image->colors > 256 ||
- image->colors < 2)
+
+ if (image->storage_class != PseudoClass)
{
if (image->debug != MagickFalse)
{
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " Could not compress colormap");
- if (image->colors > 256 || image->colors == 0)
- return(MagickFalse);
- else
- return(MagickTrue);
+ " Could not compress colormap: image is not PseudoClass");
}
+ return(MagickTrue);
}
- marker=(unsigned char *) AcquireQuantumMemory(image->colors,sizeof(*marker));
- if (marker == (unsigned char *) NULL)
- ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
- image->filename);
- opacity=(IndexPacket *) AcquireQuantumMemory(image->colors,sizeof(*opacity));
- if (opacity == (IndexPacket *) NULL)
+
+ if (image->colors == 1)
+ return(MagickTrue); /* Nothing to do */
+
+ if (image-> colors == 0 || image->colors > 256)
{
- marker=(unsigned char *) RelinquishMagickMemory(marker);
- ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
- image->filename);
+ if (image->debug != MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Could not compress colormap with %d",(int) image->colors);
+
+ return(MagickFalse);
}
+
/*
Mark colors that are present.
*/
@@ -6246,28 +6249,36 @@
marker[i]=MagickFalse;
opacity[i]=OpaqueOpacity;
}
+
top_used=0;
for (y=0; y < (ssize_t) image->rows; y++)
{
p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
+
if (p == (const PixelPacket *) NULL)
break;
+
indexes=GetVirtualIndexQueue(image);
+
if (image->matte != MagickFalse)
for (x=0; x < (ssize_t) image->columns; x++)
{
- marker[(int) indexes[x]]=MagickTrue;
- opacity[(int) indexes[x]]=GetOpacityPixelComponent(p);
- if (indexes[x] > top_used)
- top_used=indexes[x];
+ i=(int) indexes[x];
+ marker[i]=MagickTrue;
+ opacity[i]=GetOpacityPixelComponent(p);
+
+ if (i > top_used)
+ top_used=i;
p++;
}
+
else
for (x=0; x < (ssize_t) image->columns; x++)
{
- marker[(int) indexes[x]]=MagickTrue;
- if (indexes[x] > top_used)
- top_used=indexes[x];
+ i=(int) indexes[x];
+ marker[i]=MagickTrue;
+ if (i > top_used)
+ top_used=i;
}
}
@@ -6279,14 +6290,6 @@
if (IsColorEqual(image->colormap+i,&image->background_color))
{
marker[i]=MagickTrue;
- if (image->debug != MagickFalse)
- {
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " Background in OptimizePNGColormap=%d (%d,%d,%d)",
- (int) i,(int) image->colormap[i].red,
- (int) image->colormap[i].green,
- (int) image->colormap[i].blue);
- }
break;
}
}
@@ -6302,26 +6305,15 @@
(IsColorEqual(image->colormap+i,image->colormap+j)))
{
marker[j]=MagickFalse;
- if (image->debug != MagickFalse)
- {
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " Dupe OptimizePNGColormap=%d(%d,%d,%d)=%d(%d,%d,%d)",
- (int) j,
- (int) image->colormap[j].red,
- (int) image->colormap[j].green,
- (int) image->colormap[j].blue,
- (int) i,
- (int) image->colormap[i].red,
- (int) image->colormap[i].green,
- (int) image->colormap[i].blue);
- }
}
}
+
/*
Count colors that still remain.
*/
have_transparency=MagickFalse;
new_number_colors=0;
+
for (i=0; i < number_colors; i++)
if (marker[i])
{
@@ -6329,12 +6321,14 @@
if (opacity[i] != OpaqueOpacity)
have_transparency=MagickTrue;
}
+
if (image->debug != MagickFalse)
{
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " new_number_colors in OptimizePNGColormap=%d",
- (int) new_number_colors);
+ " new_number_colors in OptimizePNGColormap=%d",
+ (int) new_number_colors);
}
+
if ((!have_transparency || (marker[0] &&
(opacity[0] == (Quantum) TransparentOpacity)))
&& (new_number_colors == number_colors))
@@ -6342,68 +6336,37 @@
/*
No duplicate or unused entries, and transparency-swap not needed.
*/
- marker=(unsigned char *) RelinquishMagickMemory(marker);
- opacity=(IndexPacket *) RelinquishMagickMemory(opacity);
+
return(MagickTrue);
}
- remap_needed=MagickFalse;
- if ((ssize_t) top_used >= new_number_colors)
- remap_needed=MagickTrue;
+ remap_needed=MagickTrue;
/*
- Compress colormap.
- */
-
- colormap=(PixelPacket *) AcquireQuantumMemory(image->colors,
- sizeof(*colormap));
- if (colormap == (PixelPacket *) NULL)
- {
- marker=(unsigned char *) RelinquishMagickMemory(marker);
- opacity=(IndexPacket *) RelinquishMagickMemory(opacity);
- ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
- image->filename);
- }
- /*
Eliminate unused colormap entries.
*/
- if (opt_map == (IndexPacket *) NULL)
- {
- marker=(unsigned char *) RelinquishMagickMemory(marker);
- opacity=(IndexPacket *) RelinquishMagickMemory(opacity);
- colormap=(PixelPacket *) RelinquishMagickMemory(colormap);
- ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
- image->filename);
- }
for (i=0; i < number_colors; i++)
- opt_map[i]=0;
+ ping_plte_map[i]=i;
+
k=0;
for (i=0; i < number_colors; i++)
{
if (marker[i])
{
- opt_map[i]=(IndexPacket) k;
+ ping_plte_map[i]=(IndexPacket) k;
for (j=i+1; j < number_colors; j++)
{
if ((opacity[i] == opacity[j]) &&
(IsColorEqual(image->colormap+i,image->colormap+j)))
{
- opt_map[j]=(IndexPacket) k;
+ ping_plte_map[j]=(IndexPacket) k;
marker[j]=MagickFalse;
}
}
k++;
}
}
- j=0;
- for (i=0; i < number_colors; i++)
- {
- if (marker[i])
- {
- colormap[j]=image->colormap[i];
- j++;
- }
- }
+
if (have_transparency && (opacity[0] != (Quantum) TransparentOpacity))
{
/*
@@ -6413,18 +6376,12 @@
{
if (marker[i] && opacity[i] == (Quantum) TransparentOpacity)
{
- PixelPacket
- temp_colormap;
-
- temp_colormap=colormap[0];
- colormap[0]=colormap[(int) opt_map[i]];
- colormap[(ssize_t) opt_map[i]]=temp_colormap;
for (j=0; j < number_colors; j++)
{
- if (opt_map[j] == 0)
- opt_map[j]=opt_map[i];
- else if (opt_map[j] == opt_map[i])
- opt_map[j]=0;
+ if (ping_plte_map[j] == 0)
+ ping_plte_map[j]=ping_plte_map[i];
+ else if (ping_plte_map[j] == ping_plte_map[i])
+ ping_plte_map[j]=0;
}
remap_needed=MagickTrue;
break;
@@ -6432,73 +6389,142 @@
}
}
- if (remap_needed)
- {
- ExceptionInfo
- *exception;
-
- register IndexPacket
- *pixels;
-
- register PixelPacket
- *q;
-
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " i mark opt_map (red,green,blue,opacity)");
- for (i=0; i < (ssize_t) image->colors; i++)
- {
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " %d %d %d (%d,%d,%d,%d)",
- (int) i,
- (int) marker[i],
- (int) opt_map[i],
- (int) image->colormap[i].red,
- (int) image->colormap[i].green,
- (int) image->colormap[i].blue,
- (int) opacity[i]);
- }
-
- /*
- Remap pixels.
- */
- exception=(&image->exception);
- for (y=0; y < (ssize_t) image->rows; y++)
- {
- q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
- if (q == (PixelPacket *) NULL)
- break;
- pixels=GetAuthenticIndexQueue(image);
- for (x=0; x < (ssize_t) image->columns; x++)
- {
- j=(int) pixels[x];
- pixels[x]=(IndexPacket) opt_map[j];
- }
- if (SyncAuthenticPixels(image,exception) == MagickFalse)
- break;
- }
- for (i=0; i < new_number_colors; i++)
- image->colormap[i]=colormap[i];
- for (; i < (ssize_t) image->colors; i++)
- image->colormap[i]=colormap[0];
- }
-
- marker=(unsigned char *) RelinquishMagickMemory(marker);
- colormap=(PixelPacket *) RelinquishMagickMemory(colormap);
- opacity=(IndexPacket *) RelinquishMagickMemory(opacity);
-
- image->colors=(size_t) new_number_colors;
- (void) SyncImage(image);
-
return(MagickTrue);
}
-#endif
+#endif /* PNG_SORT_PALETTE */
+/*
+ * Temporary wrapper for OptimizePNGColormap
+ */
static MagickBooleanType CompressColormapTransFirst(Image *image)
{
- IndexPacket
- opt_map[256];
+#if defined(PNG_SORT_PALETTE)
+ register ssize_t
+ i;
- return OptimizePNGColormap(image, opt_map);
+ IndexPacket
+ opacity[256],
+ ping_plte_map[256];
+
+ for (i=0; i<256; i++)
+ {
+ ping_plte_map[i]=i;
+ opacity[i]=0;
+ }
+
+ if (OptimizePNGColormap(image, ping_plte_map, opacity) == MagickFalse)
+ return MagickFalse;
+
+ else
+ {
+ ExceptionInfo
+ *exception;
+
+ register IndexPacket
+ *pixels;
+
+ PixelPacket
+ colormap[256];
+
+ register PixelPacket
+ *q;
+
+ MagickBooleanType
+ remap_needed;
+
+ size_t
+ ping_number_colors;
+
+ ssize_t
+ j,
+ y;
+
+ register ssize_t
+ x;
+
+ ping_number_colors=(size_t) 0;
+ remap_needed = MagickFalse;
+
+ for (i=0; i<image->colors; i++)
+ {
+ colormap[ping_plte_map[i]] = image->colormap[i];
+
+ if (ping_plte_map[i] != i)
+ remap_needed = MagickTrue;
+
+ if (ping_plte_map[i] >= ping_number_colors)
+ ping_number_colors=ping_plte_map[i]+1;
+ }
+
+ /* TO DO: add background color if necessary */
+
+ if (remap_needed == MagickFalse)
+ return MagickTrue;
+
+ /*
+ Remap pixels.
+ */
+ exception=(&image->exception);
+ for (y=0; y < (ssize_t) image->rows; y++)
+ {
+ q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
+ if (q == (PixelPacket *) NULL)
+ break;
+ pixels=GetAuthenticIndexQueue(image);
+ for (x=0; x < (ssize_t) image->columns; x++)
+ {
+ j=(int) pixels[x];
+ pixels[x]=(IndexPacket) ping_plte_map[j];
+ }
+ if (SyncAuthenticPixels(image,exception) == MagickFalse)
+ break;
+ }
+
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " After OptimizePNGColormap:");
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " i plte_map (red,green,blue,opacity)");
+ for (i=0; i < image->colors; i++)
+ {
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " %d %d (%d,%d,%d,%d)",
+ (int) i,
+ (int) ping_plte_map[i],
+ (int) image->colormap[i].red,
+ (int) image->colormap[i].green,
+ (int) image->colormap[i].blue,
+ (int) opacity[ping_plte_map[i]]);
+ }
+
+
+ for (i=0; i<image->colors; i++)
+ {
+ image->colormap[i] = colormap[i];
+ }
+
+ image->colors = ping_number_colors;
+
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " After Remap:");
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " i (red,green,blue,opacity)");
+ for (i=0; i < image->colors; i++)
+ {
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " %d (%d,%d,%d,%d)",
+ (int) i,
+ (int) image->colormap[i].red,
+ (int) image->colormap[i].green,
+ (int) image->colormap[i].blue,
+ (int) opacity[i]);
+ }
+
+ return MagickTrue;
+ }
+#else
+ image=image;
+ return MagickTrue;
+#endif /* PNG_SORT_PALETTE */
}
static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info,
@@ -6546,6 +6572,9 @@
y;
MagickBooleanType
+ ping_have_bKGD,
+ ping_have_pHYs,
+ ping_have_tRNS,
status;
QuantumInfo
@@ -6606,6 +6635,10 @@
ping_trans_color.blue=0;
ping_trans_color.gray=0;
+ ping_have_bKGD=MagickFalse;
+ ping_have_pHYs=MagickFalse;
+ ping_have_tRNS=MagickFalse;
+
quantum_info = (QuantumInfo *) NULL;
image_colors=image->colors;
image_depth=image->depth;
@@ -6615,7 +6648,11 @@
(void) TransformImageColorspace(image,RGBColorspace);
mng_info->IsPalette=image->storage_class == PseudoClass &&
image_colors <= 256 && !IsOpaqueImage(image,&image->exception);
+#if 0
mng_info->optimize=image_info->type == OptimizeType;
+#else
+ mng_info->optimize = MagickFalse;
+#endif
/*
Allocate the PNG structures
@@ -6718,13 +6755,15 @@
x_resolution=(png_uint_32) (100.0*image->x_resolution);
y_resolution=(png_uint_32) (100.0*image->y_resolution);
}
+
else
{
unit_type=PNG_RESOLUTION_UNKNOWN;
x_resolution=(png_uint_32) image->x_resolution;
y_resolution=(png_uint_32) image->y_resolution;
}
- png_set_pHYs(ping,ping_info,x_resolution,y_resolution,unit_type);
+
+ ping_have_pHYs = MagickTrue;
if (logging != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" Setting up pHYs chunk");
@@ -6735,6 +6774,7 @@
{
png_set_oFFs(ping,ping_info,(png_int_32) image->page.x,
(png_int_32) image->page.y, 0);
+
if (logging != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" Setting up oFFs chunk");
@@ -6766,7 +6806,7 @@
if (logging != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" Setting up bKGd chunk");
- png_set_bKGD(ping,ping_info,&ping_background);
+ ping_have_bKGD = MagickTrue;
/*
Select the color type.
*/
@@ -6810,12 +6850,10 @@
Set image palette.
*/
ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
-#if defined(PNG_SORT_PALETTE)
if (CompressColormapTransFirst(image) == MagickFalse)
ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
number_colors=image->colors;
image_colors=number_colors;
-#endif
palette=(png_color *) AcquireQuantumMemory(257,
sizeof(*palette));
if (palette == (png_color *) NULL)
@@ -6897,10 +6935,7 @@
ping_trans_alpha[i]=(png_byte) trans_alpha[i];
}
- (void) png_set_tRNS(ping, ping_info,
- ping_trans_alpha,
- ping_num_trans,
- &ping_trans_color);
+ ping_have_tRNS=MagickTrue;
}
/*
Identify which colormap entry is the background color.
@@ -7123,8 +7158,7 @@
(ScaleQuantumToShort(PixelIntensityToQuantum(p)) & mask);
ping_trans_color.index=(png_byte)
(ScaleQuantumToChar((Quantum) (GetAlphaPixelComponent(p))));
- (void) png_set_tRNS(ping, ping_info, NULL, 0,
- &ping_trans_color);
+ ping_have_tRNS=MagickTrue;
}
if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
{
@@ -7274,7 +7308,6 @@
}
else
{
-#if defined(PNG_SORT_PALETTE)
if (mng_info->optimize)
{
if (CompressColormapTransFirst(image) == MagickFalse)
@@ -7283,7 +7316,6 @@
number_colors=image->colors;
image_colors=number_colors;
}
-#endif
palette=(png_color *) AcquireQuantumMemory(257,
sizeof(*palette));
if (palette == (png_color *) NULL)
@@ -7439,7 +7471,7 @@
if (logging != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" Setting up bKGD chunk");
- png_set_bKGD(ping,ping_info,&ping_background);
+ ping_have_bKGD = MagickTrue;
ping_trans_color.gray=(png_uint_16) (QuantumScale*(maxval*
ping_trans_color.gray));
@@ -7468,9 +7500,9 @@
" Setting up bKGD chunk with index=%d",(int) i);
}
- if (i < (ssize_t) number_colors)
+ if (i < number_colors)
{
- png_set_bKGD(ping,ping_info,&ping_background);
+ ping_have_bKGD = MagickTrue;
if (logging)
{
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
@@ -7482,7 +7514,7 @@
}
else
- png_set_invalid(ping,ping_info,PNG_INFO_bKGD);
+ ping_have_bKGD = MagickFalse;
}
if (logging != MagickFalse)
@@ -7707,20 +7739,11 @@
" Added an opaque matte channel");
}
- if (image->matte == MagickTrue && ping_color_type < 4)
+ if (image->matte == MagickTrue)
{
- if (ping_color_type == 3 && ping_num_trans == 0)
- {
- png_set_invalid(ping,ping_info,PNG_INFO_tRNS);
- if (logging != MagickFalse)
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " Ignoring request to write tRNS chunk with num_trans==0");
- }
- else
- (void) png_set_tRNS(ping, ping_info,
- ping_trans_alpha,
- ping_num_trans,
- &ping_trans_color);
+ if (ping_color_type < 4)
+ if (ping_color_type != 3 || ping_num_trans > 0)
+ ping_have_tRNS=MagickTrue;
}
if (logging != MagickFalse)
@@ -7732,10 +7755,36 @@
ping_interlace_method,ping_compression_method,
ping_filter_method);
+ if (ping_have_bKGD != MagickFalse)
+ png_set_bKGD(ping,ping_info,&ping_background);
+
png_write_info_before_PLTE(ping, ping_info);
+
+ if (ping_have_tRNS != MagickFalse)
+ {
+ if (logging)
+ {
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ "Calling png_set_tRNS");
+ }
+
+ if (ping_color_type == 3)
+ (void) png_set_tRNS(ping, ping_info,
+ ping_trans_alpha,
+ ping_num_trans,
+ NULL);
+
+ else if (ping_color_type < 3)
+ (void) png_set_tRNS(ping, ping_info,
+ NULL,
+ 0,
+ &ping_trans_color);
+ }
+
/* write any png-chunk-b profiles */
(void) png_write_chunk_from_profile(image,"PNG-chunk-b",(int) logging);
png_write_info(ping,ping_info);
+
/* write any PNG-chunk-m profiles */
(void) png_write_chunk_from_profile(image,"PNG-chunk-m",(int) logging);