/* #define PNG_ALLOCATED The result of the function is new memory */
/* #define PNG_DEPSTRUCT Access to this struct member is deprecated */
+/* PNG_PTR_NORETURN does not work on some platforms, in libpng-1.5.x */
+#define PNG_PTR_NORETURN
+
#include "png.h"
#include "zlib.h"
\f
#undef MNG_BASI_SUPPORTED
#define MNG_COALESCE_LAYERS /* In 5.4.4, this interfered with MMAP'ed files. */
#define MNG_INSERT_LAYERS /* Troublesome, but seem to work as of 5.4.4 */
-#define BUILD_PNG_PALETTE /* This works as of 6.6.6 */
#if defined(MAGICKCORE_JPEG_DELEGATE)
# define JNG_SUPPORTED /* Not finished as of 5.5.2. See "To do" comments. */
#endif
#if !defined(RGBColorMatchExact)
#define IsPNGColorEqual(color,target) \
- (((color).red == (target).red) && \
- ((color).green == (target).green) && \
- ((color).blue == (target).blue))
+ (((color).red == (target).red) && \
+ ((color).green == (target).green) && \
+ ((color).blue == (target).blue))
#endif
+/* Convenience macros for copying RGB or RGB+opacity components
+ * between a pixel and a PixelPacket.
+ */
+
+#define GetRGBOPixelComponents(pixel, packet) \
+ (packet).red = GetRedPixelComponent((pixel)); \
+ (packet).green = GetGreenPixelComponent((pixel)); \
+ (packet).red = GetBluePixelComponent((pixel)); \
+ (packet).opacity = GetOpacityPixelComponent((pixel)); \
+
+#define SetRGBOPixelComponents(pixel, packet) \
+ SetRedPixelComponent((pixel),(packet).red); \
+ SetGreenPixelComponent((pixel),(packet).green); \
+ SetBluePixelComponent((pixel),(packet).blue); \
+ SetOpacityPixelComponent((pixel),(packet).opacity); \
+
+
+#define GetRGBPixelComponents(pixel, packet) \
+ (packet).red = GetRedPixelComponent((pixel)); \
+ (packet).green = GetGreenPixelComponent((pixel)); \
+ (packet).red = GetBluePixelComponent((pixel));
+
+#define SetRGBPixelComponents(pixel, packet) \
+ SetRedPixelComponent((pixel),(packet).red); \
+ SetGreenPixelComponent((pixel),(packet).green); \
+ SetBluePixelComponent((pixel),(packet).blue);
+
/*
Establish thread safety.
setjmp/longjmp is claimed to be safe on these platforms:
MagickBooleanType
ping_exclude_bKGD,
ping_exclude_cHRM,
+ ping_exclude_date,
ping_exclude_EXIF,
ping_exclude_gAMA,
ping_exclude_iCCP,
ping_exclude_tRNS,
ping_exclude_vpAg,
ping_exclude_zCCP, /* hex-encoded iCCP */
- ping_exclude_zTXt;
+ ping_exclude_zTXt,
+ ping_preserve_colormap;
} MngInfo;
#endif /* VER */
#if PNG_LIBPNG_VER > 10011
+
#if (MAGICKCORE_QUANTUM_DEPTH >= 16)
static MagickBooleanType
- LosslessReduceDepthOK(Image *image)
+LosslessReduceDepthOK(Image *image)
{
+ /* Reduce bit depth if it can be reduced losslessly from 16+ to 8.
+ *
+ * This is true if the high byte and the next highest byte of
+ * each sample of the image, the colormap, and the background color
+ * are equal to each other. We check this by seeing if the samples
+ * are unchanged when we scale them down to 8 and back up to Quantum.
+ *
+ * We don't use the method GetImageDepth() because it doesn't check
+ * background and doesn't handle PseudoClass specially.
+ */
+
+#define QuantumToCharToQuantumEqQuantum(quantum) \
+ ((ScaleCharToQuantum((unsigned char) ScaleQuantumToChar(quantum))) == quantum)
+
MagickBooleanType
ok_to_reduce=MagickFalse;
- /* Reduce bit depth if it can be reduced losslessly from 16 to 8.
- * Note that the method GetImageDepth doesn't check background
- * and doesn't handle PseudoClass specially. Also it uses
- * multiplication and division by 257 instead of shifting, so
- * might be slower.
- */
-
- if (image->depth == 16)
+ if (image->depth >= 16)
{
const PixelPacket
*p;
ok_to_reduce=
- (((((size_t) image->background_color.red >> 8) & 0xff)
- == ((size_t) image->background_color.red & 0xff)) &&
- ((((size_t) image->background_color.green >> 8) & 0xff)
- == ((size_t) image->background_color.green & 0xff)) &&
- ((((size_t) image->background_color.blue >> 8) & 0xff)
- == ((size_t) image->background_color.blue & 0xff))) ? MagickTrue :
- MagickFalse;
+ QuantumToCharToQuantumEqQuantum(image->background_color.red) &&
+ QuantumToCharToQuantumEqQuantum(image->background_color.green) &&
+ QuantumToCharToQuantumEqQuantum(image->background_color.blue) ?
+ MagickTrue : MagickFalse;
if (ok_to_reduce != MagickFalse && image->storage_class == PseudoClass)
{
for (indx=0; indx < (ssize_t) image->colors; indx++)
{
- ok_to_reduce=(((((size_t) image->colormap[indx].red >>
- 8) & 0xff)
- == ((size_t) image->colormap[indx].red & 0xff)) &&
- ((((size_t) image->colormap[indx].green >> 8) & 0xff)
- == ((size_t) image->colormap[indx].green & 0xff)) &&
- ((((size_t) image->colormap[indx].blue >> 8) & 0xff)
- == ((size_t) image->colormap[indx].blue & 0xff)) &&
- (image->matte == MagickFalse ||
- (((size_t) image->colormap[indx].opacity >> 8) & 0xff)
- == ((size_t) image->colormap[indx].opacity & 0xff))) ?
- MagickTrue : MagickFalse;
+ ok_to_reduce=(
+ QuantumToCharToQuantumEqQuantum(
+ image->colormap[indx].red) &&
+ QuantumToCharToQuantumEqQuantum(
+ image->colormap[indx].green) &&
+ QuantumToCharToQuantumEqQuantum(
+ image->colormap[indx].blue)) ?
+ MagickTrue : MagickFalse;
+
if (ok_to_reduce == MagickFalse)
- break;
+ break;
}
}
for (x=(ssize_t) image->columns-1; x >= 0; x--)
{
- ok_to_reduce=((
- (((size_t) p->red >> 8) & 0xff) ==
- ((size_t) p->red & 0xff)) &&
- ((((size_t) p->green >> 8) & 0xff) ==
- ((size_t) p->green & 0xff)) &&
- ((((size_t) p->blue >> 8) & 0xff) ==
- ((size_t) p->blue & 0xff)) &&
- (((image->matte == MagickFalse ||
- (((size_t) p->opacity >> 8) & 0xff) ==
- ((size_t) p->opacity & 0xff))))) ? MagickTrue : MagickFalse;
+ ok_to_reduce=
+ QuantumToCharToQuantumEqQuantum(GetRedPixelComponent(p)) &&
+ QuantumToCharToQuantumEqQuantum(GetGreenPixelComponent(p)) &&
+ QuantumToCharToQuantumEqQuantum(GetBluePixelComponent(p)) ?
+ MagickTrue : MagickFalse;
if (ok_to_reduce == MagickFalse)
break;
if (ok_to_reduce != MagickFalse)
{
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " OK to reduce PNG bit depth to 8 without loss of info");
+ " OK to reduce PNG bit depth to 8 without loss of info");
}
else
{
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " Not OK to reduce PNG bit depth to 8 without loss of info");
+ " Not OK to reduce PNG bit depth to 8 without loss of info");
}
}
}
return(MagickTrue);
}
-\f
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% %
-% %
-% %
-% I m a g e I s M o n o c h r o m e %
-% %
-% %
-% %
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% %
-% Like IsMonochromeImage except does not change DirectClass to PseudoClass %
-% and is more accurate. %
-% %
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-*/
-static MagickBooleanType ImageIsMonochrome(Image *image)
-{
- register const PixelPacket
- *p;
-
- register ssize_t
- i,
- x,
- y;
-
- assert(image != (Image *) NULL);
- assert(image->signature == MagickSignature);
- if (image->debug != MagickFalse)
- (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
- if (image->storage_class == PseudoClass)
- {
- for (i=0; i < (ssize_t) image->colors; i++)
- {
- if ((IsGray(image->colormap+i) == MagickFalse) ||
- ((image->colormap[i].red != 0) &&
- (image->colormap[i].red != (Quantum) QuantumRange)))
- return(MagickFalse);
- }
- return(MagickTrue);
- }
- for (y=0; y < (ssize_t) image->rows; y++)
- {
- p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
- if (p == (const PixelPacket *) NULL)
- return(MagickFalse);
- for (x=(ssize_t) image->columns-1; x >= 0; x--)
- {
- if ((p->red != 0) && (p->red != (Quantum) QuantumRange))
- return(MagickFalse);
-
- if (IsGray(p) == MagickFalse)
- return(MagickFalse);
-
- if ((p->opacity != OpaqueOpacity) &&
- (p->opacity != (Quantum) TransparentOpacity))
- return(MagickFalse);
-
- p++;
- }
- }
- return(MagickTrue);
-}
#endif /* PNG_LIBPNG_VER > 10011 */
#endif /* MAGICKCORE_PNG_DELEGATE */
\f
length=(png_uint_32) StringToLong(sp);
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " length: %lu",(unsigned long) length);
+
while (*sp != ' ' && *sp != '\n')
sp++;
{
/* Read one PNG image */
+ /* To do: Read the tIME chunk into the date:modify property */
+ /* To do: Read the tEXt/Creation Time chunk into the date:create property */
+
Image
*image;
int
+ intent,
+ num_raw_profiles,
num_text,
+ num_text_total,
num_passes,
pass,
ping_bit_depth,
ping_interlace_method,
ping_compression_method,
ping_filter_method,
- ping_num_trans;
+ ping_num_trans,
+ unit_type;
+
+ double
+ file_gamma;
LongPixelPacket
transparent_color;
png_uint_32
ping_height,
ping_width,
- ping_rowbytes;
+ ping_rowbytes,
+ x_resolution,
+ y_resolution;
QuantumInfo
*quantum_info;
length,
row_offset;
+ ssize_t
+ j;
+
#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
png_byte unused_chunks[]=
{
#endif
logging=LogMagickEvent(CoderEvent,GetMagickModule(),
- " enter ReadOnePNGImage()");
+ " Enter ReadOnePNGImage()");
#if defined(PNG_SETJMP_NOT_THREAD_SAFE)
LockSemaphoreInfo(ping_semaphore);
transparent_color.blue=65537;
transparent_color.opacity=65537;
+ num_text = 0;
+ num_text_total = 0;
+ num_raw_profiles = 0;
+
/*
Allocate the PNG structures
*/
#endif
#if defined(PNG_READ_sRGB_SUPPORTED)
{
- int
- intent;
-
if (mng_info->have_global_srgb)
image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
(mng_info->global_srgb_intent);
}
#endif
{
- double
- file_gamma;
-
if (!png_get_gAMA(ping,ping_info,&file_gamma))
if (mng_info->have_global_gama)
png_set_gAMA(ping,ping_info,mng_info->global_gamma);
#if defined(PNG_oFFs_SUPPORTED)
if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
{
- image->page.x=png_get_x_offset_pixels(ping, ping_info);
- image->page.y=png_get_y_offset_pixels(ping, ping_info);
+ image->page.x=(ssize_t) png_get_x_offset_pixels(ping, ping_info);
+ image->page.y=(ssize_t) png_get_y_offset_pixels(ping, ping_info);
if (logging != MagickFalse)
if (image->page.x || image->page.y)
if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
{
- int
- unit_type;
-
- png_uint_32
- x_resolution,
- y_resolution;
-
/*
Set image resolution.
*/
(double) x_resolution,(double) y_resolution,unit_type);
}
#endif
+
if (png_get_valid(ping,ping_info,PNG_INFO_PLTE))
{
int
png_set_tRNS(ping,ping_info,mng_info->global_trns,
(int) mng_info->global_trns_length,NULL);
}
-#if defined(PNG_READ_bKGD_SUPPORTED)
+#ifdef PNG_READ_bKGD_SUPPORTED
if (
#ifndef PNG_READ_EMPTY_PLTE_SUPPORTED
mng_info->have_saved_bkgd_index ||
background.blue=(png_uint_16)
mng_info->global_plte[background.index].blue;
+ background.gray=(png_uint_16)
+ mng_info->global_plte[background.index].green;
+
png_set_bKGD(ping,ping_info,&background);
}
#endif
}
}
-#if defined(PNG_READ_bKGD_SUPPORTED)
+#ifdef PNG_READ_bKGD_SUPPORTED
if (mng_info->have_global_bkgd &&
(!png_get_valid(ping,ping_info,PNG_INFO_bKGD)))
image->background_color=mng_info->mng_global_bkgd;
if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
{
+ unsigned int
+ bkgd_scale;
+
/*
Set image background color.
*/
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" Reading PNG bKGD chunk.");
- if (ping_bit_depth == MAGICKCORE_QUANTUM_DEPTH)
- {
- image->background_color.red=ping_background->red;
- image->background_color.green=ping_background->green;
- image->background_color.blue=ping_background->blue;
- }
-
- else /* Scale background components to 16-bit */
- {
- unsigned int
- bkgd_scale;
-
- if (logging != MagickFalse)
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " raw ping_background=(%d,%d,%d).",ping_background->red,
- ping_background->green,ping_background->blue);
+ /* Scale background components to 16-bit, then scale
+ * to quantum depth
+ */
+ if (logging != MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " raw ping_background=(%d,%d,%d).",ping_background->red,
+ ping_background->green,ping_background->blue);
- bkgd_scale = 1;
+ bkgd_scale = 1;
- if (ping_bit_depth == 1)
- bkgd_scale = 255;
+ if (ping_bit_depth == 1)
+ bkgd_scale = 255;
- else if (ping_bit_depth == 2)
- bkgd_scale = 85;
+ else if (ping_bit_depth == 2)
+ bkgd_scale = 85;
- else if (ping_bit_depth == 4)
- bkgd_scale = 17;
+ else if (ping_bit_depth == 4)
+ bkgd_scale = 17;
- if (ping_bit_depth <= 8)
- bkgd_scale *= 257;
+ if (ping_bit_depth <= 8)
+ bkgd_scale *= 257;
- ping_background->red *= bkgd_scale;
- ping_background->green *= bkgd_scale;
- ping_background->blue *= bkgd_scale;
+ ping_background->red *= bkgd_scale;
+ ping_background->green *= bkgd_scale;
+ ping_background->blue *= bkgd_scale;
- if (logging != MagickFalse)
- {
+ if (logging != MagickFalse)
+ {
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" bkgd_scale=%d.",bkgd_scale);
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" ping_background=(%d,%d,%d).",ping_background->red,
ping_background->green,ping_background->blue);
- }
+ }
- image->background_color.red=
+ image->background_color.red=
ScaleShortToQuantum(ping_background->red);
- image->background_color.green=
+ image->background_color.green=
ScaleShortToQuantum(ping_background->green);
- image->background_color.blue=
- ScaleShortToQuantum(ping_background->blue);
+ image->background_color.blue=
+ ScaleShortToQuantum(ping_background->blue);
- image->background_color.opacity=OpaqueOpacity;
+ image->background_color.opacity=OpaqueOpacity;
- if (logging != MagickFalse)
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " image->background_color=(%.20g,%.20g,%.20g).",
- (double) image->background_color.red,
- (double) image->background_color.green,
- (double) image->background_color.blue);
- }
+ if (logging != MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " image->background_color=(%.20g,%.20g,%.20g).",
+ (double) image->background_color.red,
+ (double) image->background_color.green,
+ (double) image->background_color.blue);
}
-#endif
+#endif /* PNG_READ_bKGD_SUPPORTED */
if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
{
image->columns=ping_width;
image->rows=ping_height;
if (((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) ||
- ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
((int) ping_color_type == PNG_COLOR_TYPE_GRAY))
{
size_t
(void) png_get_PLTE(ping,ping_info,&palette,&number_colors);
- for (i=0; i < (ssize_t) image->colors; i++)
+ for (i=0; i < (ssize_t) number_colors; i++)
{
image->colormap[i].red=ScaleCharToQuantum(palette[i].red);
image->colormap[i].green=ScaleCharToQuantum(palette[i].green);
image->colormap[i].blue=ScaleCharToQuantum(palette[i].blue);
}
+
+ for ( ; i < (ssize_t) image->colors; i++)
+ {
+ image->colormap[i].red=0;
+ image->colormap[i].green=0;
+ image->colormap[i].blue=0;
+ }
}
else
}
}
}
+
+ /* Set some properties for reporting by "identify" */
+ {
+ char
+ msg[MaxTextExtent];
+
+ /* encode ping_width, ping_height, ping_bit_depth, ping_color_type,
+ ping_interlace_method in value */
+
+ (void) FormatMagickString(msg,MaxTextExtent,
+ "%d, %d",(int) ping_width, (int) ping_height);
+ (void) SetImageProperty(image,"PNG:IHDR.width,height ",msg);
+
+ (void) FormatMagickString(msg,MaxTextExtent,"%d",(int) ping_bit_depth);
+ (void) SetImageProperty(image,"PNG:IHDR.bit_depth ",msg);
+
+ (void) FormatMagickString(msg,MaxTextExtent,"%d",(int) ping_color_type);
+ (void) SetImageProperty(image,"PNG:IHDR.color_type ",msg);
+
+ (void) FormatMagickString(msg,MaxTextExtent,"%d",
+ (int) ping_interlace_method);
+ (void) SetImageProperty(image,"PNG:IHDR.interlace_method",msg);
+ }
+
/*
Read image scanlines.
*/
if (q == (PixelPacket *) NULL)
break;
-#if (0 && (MAGICKCORE_QUANTUM_DEPTH == 8) && !defined(MAGICKCORE_HDRI_SUPPORT))
-/* code deleted from version 6.6.6-8 */
-#else /* (MAGICKCORE_QUANTUM_DEPTH != 8) */
-
if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY)
(void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
GrayQuantum,ping_pixels+row_offset,exception);
else /* ping_color_type == PNG_COLOR_TYPE_RGB */
(void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
RGBQuantum,ping_pixels+row_offset,exception);
-#endif
+
if (found_transparent_pixel == MagickFalse)
{
/* Is there a transparent pixel in the row? */
{
if ((ping_color_type == PNG_COLOR_TYPE_RGBA ||
ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) &&
- (q->opacity != OpaqueOpacity))
+ (GetOpacityPixelComponent(q) != OpaqueOpacity))
{
if (logging != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
}
if ((ping_color_type == PNG_COLOR_TYPE_RGB ||
ping_color_type == PNG_COLOR_TYPE_GRAY) &&
- (ScaleQuantumToShort(q->red) == transparent_color.red &&
- ScaleQuantumToShort(q->green) == transparent_color.green &&
- ScaleQuantumToShort(q->blue) == transparent_color.blue))
+ (ScaleQuantumToShort(GetRedPixelComponent(q))
+ == transparent_color.red &&
+ ScaleQuantumToShort(GetGreenPixelComponent(q))
+ == transparent_color.green &&
+ ScaleQuantumToShort(GetBluePixelComponent(q))
+ == transparent_color.blue))
{
if (logging != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
* In a PNG datastream, Opaque is QuantumRange
* and Transparent is 0.
*/
- q->opacity=ScaleCharToQuantum((unsigned char) (255-(*p++)));
- if (q->opacity != OpaqueOpacity)
+ SetOpacityPixelComponent(q,
+ ScaleCharToQuantum((unsigned char) (255-(*p++))));
+ if (GetOpacityPixelComponent(q) != OpaqueOpacity)
found_transparent_pixel = MagickTrue;
q++;
}
{
quantum=((*p++) << 8);
quantum|=(*p++);
- q->opacity=(Quantum) (QuantumRange-quantum);
- if (q->opacity != OpaqueOpacity)
+ SetOpacityPixelComponent(q,(Quantum) (QuantumRange-quantum));
+ if (GetOpacityPixelComponent(q) != OpaqueOpacity)
found_transparent_pixel = MagickTrue;
q++;
}
if (ping_color_type == 4)
{
- q->opacity=(*p << 8) | *(p+1);
- q->opacity*=65537L;
- q->opacity=(Quantum) GetAlphaPixelComponent(q);
- if (q->opacity != OpaqueOpacity)
+ quantum=(*p << 8) | *(p+1);
+ quantum*=65537L;
+ SetOpacityPixelComponent(q,
+ (Quantum) GetAlphaPixelComponent(q));
+ if (GetOpacityPixelComponent(q) != OpaqueOpacity)
found_transparent_pixel = MagickTrue;
p+=2;
q++;
if (ping_color_type == 4)
{
- q->opacity=(Quantum) (QuantumRange-(*p++));
- if (q->opacity != OpaqueOpacity)
+ SetOpacityPixelComponent(q,(Quantum) (QuantumRange-(*p++)));
+ if (GetOpacityPixelComponent(q) != OpaqueOpacity)
found_transparent_pixel = MagickTrue;
p++;
q++;
default:
break;
}
+
/*
Transfer image scanline.
*/
r=quantum_scanline;
for (x=0; x < (ssize_t) image->columns; x++)
- indexes[x]=(IndexPacket) (*r++);
+ SetIndexPixelComponent(indexes+x,*r++);
if (SyncAuthenticPixels(image,exception) == MagickFalse)
break;
if ((image->previous == (Image *) NULL) && (num_passes == 1))
{
status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
- image->rows);
+ image->rows);
if (status == MagickFalse)
break;
image->matte=matte;
}
- png_read_end(ping,ping_info);
+ png_read_end(ping,end_info);
if (image_info->number_scenes != 0 && mng_info->scenes_found-1 <
(ssize_t) image_info->first_scene && image->delay != 0)
*/
for (x=(ssize_t) image->columns-1; x >= 0; x--)
{
- if (ScaleQuantumToShort(q->red) == transparent_color.red &&
- ScaleQuantumToShort(q->green) == transparent_color.green &&
- ScaleQuantumToShort(q->blue) == transparent_color.blue)
+ if (ScaleQuantumToShort(GetRedPixelComponent(q))
+ == transparent_color.red &&
+ ScaleQuantumToShort(GetGreenPixelComponent(q))
+ == transparent_color.green &&
+ ScaleQuantumToShort(GetBluePixelComponent(q))
+ == transparent_color.blue)
{
- q->opacity=(Quantum) TransparentOpacity;
+ SetOpacityPixelComponent(q,TransparentOpacity);
}
#if 0 /* I have not found a case where this is needed. */
else
{
- q->opacity=(Quantum) OpaqueOpacity;
+ SetOpacityPixelComponent(q)=(Quantum) OpaqueOpacity;
}
#endif
(ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
image->colorspace=GRAYColorspace;
- if (png_get_text(ping,ping_info,&text,&num_text) != 0)
- for (i=0; i < (ssize_t) num_text; i++)
- {
- /* Check for a profile */
+ for (j = 0; j < 2; j++)
+ {
+ if (j == 0)
+ status = png_get_text(ping,ping_info,&text,&num_text) != 0 ?
+ MagickTrue : MagickFalse;
+ else
+ status = png_get_text(ping,end_info,&text,&num_text) != 0 ?
+ MagickTrue : MagickFalse;
- if (logging != MagickFalse)
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " Reading PNG text chunk");
+ if (status != MagickFalse)
+ for (i=0; i < (ssize_t) num_text; i++)
+ {
+ /* Check for a profile */
- if (memcmp(text[i].key, "Raw profile type ",17) == 0)
- (void) Magick_png_read_raw_profile(image,image_info,text,(int) i);
+ if (logging != MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Reading PNG text chunk");
- else
- {
- char
- *value;
+ if (memcmp(text[i].key, "Raw profile type ",17) == 0)
+ {
+ (void) Magick_png_read_raw_profile(image,image_info,text,(int) i);
+ num_raw_profiles++;
+ }
- length=text[i].text_length;
- value=(char *) AcquireQuantumMemory(length+MaxTextExtent,
- sizeof(*value));
- if (value == (char *) NULL)
+ else
+ {
+ char
+ *value;
+
+ length=text[i].text_length;
+ value=(char *) AcquireQuantumMemory(length+MaxTextExtent,
+ sizeof(*value));
+ if (value == (char *) NULL)
+ {
+ (void) ThrowMagickException(&image->exception,GetMagickModule(),
+ ResourceLimitError,"MemoryAllocationFailed","`%s'",
+ image->filename);
+ break;
+ }
+ *value='\0';
+ (void) ConcatenateMagickString(value,text[i].text,length+2);
+
+ /* Don't save "density" or "units" property if we have a pHYs
+ * chunk
+ */
+ if (!png_get_valid(ping,ping_info,PNG_INFO_pHYs) ||
+ (LocaleCompare(text[i].key,"density") != 0 &&
+ LocaleCompare(text[i].key,"units") != 0))
+ (void) SetImageProperty(image,text[i].key,value);
+
+ if (logging != MagickFalse)
{
- (void) ThrowMagickException(&image->exception,GetMagickModule(),
- ResourceLimitError,"MemoryAllocationFailed","`%s'",
- image->filename);
- break;
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " length: %lu",(unsigned long) length);
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Keyword: %s",text[i].key);
}
- *value='\0';
- (void) ConcatenateMagickString(value,text[i].text,length+2);
- (void) SetImageProperty(image,text[i].key,value);
- if (logging != MagickFalse)
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " Keyword: %s",text[i].key);
-
- value=DestroyString(value);
- }
+ value=DestroyString(value);
+ }
+ }
+ num_text_total += num_text;
}
#ifdef MNG_OBJECT_BUFFERS
}
}
#endif
+
+ /* Set image->matte to MagickTrue if the input colortype supports
+ * alpha or if a valid tRNS chunk is present, no matter whether there
+ * is actual transparency present.
+ */
+ image->matte=(((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) ||
+ ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
+ (png_get_valid(ping,ping_info,PNG_INFO_tRNS))) ?
+ MagickTrue : MagickFalse;
+
+ /* Set more properties for identify to retrieve */
+ {
+ char
+ msg[MaxTextExtent];
+
+ if (num_text_total != 0)
+ {
+ /* libpng doesn't tell us whether they were tEXt, zTXt, or iTXt */
+ (void) FormatMagickString(msg,MaxTextExtent,
+ "%d tEXt/zTXt/iTXt chunks were found", num_text_total);
+ (void) SetImageProperty(image,"PNG:text ",msg);
+ }
+
+ if (num_raw_profiles != 0)
+ {
+ (void) FormatMagickString(msg,MaxTextExtent,
+ "%d were found", num_raw_profiles);
+ (void) SetImageProperty(image,"PNG:text-encoded profiles",msg);
+ }
+
+ if (png_get_valid(ping,ping_info,PNG_INFO_cHRM))
+ {
+ (void) FormatMagickString(msg,MaxTextExtent,"%s",
+ "chunk was found (see Chromaticity, above)");
+ (void) SetImageProperty(image,"PNG:cHRM ",msg);
+ }
+
+ if (png_get_valid(ping,ping_info,PNG_INFO_bKGD))
+ {
+ (void) FormatMagickString(msg,MaxTextExtent,"%s",
+ "chunk was found (see Background color, above)");
+ (void) SetImageProperty(image,"PNG:bKGD ",msg);
+ }
+
+ (void) FormatMagickString(msg,MaxTextExtent,"%s",
+ "chunk was found");
+
+ if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
+ (void) SetImageProperty(image,"PNG:iCCP ",msg);
+
+ if (png_get_valid(ping,ping_info,PNG_INFO_tRNS))
+ (void) SetImageProperty(image,"PNG:tRNS ",msg);
+
+#if defined(PNG_sRGB_SUPPORTED)
+ if (png_get_valid(ping,ping_info,PNG_INFO_sRGB))
+ {
+ (void) FormatMagickString(msg,MaxTextExtent,
+ "intent=%d (See Rendering intent)",
+ (int) intent);
+ (void) SetImageProperty(image,"PNG:sRGB ",msg);
+ }
+#endif
+
+ if (png_get_valid(ping,ping_info,PNG_INFO_gAMA))
+ {
+ (void) FormatMagickString(msg,MaxTextExtent,
+ "gamma=%.8g (See Gamma, above)",
+ file_gamma);
+ (void) SetImageProperty(image,"PNG:gAMA ",msg);
+ }
+
+#if defined(PNG_pHYs_SUPPORTED)
+ if (png_get_valid(ping,ping_info,PNG_INFO_pHYs))
+ {
+ (void) FormatMagickString(msg,MaxTextExtent,
+ "x_res=%.10g, y_res=%.10g, units=%d",
+ (double) x_resolution,(double) y_resolution, unit_type);
+ (void) SetImageProperty(image,"PNG:pHYs ",msg);
+ }
+#endif
+
+#if defined(PNG_oFFs_SUPPORTED)
+ if (png_get_valid(ping,ping_info,PNG_INFO_oFFs))
+ {
+ (void) FormatMagickString(msg,MaxTextExtent,"x_off=%.20g, y_off=%.20g",
+ (double) image->page.x,(double) image->page.y);
+ (void) SetImageProperty(image,"PNG:oFFs ",msg);
+ }
+#endif
+
+ if ((image->page.width != 0 && image->page.width != image->columns) ||
+ (image->page.height != 0 && image->page.height != image->rows))
+ {
+ (void) FormatMagickString(msg,MaxTextExtent,
+ "width=%.20g, height=%.20g",
+ (double) image->page.width,(double) image->page.height);
+ (void) SetImageProperty(image,"PNG:vpAg ",msg);
+ }
+ }
+
/*
Relinquish resources.
*/
assert(exception != (ExceptionInfo *) NULL);
assert(exception->signature == MagickSignature);
- logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadPNGImage()");
+ logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadPNGImage()");
image=AcquireImage(image_info);
mng_info=(MngInfo *) NULL;
status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
*/
count=ReadBlob(image,8,(unsigned char *) magic_number);
- if (memcmp(magic_number,"\211PNG\r\n\032\n",8) != 0)
+ if (count < 8 || memcmp(magic_number,"\211PNG\r\n\032\n",8) != 0)
ThrowReaderException(CorruptImageError,"ImproperImageHeader");
/*
ThrowReaderException(CorruptImageError,"CorruptImage");
}
+#if 0 /* This is probably redundant now */
if (LocaleCompare(image_info->magick,"PNG8") == 0)
{
(void) SetImageType(image,PaletteType);
/* To do: Reduce to binary transparency */
}
}
+#endif
if (LocaleCompare(image_info->magick,"PNG24") == 0)
{
if (LocaleCompare(image_info->magick,"PNG32") == 0)
(void) SetImageType(image,TrueColorMatteType);
+ if (logging != MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " page.w: %.20g, page.h: %.20g,page.x: %.20g, page.y: %.20g.",
+ (double) image->page.width,(double) image->page.height,
+ (double) image->page.x,(double) image->page.y);
+
if (logging != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadPNGImage()");
color_image_info=(ImageInfo *) NULL;
logging=LogMagickEvent(CoderEvent,GetMagickModule(),
- " enter ReadOneJNGImage()");
+ " Enter ReadOneJNGImage()");
image=mng_info->image;
{
if (length > 8)
{
- image->page.x=mng_get_long(p);
- image->page.y=mng_get_long(&p[4]);
+ image->page.x=(ssize_t) mng_get_long(p);
+ image->page.y=(ssize_t) mng_get_long(&p[4]);
if ((int) p[8] != 0)
{
#if 0
if (memcmp(type,mng_iCCP,4) == 0)
{
- /* To do. */
+ /* To do: */
if (length)
chunk=(unsigned char *) RelinquishMagickMemory(chunk);
if (image->matte != MagickFalse)
for (x=(ssize_t) image->columns; x != 0; x--,q++,s++)
- q->opacity=(Quantum) QuantumRange-s->red;
+ SetOpacityPixelComponent(q,(Quantum) QuantumRange-
+ GetRedPixelComponent(s));
else
for (x=(ssize_t) image->columns; x != 0; x--,q++,s++)
{
- q->opacity=(Quantum) QuantumRange-s->red;
- if (q->opacity != OpaqueOpacity)
+ SetOpacityPixelComponent(q,(Quantum) QuantumRange-
+ GetRedPixelComponent(s));
+ if (GetOpacityPixelComponent(q) != OpaqueOpacity)
image->matte=MagickTrue;
}
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
assert(exception != (ExceptionInfo *) NULL);
assert(exception->signature == MagickSignature);
- logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadJNGImage()");
+ logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadJNGImage()");
image=AcquireImage(image_info);
mng_info=(MngInfo *) NULL;
status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number);
- if (memcmp(magic_number,"\213JNG\r\n\032\n",8) != 0)
+ if (count < 8 || memcmp(magic_number,"\213JNG\r\n\032\n",8) != 0)
ThrowReaderException(CorruptImageError,"ImproperImageHeader");
/* Allocate a MngInfo structure. */
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image_info->filename);
assert(exception != (ExceptionInfo *) NULL);
assert(exception->signature == MagickSignature);
- logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadMNGImage()");
+ logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter ReadMNGImage()");
image=AcquireImage(image_info);
mng_info=(MngInfo *) NULL;
status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
if (memcmp(type,mng_iCCP,4) == 0)
{
- /* To do. */
+ /* To do: */
/*
Read global iCCP.
magn_methx=mng_info->magn_methx;
magn_methy=mng_info->magn_methy;
-#if (MAGICKCORE_QUANTUM_DEPTH == 32)
+#if (MAGICKCORE_QUANTUM_DEPTH > 16)
#define QM unsigned short
if (magn_methx != 1 || magn_methy != 1)
{
for (x=(ssize_t) image->columns-1; x >= 0; x--)
{
- q->red=ScaleQuantumToShort(q->red);
- q->green=ScaleQuantumToShort(q->green);
- q->blue=ScaleQuantumToShort(q->blue);
- q->opacity=ScaleQuantumToShort(q->opacity);
+ SetRedPixelComponent(q,ScaleQuantumToShort(
+ GetRedPixelComponent(q));
+ SetGreenPixelComponent(q,ScaleQuantumToShort(
+ GetGreenPixelComponent(q));
+ SetBluePixelComponent(q,ScaleQuantumToShort(
+ GetBluePixelComponent(q));
+ SetOpacityPixelComponent(q,ScaleQuantumToShort(
+ GetOpacityPixelComponent(q));
q++;
}
for (i=0; i < m; i++, yy++)
{
+ /* To do: Rewrite using Get/Set***PixelComponent() */
register PixelPacket
*pixels;
pixels=prev;
n=next;
q=GetAuthenticPixels(large_image,0,yy,large_image->columns,
- 1,exception);
+ 1,exception);
q+=(large_image->columns-image->columns);
for (x=(ssize_t) image->columns-1; x >= 0; x--)
{
- /* TO DO: get color as function of indexes[x] */
+ /* To do: get color as function of indexes[x] */
/*
if (image->storage_class == PseudoClass)
{
*pixels;
q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
+ /* To do: Rewrite using Get/Set***PixelComponent() */
pixels=q+(image->columns-length);
n=pixels+1;
for (x=(ssize_t) (image->columns-length);
x < (ssize_t) image->columns; x++)
{
+ /* To do: Rewrite using Get/Set***PixelComponent() */
+
if (x == (ssize_t) (image->columns-length))
m=(ssize_t) mng_info->magn_ml;
if (magn_methx <= 1)
{
/* replicate previous */
+ /* To do: Rewrite using Get/Set***PixelComponent() */
*q=(*pixels);
}
if (SyncAuthenticPixels(image,exception) == MagickFalse)
break;
}
-#if (MAGICKCORE_QUANTUM_DEPTH == 32)
+#if (MAGICKCORE_QUANTUM_DEPTH > 16)
if (magn_methx != 1 || magn_methy != 1)
{
/*
for (x=(ssize_t) image->columns-1; x >= 0; x--)
{
- q->red=ScaleShortToQuantum(q->red);
- q->green=ScaleShortToQuantum(q->green);
- q->blue=ScaleShortToQuantum(q->blue);
- q->opacity=ScaleShortToQuantum(q->opacity);
+ SetRedPixelComponent(q,ScaleShortToQuantum(
+ GetRedPixelComponent(q));
+ SetGreenPixelComponent(q,ScaleShortToQuantum(
+ GetGreenPixelComponent(q));
+ SetBluePixelComponent(q,ScaleShortToQuantum(
+ GetBluePixelComponent(q));
+ SetOpacityPixelComponent(q,ScaleShortToQuantum(
+ GetOpacityPixelComponent(q));
q++;
}
image->depth=16;
#endif
-#if (MAGICKCORE_QUANTUM_DEPTH >= 16)
+#if (MAGICKCORE_QUANTUM_DEPTH > 8)
if (LosslessReduceDepthOK(image) != MagickFalse)
image->depth = 8;
#endif
logging,
matte,
+ ping_have_blob,
+ ping_have_cheap_transparency,
ping_have_color,
+ ping_have_non_bw,
ping_have_PLTE,
ping_have_bKGD,
ping_have_pHYs,
ping_exclude_bKGD,
ping_exclude_cHRM,
- ping_exclude_EXIF,
+ ping_exclude_date,
+ /* ping_exclude_EXIF, */
ping_exclude_gAMA,
ping_exclude_iCCP,
/* ping_exclude_iTXt, */
ping_exclude_pHYs,
ping_exclude_sRGB,
ping_exclude_tEXt,
- ping_exclude_tRNS,
+ /* ping_exclude_tRNS, */
ping_exclude_vpAg,
ping_exclude_zCCP, /* hex-encoded iCCP */
ping_exclude_zTXt,
+ ping_preserve_colormap,
ping_need_colortype_warning,
- status;
+ status,
+ tried_333,
+ tried_444;
QuantumInfo
*quantum_info;
save_image_depth;
int
+ j,
number_colors,
number_opaque,
number_semitransparent,
ping_pHYs_y_resolution;
logging=LogMagickEvent(CoderEvent,GetMagickModule(),
- " enter WriteOnePNGImage()");
+ " Enter WriteOnePNGImage()");
image = CloneImage(IMimage,0,0,MagickFalse,&IMimage->exception);
image_info=(ImageInfo *) CloneImageInfo(IMimage_info);
-
- if (mng_info->need_blob != MagickFalse)
- {
- if (OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception) ==
- MagickFalse)
- {
- image_info=DestroyImageInfo(image_info);
- image=DestroyImage(image);
- return(MagickFalse);
- }
- }
+ if (image_info == (ImageInfo *) NULL)
+ ThrowWriterException(ResourceLimitError, "MemoryAllocationFailed");
#if defined(PNG_SETJMP_NOT_THREAD_SAFE)
LockSemaphoreInfo(ping_semaphore);
ping_pHYs_x_resolution = 0;
ping_pHYs_y_resolution = 0;
+ ping_have_blob=MagickFalse;
ping_have_color=MagickTrue;
+ ping_have_non_bw=MagickTrue;
ping_have_PLTE=MagickFalse;
ping_have_bKGD=MagickFalse;
ping_have_pHYs=MagickFalse;
ping_exclude_bKGD=mng_info->ping_exclude_bKGD;
ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
- ping_exclude_EXIF=mng_info->ping_exclude_EXIF; /* hex-encoded EXIF in zTXt */
+ ping_exclude_date=mng_info->ping_exclude_date;
+ /* ping_exclude_EXIF=mng_info->ping_exclude_EXIF; */
ping_exclude_gAMA=mng_info->ping_exclude_gAMA;
- ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
ping_exclude_iCCP=mng_info->ping_exclude_iCCP;
/* ping_exclude_iTXt=mng_info->ping_exclude_iTXt; */
ping_exclude_oFFs=mng_info->ping_exclude_oFFs;
ping_exclude_pHYs=mng_info->ping_exclude_pHYs;
ping_exclude_sRGB=mng_info->ping_exclude_sRGB;
ping_exclude_tEXt=mng_info->ping_exclude_tEXt;
- ping_exclude_tRNS=mng_info->ping_exclude_tRNS;
+ /* ping_exclude_tRNS=mng_info->ping_exclude_tRNS; */
ping_exclude_vpAg=mng_info->ping_exclude_vpAg;
ping_exclude_zCCP=mng_info->ping_exclude_zCCP; /* hex-encoded iCCP in zTXt */
ping_exclude_zTXt=mng_info->ping_exclude_zTXt;
+ ping_preserve_colormap = mng_info->ping_preserve_colormap;
ping_need_colortype_warning = MagickFalse;
number_opaque = 0;
number_semitransparent = 0;
number_transparent = 0;
+ if (logging != MagickFalse)
+ {
+ if (image->storage_class == UndefinedClass)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " storage_class=UndefinedClass");
+ if (image->storage_class == DirectClass)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " storage_class=DirectClass");
+ if (image->storage_class == PseudoClass)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " storage_class=PseudoClass");
+ }
+
+ if (ping_preserve_colormap == MagickFalse)
+ {
+ if (image->storage_class != PseudoClass && image->colormap != NULL)
+ {
+ /* Free the bogus colormap; it can cause trouble later */
+ if (logging != MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Freeing bogus colormap");
+ (void *) RelinquishMagickMemory(image->colormap);
+ image->colormap=NULL;
+ }
+ }
+
if (image->colorspace != RGBColorspace)
(void) TransformImageColorspace(image,RGBColorspace);
}
#endif
+#if 0 /* To do: Option to use the original colormap */
+ if (ping_preserve_colormap != MagickFalse)
+ {
+ }
+#endif
+
+#if 0 /* To do: respect the -depth option */
+ if (image->depth < MAGICKCORE_QUANTUM_DEPTH)
+ {
+ }
+#endif
+
+ /* To do: set to next higher multiple of 8 */
+ if (image->depth < 8)
+ image->depth=8;
#if (MAGICKCORE_QUANTUM_DEPTH > 16)
/* PNG does not handle depths greater than 16 so reduce it even
image->depth=16;
#endif
-#if (MAGICKCORE_QUANTUM_DEPTH >= 16)
- if (image->depth == 16 && mng_info->write_png_colortype != 16)
+#if (MAGICKCORE_QUANTUM_DEPTH > 8)
+ if (image->depth == 16 && mng_info->write_png_depth != 16)
if (mng_info->write_png8 || LosslessReduceDepthOK(image) != MagickFalse)
image->depth = 8;
#endif
-#ifdef BUILD_PNG_PALETTE
- if (mng_info->write_png_colortype < 8 /* all */)
- {
- /*
- * Sometimes we get DirectClass images that have 256 colors or fewer.
- * This code will build a colormap.
- *
- * Also, sometimes we get PseudoClass images with an out-of-date
- * colormap. This code will replace the colormap with a new one.
- * Sometimes we get PseudoClass images that have more than 256 colors.
- * This code will delete the colormap and change the image to
- * DirectClass.
- *
- * If image->matte is MagickFalse, we ignore the opacity channel
- * even though it sometimes contains left-over non-opaque values.
- *
- * Also we gather some information (number of opaque, transparent,
- * and semitransparent pixels, and whether the image has any non-gray
- * pixels) that we might need later. If the user wants to force
- * GrayAlpha or RGBA (colortype 4 or 6) we probably don't need any
- * of that.
- */
+ /* Normally we run this just once, but in the case of writing PNG8
+ * we reduce the transparency to binary and run again, then if there
+ * are still too many colors we reduce to a simple 4-4-4-1, then 3-3-3-1
+ * RGBA palette and run again, and finally to a simple 3-3-2-1 RGBA
+ * palette. The final reduction can only fail if there are still 256
+ * colors present and one of them has both transparent and opaque instances.
+ */
+
+ tried_333 = MagickFalse;
+ tried_444 = MagickFalse;
+
+ for (j=0; j<5; j++)
+ {
+ /* BUILD_PALETTE
+ *
+ * Sometimes we get DirectClass images that have 256 colors or fewer.
+ * This code will build a colormap.
+ *
+ * Also, sometimes we get PseudoClass images with an out-of-date
+ * colormap. This code will replace the colormap with a new one.
+ * Sometimes we get PseudoClass images that have more than 256 colors.
+ * This code will delete the colormap and change the image to
+ * DirectClass.
+ *
+ * If image->matte is MagickFalse, we ignore the opacity channel
+ * even though it sometimes contains left-over non-opaque values.
+ *
+ * Also we gather some information (number of opaque, transparent,
+ * and semitransparent pixels, and whether the image has any non-gray
+ * pixels or only black-and-white pixels) that we might need later.
+ *
+ * Even if the user wants to force GrayAlpha or RGBA (colortype 4 or 6)
+ * we need to check for bogus non-opaque values, at least.
+ */
- ExceptionInfo
- *exception;
+ ExceptionInfo
+ *exception;
- int
- n;
+ int
+ n;
- PixelPacket
- opaque[260],
- semitransparent[260],
- transparent[260];
+ PixelPacket
+ opaque[260],
+ semitransparent[260],
+ transparent[260];
- register IndexPacket
- *indexes;
+ register IndexPacket
+ *indexes;
- register const PixelPacket
- *q;
+ register const PixelPacket
+ *s,
+ *q;
- if (logging != MagickFalse)
+ register PixelPacket
+ *r;
+
+ if (logging != MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Enter BUILD_PALETTE:");
+
+ if (logging != MagickFalse)
+ {
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " image->columns=%.20g",(double) image->columns);
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " image->rows=%.20g",(double) image->rows);
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " image->matte=%.20g",(double) image->matte);
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " Enter BUILD_PALETTE:");
+ " image->depth=%.20g",(double) image->depth);
- if (logging != MagickFalse)
+ if (image->storage_class == PseudoClass && image->colormap != NULL)
{
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " image->columns=%.20g",(double) image->columns);
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " image->rows=%.20g",(double) image->rows);
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " image->matte=%.20g",(double) image->matte);
+ " Original colormap:");
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " image->depth=%.20g",(double) image->depth);
+ " i (red,green,blue,opacity)");
- if (image->colormap != NULL)
+ for (i=0; i < 256; i++)
{
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " Original colormap:");
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " i (red,green,blue,opacity)");
-
- for (i=0; i < 256; 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) image->colormap[i].opacity);
- }
+ (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) image->colormap[i].opacity);
+ }
- for (i=image->colors - 10; i < (ssize_t) image->colors; i++)
- {
- if (i > 255)
- {
- (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) image->colormap[i].opacity);
- }
- }
+ for (i=image->colors - 10; i < (ssize_t) image->colors; i++)
+ {
+ if (i > 255)
+ {
+ (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) image->colormap[i].opacity);
+ }
}
+ }
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " image->colors=%d",(int) image->colors);
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " image->colors=%d",(int) image->colors);
- if (image->colors == 0)
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " (zero means unknown)");
+ if (image->colors == 0)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " (zero means unknown)");
+ if (ping_preserve_colormap == MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" Regenerate the colormap");
- }
+ }
+
+ exception=(&image->exception);
- exception=(&image->exception);
+ image_colors=0;
+ number_opaque = 0;
+ number_semitransparent = 0;
+ number_transparent = 0;
- ping_have_color=MagickFalse;
- image_colors=0;
+ for (y=0; y < (ssize_t) image->rows; y++)
+ {
+ q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
- for (y=0; y < (ssize_t) image->rows; y++)
+ if (q == (PixelPacket *) NULL)
+ break;
+
+ for (x=0; x < (ssize_t) image->columns; x++)
{
- q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
+ if (image->matte == MagickFalse ||
+ GetOpacityPixelComponent(q) == OpaqueOpacity)
+ {
+ if (number_opaque < 259)
+ {
+ if (number_opaque == 0)
+ {
+ GetRGBPixelComponents(q, opaque[0]);
+ opaque[0].opacity=OpaqueOpacity;
+ number_opaque=1;
+ }
- if (q == (PixelPacket *) NULL)
- break;
+ for (i=0; i< (ssize_t) number_opaque; i++)
+ {
+ if (IsColorEqual(q, opaque+i))
+ break;
+ }
- for (x=0; x < (ssize_t) image->columns; x++)
- {
- if (q->red != q->green || q->red != q->blue)
- ping_have_color=MagickTrue;
+ if (i == (ssize_t) number_opaque &&
+ number_opaque < 259)
+ {
+ number_opaque++;
+ GetRGBPixelComponents(q, opaque[i]);
+ opaque[i].opacity=OpaqueOpacity;
+ }
+ }
+ }
+ else if (q->opacity == TransparentOpacity)
+ {
+ if (number_transparent < 259)
+ {
+ if (number_transparent == 0)
+ {
+ GetRGBOPixelComponents(q, transparent[0]);
+ ping_trans_color.red=
+ (unsigned short) GetRedPixelComponent(q);
+ ping_trans_color.green=
+ (unsigned short) GetGreenPixelComponent(q);
+ ping_trans_color.blue=
+ (unsigned short) GetBluePixelComponent(q);
+ ping_trans_color.gray=
+ (unsigned short) GetRedPixelComponent(q);
+ number_transparent = 1;
+ }
- if (image->matte == MagickFalse || q->opacity == OpaqueOpacity)
- {
- if (number_opaque < 259)
- {
- if (number_opaque == 0)
- {
- opaque[0]=*q;
- opaque[0].opacity=OpaqueOpacity;
- number_opaque=1;
- }
-
- for (i=0; i< (ssize_t) number_opaque; i++)
- {
- if (IsColorEqual(opaque+i, (PixelPacket *) q))
- break;
- }
-
- if (i == (ssize_t) number_opaque &&
- number_opaque < 259)
- {
- number_opaque++;
- opaque[i] = *q;
- opaque[i].opacity = OpaqueOpacity;
- }
- }
- }
- else if (q->opacity == TransparentOpacity)
- {
- if (number_transparent < 259)
- {
- if (number_transparent == 0)
- {
- transparent[0]=*q;
- ping_trans_color.red=(unsigned short)(q->red);
- ping_trans_color.green=(unsigned short) (q->green);
- ping_trans_color.blue=(unsigned short) (q->blue);
- ping_trans_color.gray=(unsigned short) (q->blue);
- number_transparent = 1;
- }
-
- for (i=0; i< (ssize_t) number_transparent; i++)
- {
- if (IsColorEqual(transparent+i, (PixelPacket *) q))
- break;
- }
-
- if (i == (ssize_t) number_transparent &&
- number_transparent < 259)
- {
- number_transparent++;
- transparent[i] = *q;
- }
- }
- }
- else
- {
- if (number_semitransparent < 259)
- {
- if (number_semitransparent == 0)
- {
- semitransparent[0]=*q;
- number_semitransparent = 1;
- }
-
- for (i=0; i< (ssize_t) number_semitransparent; i++)
- {
- if (IsColorEqual(semitransparent+i,
- (PixelPacket *) q) &&
- q->opacity == semitransparent[i].opacity)
- break;
- }
-
- if (i == (ssize_t) number_semitransparent &&
- number_semitransparent < 259)
- {
- number_semitransparent++;
- semitransparent[i] = *q;
- }
- }
- }
- q++;
+ for (i=0; i< (ssize_t) number_transparent; i++)
+ {
+ if (IsColorEqual(q, transparent+i))
+ break;
+ }
+
+ if (i == (ssize_t) number_transparent &&
+ number_transparent < 259)
+ {
+ number_transparent++;
+ GetRGBOPixelComponents(q, transparent[i]);
+ }
+ }
}
- }
+ else
+ {
+ if (number_semitransparent < 259)
+ {
+ if (number_semitransparent == 0)
+ {
+ GetRGBOPixelComponents(q, semitransparent[0]);
+ number_semitransparent = 1;
+ }
- image_colors=number_opaque+number_transparent+number_semitransparent;
+ for (i=0; i< (ssize_t) number_semitransparent; i++)
+ {
+ if (IsColorEqual(q, semitransparent+i)
+ && GetOpacityPixelComponent(q) ==
+ semitransparent[i].opacity)
+ break;
+ }
+ if (i == (ssize_t) number_semitransparent &&
+ number_semitransparent < 259)
+ {
+ number_semitransparent++;
+ GetRGBOPixelComponents(q, semitransparent[i]);
+ }
+ }
+ }
+ q++;
+ }
+ }
+
+ if (ping_exclude_bKGD == MagickFalse)
+ {
+ /* Add the background color to the palette, if it
+ * isn't already there.
+ */
if (logging != MagickFalse)
{
- if (image_colors > 256)
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " image has more than 256 colors");
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Check colormap for background (%d,%d,%d)",
+ (int) image->background_color.red,
+ (int) image->background_color.green,
+ (int) image->background_color.blue);
+ }
+ for (i=0; i<number_opaque; i++)
+ {
+ if (opaque[i].red == image->background_color.red &&
+ opaque[i].green == image->background_color.green &&
+ opaque[i].blue == image->background_color.blue)
+ break;
+ }
+ if (number_opaque < 259 && i == number_opaque)
+ {
+ opaque[i] = image->background_color;
+ ping_background.index = i;
+ if (logging != MagickFalse)
+ {
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " background_color index is %d",(int) i);
+ }
- else
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " image has %d colors",image_colors);
}
+ else if (logging != MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " No room in the colormap to add background color");
+ }
- if (image_colors < 257)
- {
- PixelPacket
- colormap[260];
-
- /*
- Initialize image colormap.
- */
+ image_colors=number_opaque+number_transparent+number_semitransparent;
- if (logging != MagickFalse)
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " Sort the new colormap");
+ if (mng_info->write_png8 != MagickFalse && image_colors > 256)
+ {
+ /* No room for the background color; remove it. */
+ number_opaque--;
+ image_colors--;
+ }
+
+ if (logging != MagickFalse)
+ {
+ if (image_colors > 256)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " image has more than 256 colors");
+
+ else
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " image has %d colors",image_colors);
+ }
+
+ if (ping_preserve_colormap != MagickFalse)
+ break;
+
+ if (mng_info->write_png_colortype != 7) /* We won't need this info */
+ {
+ ping_have_color=MagickFalse;
+ ping_have_non_bw=MagickFalse;
- /* Sort palette, transparent first */;
+ if(image_colors > 256)
+ {
+ for (y=0; y < (ssize_t) image->rows; y++)
+ {
+ q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
- n = 0;
+ if (q == (PixelPacket *) NULL)
+ break;
- for (i=0; i<number_transparent; i++)
- colormap[n++] = transparent[i];
+ /* Worst case is black-and-white; we are looking at every
+ * pixel twice.
+ */
- for (i=0; i<number_semitransparent; i++)
- colormap[n++] = semitransparent[i];
+ if (ping_have_color == MagickFalse)
+ {
+ s=q;
+ for (x=0; x < (ssize_t) image->columns; x++)
+ {
+ if (GetRedPixelComponent(s) != GetGreenPixelComponent(s)
+ || GetRedPixelComponent(s) != GetBluePixelComponent(s))
+ {
+ ping_have_color=MagickTrue;
+ ping_have_non_bw=MagickTrue;
+ break;
+ }
+ s++;
+ }
+ }
- for (i=0; i<number_opaque; i++)
- colormap[n++] = opaque[i];
+ if (ping_have_non_bw == MagickFalse)
+ {
+ s=q;
+ for (x=0; x < (ssize_t) image->columns; x++)
+ {
+ if (GetRedPixelComponent(s) != 0 &&
+ GetRedPixelComponent(s) != QuantumRange)
+ {
+ ping_have_non_bw=MagickTrue;
+ }
+ s++;
+ }
+ }
+ }
+ }
+ }
- if (ping_exclude_bKGD == MagickFalse)
+ if (image_colors < 257)
+ {
+ PixelPacket
+ colormap[260];
+
+ /*
+ * Initialize image colormap.
+ */
+
+ if (logging != MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Sort the new colormap");
+
+ /* Sort palette, transparent first */;
+
+ n = 0;
+
+ for (i=0; i<number_transparent; i++)
+ colormap[n++] = transparent[i];
+
+ for (i=0; i<number_semitransparent; i++)
+ colormap[n++] = semitransparent[i];
+
+ for (i=0; i<number_opaque; i++)
+ colormap[n++] = opaque[i];
+
+ ping_background.index +=
+ (number_transparent + number_semitransparent);
+
+ /* image_colors < 257; search the colormap instead of the pixels
+ * to get ping_have_color and ping_have_non_bw
+ */
+ for (i=0; i<n; i++)
+ {
+ if (ping_have_color == MagickFalse)
+ {
+ if (colormap[i].red != colormap[i].green ||
+ colormap[i].red != colormap[i].blue)
+ {
+ ping_have_color=MagickTrue;
+ ping_have_non_bw=MagickTrue;
+ break;
+ }
+ }
+
+ if (ping_have_non_bw == MagickFalse)
+ {
+ if (colormap[i].red != 0 && colormap[i].red != QuantumRange)
+ ping_have_non_bw=MagickTrue;
+ }
+ }
+
+ if ((mng_info->ping_exclude_tRNS == MagickFalse ||
+ (number_transparent == 0 && number_semitransparent == 0)) &&
+ (((mng_info->write_png_colortype-1) ==
+ PNG_COLOR_TYPE_PALETTE) ||
+ (mng_info->write_png_colortype == 0)))
+ {
+ if (logging != MagickFalse)
{
- /* Add the background color to the palette, if it
- * isn't already there.
- */
- for (i=0; i<number_opaque; i++)
- {
- if (IsColorEqual(opaque+i,
- &image->background_color))
- break;
- }
+ if (n != (ssize_t) image_colors)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " image_colors (%d) and n (%d) don't match",
+ image_colors, n);
+
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " AcquireImageColormap");
+ }
+
+ image->colors = image_colors;
+
+ if (AcquireImageColormap(image,image_colors) ==
+ MagickFalse)
+ ThrowWriterException(ResourceLimitError,
+ "MemoryAllocationFailed");
+
+ for (i=0; i< (ssize_t) image_colors; i++)
+ image->colormap[i] = colormap[i];
+
+ if (logging != MagickFalse)
+ {
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " image->colors=%d (%d)",
+ (int) image->colors, image_colors);
+
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Update the pixel indexes");
+ }
+
+ /* Sync the pixel indices with the new colormap */
- if (number_opaque < 257 && i == number_opaque)
+ for (y=0; y < (ssize_t) image->rows; y++)
+ {
+ q=GetAuthenticPixels(image,0,y,image->columns,1,
+ exception);
+
+ if (q == (PixelPacket *) NULL)
+ break;
+
+ indexes=GetAuthenticIndexQueue(image);
+
+ for (x=0; x < (ssize_t) image->columns; x++)
+ {
+ for (i=0; i< (ssize_t) image_colors; i++)
{
- opaque[i]=image->background_color;
- opaque[i].opacity = OpaqueOpacity;
- number_opaque++;
+ if ((image->matte == MagickFalse ||
+ image->colormap[i].opacity ==
+ GetOpacityPixelComponent(q)) &&
+ image->colormap[i].red ==
+ GetRedPixelComponent(q) &&
+ image->colormap[i].green ==
+ GetGreenPixelComponent(q) &&
+ image->colormap[i].blue ==
+ GetBluePixelComponent(q))
+ {
+ SetIndexPixelComponent(indexes+x,i);
+ break;
+ }
}
+ q++;
}
- if ((mng_info->ping_exclude_tRNS == MagickFalse ||
- (number_transparent == 0 && number_semitransparent == 0)) &&
- (((mng_info->write_png_colortype-1) ==
- PNG_COLOR_TYPE_PALETTE) ||
- (mng_info->write_png_colortype == 0)))
- {
- if (logging != MagickFalse)
- {
- if (n != (ssize_t) image_colors)
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " image_colors (%d) and n (%d) don't match",
- image_colors, n);
+ if (SyncAuthenticPixels(image,exception) == MagickFalse)
+ break;
+ }
+ }
+ }
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " AcquireImageColormap");
- }
+ if (logging != MagickFalse)
+ {
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " image->colors=%d", (int) image->colors);
- image->colors = image_colors;
+ if (image->colormap != NULL)
+ {
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " i (red,green,blue,opacity)");
- if (AcquireImageColormap(image,image_colors) ==
- MagickFalse)
- ThrowWriterException(ResourceLimitError,
- "MemoryAllocationFailed");
+ for (i=0; i < (ssize_t) image->colors; i++)
+ {
+ if (i < 300 || i >= (ssize_t) image->colors - 10)
+ {
+ (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) image->colormap[i].opacity);
+ }
+ }
+ }
- for (i=0; i< (ssize_t) image_colors; i++)
- image->colormap[i] = colormap[i];
+ if (number_transparent < 257)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " number_transparent = %d",
+ number_transparent);
+ else
- if (logging != MagickFalse)
- {
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " image->colors=%d (%d)",
- (int) image->colors, image_colors);
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " number_transparent > 256");
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " Update the pixel indexes");
+ if (number_opaque < 257)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " number_opaque = %d",
+ number_opaque);
+
+ else
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " number_opaque > 256");
+
+ if (number_semitransparent < 257)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " number_semitransparent = %d",
+ number_semitransparent);
+
+ else
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " number_semitransparent > 256");
+
+ if (ping_have_non_bw == MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " All pixels and the background are black or white");
+
+ else if (ping_have_color == MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " All pixels and the background are gray");
+
+ else
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " At least one pixel or the background is non-gray");
+
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Exit BUILD_PALETTE:");
+ }
+
+ if (mng_info->write_png8 == MagickFalse)
+ break;
+
+ /* Make any reductions necessary for the PNG8 format */
+ if (image_colors <= 256 &&
+ image_colors != 0 && image->colormap != NULL &&
+ number_semitransparent == 0 &&
+ number_transparent <= 1)
+ break;
+
+ /* PNG8 can't have semitransparent colors so we threshold the
+ * opacity to 0 or OpaqueOpacity
+ */
+ if (number_semitransparent != 0)
+ {
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Thresholding the alpha channel to binary");
+
+ for (y=0; y < (ssize_t) image->rows; y++)
+ {
+ r=GetAuthenticPixels(image,0,y,image->columns,1,
+ exception);
+
+ if (r == (PixelPacket *) NULL)
+ break;
+
+ for (x=0; x < (ssize_t) image->columns; x++)
+ {
+ SetOpacityPixelComponent(r,
+ (GetOpacityPixelComponent(r) > TransparentOpacity/2) ?
+ TransparentOpacity : OpaqueOpacity);
+ r++;
+ }
+
+ if (SyncAuthenticPixels(image,exception) == MagickFalse)
+ break;
+
+ if (image_colors != 0 && image_colors <= 256 &&
+ image->colormap != NULL)
+ for (i=0; i<image_colors; i++)
+ image->colormap[i].opacity =
+ image->colormap[i].opacity > TransparentOpacity/2 ?
+ TransparentOpacity : OpaqueOpacity;
+ }
+ continue;
+ }
+
+ /* PNG8 can't have more than 256 colors so we quantize the pixels and
+ * background color to the 4-4-4-1, 3-3-3-1 or 3-3-2-1 palette. If the
+ * image is mostly gray, the 4-4-4-1 palette is likely to end up with 256
+ * colors or less.
+ */
+ if (tried_444 == MagickFalse && (image_colors == 0 || image_colors > 256))
+ {
+ if (logging != MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Quantizing the background color to 4-4-4");
+
+ tried_444 = MagickTrue;
+
+ image->background_color.red=
+ ScaleCharToQuantum(
+ (ScaleQuantumToChar(image->background_color.red) & 0xf0) |
+ (ScaleQuantumToChar(image->background_color.red) & 0xf0) >> 4);
+ image->background_color.green=
+ ScaleCharToQuantum(
+ (ScaleQuantumToChar(image->background_color.green) & 0xf0) |
+ (ScaleQuantumToChar(image->background_color.green) & 0xf0) >> 4);
+ image->background_color.blue=
+ ScaleCharToQuantum(
+ (ScaleQuantumToChar(image->background_color.blue) & 0xf0) |
+ (ScaleQuantumToChar(image->background_color.blue) & 0xf0) >> 4);
+
+ if (logging != MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Quantizing the pixel colors to 4-4-4");
+
+ if (image->colormap == NULL)
+ {
+ for (y=0; y < (ssize_t) image->rows; y++)
+ {
+ r=GetAuthenticPixels(image,0,y,image->columns,1,
+ exception);
+
+ if (r == (PixelPacket *) NULL)
+ break;
+
+ for (x=0; x < (ssize_t) image->columns; x++)
+ {
+ if (GetOpacityPixelComponent(r) == TransparentOpacity)
+ {
+ SetRGBPixelComponents(r,image->background_color);
}
+ else
+ {
+ SetRedPixelComponent(r,ScaleCharToQuantum(
+ (ScaleQuantumToChar(GetRedPixelComponent(r)) & 0xf0) |
+ (ScaleQuantumToChar(GetRedPixelComponent(r)) & 0xf0) >> 4));
+ SetGreenPixelComponent(r,ScaleCharToQuantum(
+ (ScaleQuantumToChar(GetGreenPixelComponent(r)) & 0xf0) |
+ (ScaleQuantumToChar(GetGreenPixelComponent(r)) & 0xf0) >>
+ 4));
+ SetBluePixelComponent(r,ScaleCharToQuantum(
+ (ScaleQuantumToChar(GetBluePixelComponent(r)) & 0xf0) |
+ (ScaleQuantumToChar(GetBluePixelComponent(r)) & 0xf0) >>
+ 4));
+ }
+ r++;
+ }
+
+ if (SyncAuthenticPixels(image,exception) == MagickFalse)
+ break;
+ }
+ }
- for (y=0; y < (ssize_t) image->rows; y++)
- {
- q=GetAuthenticPixels(image,0,y,image->columns,1,
- exception);
+ else /* Should not reach this; colormap already exists and
+ must be <= 256 */
+ {
+ if (logging != MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Quantizing the colormap to 4-4-4");
+ for (i=0; i<image_colors; i++)
+ {
+ image->colormap[i].red=ScaleCharToQuantum(
+ (ScaleQuantumToChar(image->colormap[i].red) & 0xf0) |
+ (ScaleQuantumToChar(image->colormap[i].red) & 0xf0) >> 4);
+ image->colormap[i].green=ScaleCharToQuantum(
+ (ScaleQuantumToChar(image->colormap[i].green) & 0xf0) |
+ (ScaleQuantumToChar(image->colormap[i].green) & 0xf0) >> 4);
+ image->colormap[i].blue=ScaleCharToQuantum(
+ (ScaleQuantumToChar(image->colormap[i].blue) & 0xf0) |
+ (ScaleQuantumToChar(image->colormap[i].blue) & 0xf0 >> 4));
+ }
+ }
+ continue;
+ }
+
+ if (tried_333 == MagickFalse && (image_colors == 0 || image_colors > 256))
+ {
+ if (logging != MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Quantizing the background color to 3-3-3");
+
+ tried_333 = MagickTrue;
+
+ image->background_color.red=
+ ScaleCharToQuantum(
+ (ScaleQuantumToChar(image->background_color.red) & 0xe0) |
+ (ScaleQuantumToChar(image->background_color.red) & 0xe0) >> 3 |
+ (ScaleQuantumToChar(image->background_color.red) & 0xc0) >> 6);
+ image->background_color.green=
+ ScaleCharToQuantum(
+ (ScaleQuantumToChar(image->background_color.green) & 0xe0) |
+ (ScaleQuantumToChar(image->background_color.green) & 0xe0) >> 3 |
+ (ScaleQuantumToChar(image->background_color.green) & 0xc0) >> 6);
+ image->background_color.blue=
+ ScaleCharToQuantum(
+ (ScaleQuantumToChar(image->background_color.blue) & 0xe0) |
+ (ScaleQuantumToChar(image->background_color.blue) & 0xe0) >> 3 |
+ (ScaleQuantumToChar(image->background_color.blue) & 0xc0) >> 6);
+
+ if (logging != MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Quantizing the pixel colors to 3-3-3-1");
- if (q == (PixelPacket *) NULL)
- break;
+ if (image->colormap == NULL)
+ {
+ for (y=0; y < (ssize_t) image->rows; y++)
+ {
+ r=GetAuthenticPixels(image,0,y,image->columns,1,
+ exception);
- indexes=GetAuthenticIndexQueue(image);
+ if (r == (PixelPacket *) NULL)
+ break;
- for (x=0; x < (ssize_t) image->columns; x++)
+ for (x=0; x < (ssize_t) image->columns; x++)
+ {
+ if (GetOpacityPixelComponent(r) == TransparentOpacity)
{
- for (i=0; i< (ssize_t) image_colors; i++)
- {
- if ((image->matte == MagickFalse ||
- image->colormap[i].opacity == q->opacity) &&
- (IsColorEqual(&image->colormap[i],(PixelPacket *) q)))
- {
- indexes[x]=(IndexPacket) i;
- break;
- }
- }
- q++;
+ SetRGBPixelComponents(r,image->background_color);
+ }
+ else
+ {
+ SetRedPixelComponent(r,ScaleCharToQuantum(
+ (ScaleQuantumToChar(GetRedPixelComponent(r)) & 0xe0) |
+ (ScaleQuantumToChar(GetRedPixelComponent(r)) & 0xe0) >> 3 |
+ (ScaleQuantumToChar(GetRedPixelComponent(r)) & 0xc0) >>
+ 6));
+ SetGreenPixelComponent(r,ScaleCharToQuantum(
+ (ScaleQuantumToChar(GetGreenPixelComponent(r)) & 0xe0) |
+ (ScaleQuantumToChar(GetGreenPixelComponent(r)) & 0xe0) >>
+ 3 |
+ (ScaleQuantumToChar(GetGreenPixelComponent(r)) & 0xc0) >>
+ 6));
+ SetBluePixelComponent(r,ScaleCharToQuantum(
+ (ScaleQuantumToChar(GetBluePixelComponent(r)) & 0xe0) |
+ (ScaleQuantumToChar(GetBluePixelComponent(r)) & 0xe0) >> 3 |
+ (ScaleQuantumToChar(GetBluePixelComponent(r)) & 0xc0) >>
+ 6));
}
+ r++;
+ }
+
+ if (SyncAuthenticPixels(image,exception) == MagickFalse)
+ break;
+ }
+ }
- if (SyncAuthenticPixels(image,exception) == MagickFalse)
- break;
- }
- }
- }
+ else /* Should not reach this; colormap already exists and
+ must be <= 256 */
+ {
+ if (logging != MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Quantizing the colormap to 3-3-3-1");
+ for (i=0; i<image_colors; i++)
+ {
+ image->colormap[i].red=ScaleCharToQuantum(
+ (ScaleQuantumToChar(image->colormap[i].red) & 0xe0) |
+ (ScaleQuantumToChar(image->colormap[i].red) & 0xe0) >> 3 |
+ (ScaleQuantumToChar(image->colormap[i].red) & 0xc0) >> 6);
+ image->colormap[i].green=ScaleCharToQuantum(
+ (ScaleQuantumToChar(image->colormap[i].green) & 0xe0) |
+ (ScaleQuantumToChar(image->colormap[i].green) & 0xe0) >> 3 |
+ (ScaleQuantumToChar(image->colormap[i].green) & 0xc0) >> 6);
+ image->colormap[i].blue=ScaleCharToQuantum(
+ (ScaleQuantumToChar(image->colormap[i].blue) & 0xe0) |
+ (ScaleQuantumToChar(image->colormap[i].blue) & 0xe0) >> 3 |
+ (ScaleQuantumToChar(image->colormap[i].blue) & 0xc0) >> 6);
+ }
+ }
+ continue;
+ }
- if (logging != MagickFalse)
- {
+ if (image_colors == 0 || image_colors > 256)
+ {
+ if (logging != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " image->colors=%d", (int) image->colors);
-
- if (image->colormap != NULL)
- {
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " i (red,green,blue,opacity)");
+ " Quantizing the background color to 3-3-2");
- for (i=0; i < (ssize_t) image->colors; i++)
- {
- if (i < 300 || i >= image->colors - 10)
- {
- (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) image->colormap[i].opacity);
- }
- }
- }
+ /* Red and green were already done so we only quantize the blue
+ * channel
+ */
- if (logging != MagickFalse)
- {
- if (number_transparent < 257)
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " number_transparent = %d",
- number_transparent);
- else
+ image->background_color.blue=ScaleCharToQuantum(
+ (ScaleQuantumToChar(image->background_color.blue) & 0xc0) |
+ (ScaleQuantumToChar(image->background_color.blue) & 0xc0) >> 2 |
+ (ScaleQuantumToChar(image->background_color.blue) & 0xc0) >> 4 |
+ (ScaleQuantumToChar(image->background_color.blue) & 0xc0) >> 6);
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " number_transparent > 256");
+ if (logging != MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Quantizing the pixel colors to 3-3-2-1");
- if (number_opaque < 257)
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " number_opaque = %d",
- number_opaque);
- else
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " number_opaque > 256");
+ if (image->colormap == NULL)
+ {
+ for (y=0; y < (ssize_t) image->rows; y++)
+ {
+ r=GetAuthenticPixels(image,0,y,image->columns,1,
+ exception);
- if (number_semitransparent < 257)
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " number_semitransparent = %d",
- number_semitransparent);
- else
+ if (r == (PixelPacket *) NULL)
+ break;
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " number_semitransparent > 256");
- }
+ for (x=0; x < (ssize_t) image->columns; x++)
+ {
+ if (GetOpacityPixelComponent(r) == TransparentOpacity)
+ {
+ SetRGBPixelComponents(r,image->background_color);
+ }
+ else
+ {
+ SetBluePixelComponent(r,ScaleCharToQuantum(
+ (ScaleQuantumToChar(GetBluePixelComponent(r)) & 0xc0) |
+ (ScaleQuantumToChar(GetBluePixelComponent(r)) & 0xc0) >> 2 |
+ (ScaleQuantumToChar(GetBluePixelComponent(r)) & 0xc0) >> 4 |
+ (ScaleQuantumToChar(GetBluePixelComponent(r)) & 0xc0) >>
+ 6));
+ }
+ r++;
+ }
+
+ if (SyncAuthenticPixels(image,exception) == MagickFalse)
+ break;
+ }
+ }
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " Exit BUILD_PALETTE:");
- }
+ else /* Should not reach this; colormap already exists and
+ must be <= 256 */
+ {
+ if (logging != MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Quantizing the colormap to 3-3-2-1");
+ for (i=0; i<image_colors; i++)
+ {
+ image->colormap[i].blue=ScaleCharToQuantum(
+ (ScaleQuantumToChar(image->colormap[i].blue) & 0xc0) |
+ (ScaleQuantumToChar(image->colormap[i].blue) & 0xc0) >> 2 |
+ (ScaleQuantumToChar(image->colormap[i].blue) & 0xc0) >> 4 |
+ (ScaleQuantumToChar(image->colormap[i].blue) & 0xc0) >> 6);
+ }
+ }
+ continue;
}
-#endif /* BUILD_PNG_PALETTE */
+ break;
+ }
+ /* END OF BUILD_PALETTE */
+ /* If we are excluding the tRNS chunk and there is transparency,
+ * then we must write a Gray-Alpha (color-type 4) or RGBA (color-type 6)
+ * PNG.
+ */
if (mng_info->ping_exclude_tRNS != MagickFalse &&
(number_transparent != 0 || number_semitransparent != 0))
{
- int colortype=mng_info->write_png_colortype;
+ unsigned int colortype=mng_info->write_png_colortype;
if (ping_have_color == MagickFalse)
mng_info->write_png_colortype = 5;
else
mng_info->write_png_colortype = 7;
- if (colortype != 0 && mng_info->write_png_colortype != (ssize_t) colortype)
+ if (colortype != 0 &&
+ mng_info->write_png_colortype != colortype)
ping_need_colortype_warning=MagickTrue;
}
+ /* See if cheap transparency is possible. It is only possible
+ * when there is a single transparent color, no semitransparent
+ * color, and no opaque color that has the same RGB components
+ * as the transparent color. We only need this information if
+ * we are writing a PNG with colortype 0 or 2, and we have not
+ * excluded the tRNS chunk.
+ */
+ if (number_transparent == 1 &&
+ mng_info->write_png_colortype < 4)
+ {
+ ping_have_cheap_transparency = MagickTrue;
+
+ if (number_semitransparent != 0)
+ ping_have_cheap_transparency = MagickFalse;
+
+ else if (image_colors == 0 || image_colors > 256 ||
+ image->colormap == NULL)
+ {
+ ExceptionInfo
+ *exception;
+
+ register const PixelPacket
+ *q;
+
+ exception=(&image->exception);
+
+ for (y=0; y < (ssize_t) image->rows; y++)
+ {
+ q=GetVirtualPixels(image,0,y,image->columns,1, exception);
+
+ if (q == (PixelPacket *) NULL)
+ break;
+
+ for (x=0; x < (ssize_t) image->columns; x++)
+ {
+ if (q->opacity != TransparentOpacity &&
+ (unsigned short) GetRedPixelComponent(q) ==
+ ping_trans_color.red &&
+ (unsigned short) GetGreenPixelComponent(q) ==
+ ping_trans_color.green &&
+ (unsigned short) GetBluePixelComponent(q) ==
+ ping_trans_color.blue)
+ {
+ ping_have_cheap_transparency = MagickFalse;
+ break;
+ }
+
+ q++;
+ }
+
+ if (ping_have_cheap_transparency == MagickFalse)
+ break;
+ }
+ }
+ else
+ {
+ /* Assuming that image->colormap[0] is the one transparent color
+ * and that all others are opaque.
+ */
+ if (image_colors > 1)
+ for (i=1; i<image_colors; i++)
+ if (image->colormap[i].red == image->colormap[0].red &&
+ image->colormap[i].green == image->colormap[0].green &&
+ image->colormap[i].blue == image->colormap[0].blue)
+ {
+ ping_have_cheap_transparency = MagickFalse;
+ break;
+ }
+ }
+
+ if (logging != MagickFalse)
+ {
+ if (ping_have_cheap_transparency == MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Cheap transparency is not possible.");
+
+ else
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Cheap transparency is possible.");
+ }
+ }
+ else
+ ping_have_cheap_transparency = MagickFalse;
+
image_depth=image->depth;
quantum_info = (QuantumInfo *) NULL;
image_matte=image->matte;
mng_info->IsPalette=image->storage_class == PseudoClass &&
- image_colors <= 256;
+ image_colors <= 256 && image->colormap != NULL;
+
+ if ((mng_info->write_png_colortype == 4 || mng_info->write_png8) &&
+ (image->colors == 0 || image->colormap == NULL))
+ {
+ image_info=DestroyImageInfo(image_info);
+ image=DestroyImage(image);
+ (void) ThrowMagickException(&IMimage->exception,
+ GetMagickModule(),CoderError,
+ "Cannot write PNG8 or color-type 3; colormap is NULL",
+ "`%s'",IMimage->filename);
+#if defined(PNG_SETJMP_NOT_THREAD_SAFE)
+ UnlockSemaphoreInfo(ping_semaphore);
+#endif
+ return(MagickFalse);
+ }
/*
Allocate the PNG structures
#if defined(PNG_SETJMP_NOT_THREAD_SAFE)
UnlockSemaphoreInfo(ping_semaphore);
#endif
- if (mng_info->need_blob != MagickFalse)
+ if (ping_have_blob != MagickFalse)
(void) CloseBlob(image);
image_info=DestroyImageInfo(image_info);
image=DestroyImage(image);
if (image->units == PixelsPerInchResolution)
{
ping_pHYs_unit_type=PNG_RESOLUTION_METER;
- ping_pHYs_x_resolution=(png_uint_32) (100.0*image->x_resolution/2.54);
- ping_pHYs_y_resolution=(png_uint_32) (100.0*image->y_resolution/2.54);
+ ping_pHYs_x_resolution=
+ (png_uint_32) ((100.0*image->x_resolution+0.5)/2.54);
+ ping_pHYs_y_resolution=
+ (png_uint_32) ((100.0*image->y_resolution+0.5)/2.54);
}
else if (image->units == PixelsPerCentimeterResolution)
{
ping_pHYs_unit_type=PNG_RESOLUTION_METER;
- ping_pHYs_x_resolution=(png_uint_32) (100.0*image->x_resolution);
- ping_pHYs_y_resolution=(png_uint_32) (100.0*image->y_resolution);
+ ping_pHYs_x_resolution=(png_uint_32) (100.0*image->x_resolution+0.5);
+ ping_pHYs_y_resolution=(png_uint_32) (100.0*image->y_resolution+0.5);
}
else
ping_pHYs_y_resolution=(png_uint_32) image->y_resolution;
}
+ if (logging != MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Set up PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.",
+ (double) ping_pHYs_x_resolution,(double) ping_pHYs_y_resolution,
+ (int) ping_pHYs_unit_type);
ping_have_pHYs = MagickTrue;
}
}
ping_background.blue=(png_uint_16)
(ScaleQuantumToShort(image->background_color.blue) & mask);
+
+ ping_background.gray=(png_uint_16) ping_background.green;
}
if (logging != MagickFalse)
{
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" Setting up bKGD chunk (1)");
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " background_color index is %d",
+ (int) ping_background.index);
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" ping_bit_depth=%d",ping_bit_depth);
matte=image_matte;
old_bit_depth=0;
- if (mng_info->write_png8)
+ if (mng_info->IsPalette && mng_info->write_png8)
{
- /* TO DO: make this a function cause it's used twice, except
+ /* To do: make this a function cause it's used twice, except
for reducing the sample depth from 8. */
number_colors=image_colors;
for (i=0; i < (ssize_t) number_transparent; i++)
ping_trans_alpha[i]=0;
- /* PNG8 can't have semitransparent colors so we threshold them
- * to 0 or 255
- */
- for (; i < (ssize_t) number_semitransparent; i++)
- ping_trans_alpha[i]=image->colormap[i].opacity >
- OpaqueOpacity/2 ? 0 : 255;
ping_num_trans=(unsigned short) (number_transparent +
number_semitransparent);
ping_have_tRNS=MagickTrue;
}
- if (ping_exclude_bKGD == MagickFalse)
+ if (ping_exclude_bKGD == MagickFalse)
{
- /*
- * Identify which colormap entry is the background color.
- */
+ /*
+ * Identify which colormap entry is the background color.
+ */
+
for (i=0; i < (ssize_t) MagickMax(1L*number_colors-1L,1L); i++)
if (IsPNGColorEqual(ping_background,image->colormap[i]))
break;
ping_background.index=(png_byte) i;
+
+ if (logging != MagickFalse)
+ {
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " background_color index is %d",
+ (int) ping_background.index);
+ }
}
} /* end of write_png8 */
else
image_matte=MagickFalse;
+
+ if (logging != MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " PNG colortype %d was specified:",(int) ping_color_type);
}
- else /* write_ping_colortype not specified */
+ else /* write_png_colortype not specified */
{
if (logging != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
image_info->type == PaletteMatteType)
ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE;
- if (image_info->type == UndefinedType ||
- image_info->type == OptimizeType)
+ if (mng_info->write_png_colortype == 0 &&
+ (image_info->type == UndefinedType ||
+ image_info->type == OptimizeType))
{
if (ping_have_color == MagickFalse)
{
if (ping_color_type == PNG_COLOR_TYPE_GRAY)
{
- if (image->matte == MagickFalse && image->colors < 256)
- {
- if (ImageIsMonochrome(image))
- {
- ping_bit_depth=1;
- }
- }
+ if (image->matte == MagickFalse && ping_have_non_bw == MagickFalse)
+ ping_bit_depth=1;
}
if (ping_color_type == PNG_COLOR_TYPE_PALETTE)
{
if (mng_info->IsPalette)
{
+ if (mng_info->write_png_colortype == 0)
+ {
+ ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
- ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
-
- if (ping_have_color != MagickFalse)
- ping_color_type=PNG_COLOR_TYPE_RGBA;
+ if (ping_have_color != MagickFalse)
+ ping_color_type=PNG_COLOR_TYPE_RGBA;
+ }
/*
* Determine if there is any transparent color.
*/
image_matte=MagickFalse;
- ping_color_type&=0x03;
+
+ if (mng_info->write_png_colortype == 0)
+ ping_color_type&=0x03;
}
else
{
unsigned int
- mask;
+ mask;
mask=0xffff;
if (ping_have_tRNS != MagickFalse)
{
/*
- Determine if there is one and only one transparent color
- and if so if it is fully transparent.
- */
- if (logging != MagickFalse)
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " Is there a single fully transparent color?");
-
- if (number_transparent > 1 || number_semitransparent > 0)
- {
- ping_have_tRNS = MagickFalse;
- if (logging != MagickFalse)
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " ... No.");
- }
- else
- {
- if (logging != MagickFalse)
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " ... Yes: (%d,%d,%d), (gray: %d)",
- (int) ping_trans_color.red,
- (int) ping_trans_color.green,
- (int) ping_trans_color.blue,
- (int) ping_trans_color.gray);
- }
+ * Determine if there is one and only one transparent color
+ * and if so if it is fully transparent.
+ */
+ if (ping_have_cheap_transparency == MagickFalse)
+ ping_have_tRNS=MagickFalse;
}
if (ping_have_tRNS != MagickFalse)
{
- ping_color_type &= 0x03; /* changes 4 or 6 to 0 or 2 */
+ if (mng_info->write_png_colortype == 0)
+ ping_color_type &= 0x03; /* changes 4 or 6 to 0 or 2 */
if (image_depth == 8)
{
if ((mng_info->IsPalette) &&
mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE &&
- ImageIsGray(image) && (image_matte == MagickFalse || image_depth >= 8))
+ ping_have_color == MagickFalse &&
+ (image_matte == MagickFalse || image_depth >= 8))
{
size_t one=1;
if (image_matte != MagickFalse)
ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
- else
+ else if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_GRAY_ALPHA)
{
ping_color_type=PNG_COLOR_TYPE_GRAY;
if (image_depth > MAGICKCORE_QUANTUM_DEPTH)
image_depth=MAGICKCORE_QUANTUM_DEPTH;
- if (image_colors == 0 || image_colors-1 > MaxColormapSize)
+ if ((image_colors == 0) ||
+ ((ssize_t) (image_colors-1) > (ssize_t) MaxColormapSize))
image_colors=(int) (one << image_depth);
if (image_depth > 8)
PNG_COLOR_TYPE_GRAY && image_colors < 17 &&
mng_info->IsPalette)
{
-
/* Check if grayscale is reducible */
+
int
depth_4_ok=MagickTrue,
depth_2_ok=MagickTrue,
if ((intensity & 0x0f) != ((intensity & 0xf0) >> 4))
depth_4_ok=depth_2_ok=depth_1_ok=MagickFalse;
-
else if ((intensity & 0x03) != ((intensity & 0x0c) >> 2))
depth_2_ok=depth_1_ok=MagickFalse;
-
else if ((intensity & 0x01) != ((intensity & 0x02) >> 1))
depth_1_ok=MagickFalse;
}
ping_bit_depth=1;
one=1;
- while ((one << ping_bit_depth) < number_colors)
+ while ((one << ping_bit_depth) < (ssize_t) number_colors)
ping_bit_depth <<= 1;
}
if (logging != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" Setting up bKGD chunk (2)");
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " background_color index is %d",
+ (int) ping_background.index);
ping_have_bKGD = MagickTrue;
}
if (ping_exclude_bKGD == MagickFalse)
{
- if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
+ if (mng_info->IsPalette && (int) ping_color_type == PNG_COLOR_TYPE_PALETTE)
{
/*
Identify which colormap entry is the background color.
png_set_filter(ping,PNG_FILTER_TYPE_BASE,base_filter);
}
- if (ping_exclude_iCCP == MagickFalse || ping_exclude_zCCP == MagickFalse)
+ if ((ping_exclude_tEXt == MagickFalse || ping_exclude_zTXt == MagickFalse) &&
+ (ping_exclude_iCCP == MagickFalse || ping_exclude_zCCP == MagickFalse))
{
ResetImageProfileIterator(image);
for (name=GetNextImageProfile(image); name != (const char *) NULL; )
if (mng_info->write_png_colortype != 0)
{
if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY)
- if (ImageIsGray(image) == MagickFalse)
+ if (ping_have_color != MagickFalse)
{
ping_color_type = PNG_COLOR_TYPE_RGB;
}
if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY_ALPHA)
- if (ImageIsGray(image) == MagickFalse)
+ if (ping_have_color != MagickFalse)
ping_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
}
if (ping_exclude_bKGD == MagickFalse)
{
if (ping_have_bKGD != MagickFalse)
+ {
png_set_bKGD(ping,ping_info,&ping_background);
+ if (logging)
+ {
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Setting up bKGD chunk");
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " background color = (%d,%d,%d)",
+ (int) ping_background.red,
+ (int) ping_background.green,
+ (int) ping_background.blue);
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " index = %d, gray=%d",
+ (int) ping_background.index,
+ (int) ping_background.gray);
+ }
+ }
}
if (ping_exclude_pHYs == MagickFalse)
ping_pHYs_x_resolution,
ping_pHYs_y_resolution,
ping_pHYs_unit_type);
+
+ if (logging)
+ {
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Setting up pHYs chunk");
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " x_resolution=%lu",
+ (unsigned long) ping_pHYs_x_resolution);
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " y_resolution=%lu",
+ (unsigned long) ping_pHYs_y_resolution);
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " unit_type=%lu",
+ (unsigned long) ping_pHYs_unit_type);
+ }
}
}
}
#endif
+ if (mng_info->need_blob != MagickFalse)
+ {
+ if (OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception) ==
+ MagickFalse)
+ png_error(ping,"WriteBlob Failed");
+
+ ping_have_blob=MagickTrue;
+ }
+
png_write_info_before_PLTE(ping, ping_info);
if (ping_have_tRNS != MagickFalse && ping_color_type < 4)
/* write any png-chunk-b profiles */
(void) Magick_png_write_chunk_from_profile(image,"PNG-chunk-b",logging);
+
png_write_info(ping,ping_info);
/* write any PNG-chunk-m profiles */
#if defined(PNG_SETJMP_NOT_THREAD_SAFE)
UnlockSemaphoreInfo(ping_semaphore);
#endif
- if (mng_info->need_blob != MagickFalse)
+ if (ping_have_blob != MagickFalse)
(void) CloseBlob(image);
image_info=DestroyImageInfo(image_info);
image=DestroyImage(image);
!mng_info->write_png32) &&
(mng_info->IsPalette ||
(image_info->type == BilevelType)) &&
- image_matte == MagickFalse && ImageIsMonochrome(image))
+ image_matte == MagickFalse &&
+ ping_have_non_bw == MagickFalse)
{
/* Palette, Bilevel, or Opaque Monochrome */
register const PixelPacket
*/
for (y=0; y < (ssize_t) image->rows; y++)
{
-
- if (logging != MagickFalse)
+ if (logging != MagickFalse && y == 0)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" Writing row of pixels (0)");
!mng_info->write_png32) &&
(image_matte != MagickFalse ||
(ping_bit_depth >= MAGICKCORE_QUANTUM_DEPTH)) &&
- (mng_info->IsPalette) && ImageIsGray(image))
+ (mng_info->IsPalette) && ping_have_color == MagickFalse)
{
register const PixelPacket
*p;
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" pass %d, Image Is RGB, 16-bit GRAY, or GRAY_ALPHA",pass);
- p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
+ p=GetVirtualPixels(image,0,y,image->columns,1,
+ &image->exception);
if (p == (const PixelPacket *) NULL)
break;
if (ping_color_type == PNG_COLOR_TYPE_GRAY)
- (void) ExportQuantumPixels(image,(const CacheView *) NULL,
+ {
+ quantum_info->depth=image->depth;
+
+ (void) ExportQuantumPixels(image,(const CacheView *) NULL,
quantum_info,GrayQuantum,ping_pixels,&image->exception);
+ }
else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
{
}
else
- (void) ExportQuantumPixels(image,(const CacheView *) NULL,
- quantum_info,IndexQuantum,ping_pixels,&image->exception);
-
- if (logging != MagickFalse && y <= 2)
{
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " Writing row of pixels (4)");
+ (void) ExportQuantumPixels(image,(const CacheView *) NULL,
+ quantum_info,IndexQuantum,ping_pixels,&image->exception);
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " ping_pixels[0]=%d,ping_pixels[1]=%d",
- (int)ping_pixels[0],(int)ping_pixels[1]);
+ if (logging != MagickFalse && y <= 2)
+ {
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Writing row of non-gray pixels (4)");
+
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " ping_pixels[0]=%d,ping_pixels[1]=%d",
+ (int)ping_pixels[0],(int)ping_pixels[1]);
+ }
}
png_write_row(ping,ping_pixels);
}
" PNG Interlace method: %d",ping_interlace_method);
}
/*
- Generate text chunks.
+ Generate text chunks after IDAT.
*/
- if (ping_exclude_tEXt == MagickFalse && ping_exclude_zTXt == MagickFalse)
+ if (ping_exclude_tEXt == MagickFalse || ping_exclude_zTXt == MagickFalse)
{
ResetImagePropertyIterator(image);
property=GetNextImageProperty(image);
text;
value=GetImageProperty(image,property);
- if (value != (const char *) NULL)
- {
- text=(png_textp) png_malloc(ping,(png_uint_32) sizeof(png_text));
- text[0].key=(char *) property;
- text[0].text=(char *) value;
- text[0].text_length=strlen(value);
- if (ping_exclude_tEXt != MagickFalse)
- text[0].compression=PNG_TEXT_COMPRESSION_zTXt;
+ /* Don't write any "png:" properties; those are just for "identify" */
+ if (LocaleNCompare(property,"png:",4) != 0 &&
- else if (ping_exclude_zTXt != MagickFalse)
- text[0].compression=PNG_TEXT_COMPRESSION_NONE;
+ /* Suppress density and units if we wrote a pHYs chunk */
+ (ping_exclude_pHYs != MagickFalse ||
+ LocaleCompare(property,"density") != 0 ||
+ LocaleCompare(property,"units") != 0) &&
- else
+ /* Suppress the IM-generated Date:create and Date:modify */
+ (ping_exclude_date == MagickFalse ||
+ LocaleNCompare(property, "Date:",5) != 0))
+ {
+ if (value != (const char *) NULL)
{
- text[0].compression=image_info->compression == NoCompression ||
- (image_info->compression == UndefinedCompression &&
- text[0].text_length < 128) ? PNG_TEXT_COMPRESSION_NONE :
- PNG_TEXT_COMPRESSION_zTXt ;
- }
+ text=(png_textp) png_malloc(ping,(png_uint_32) sizeof(png_text));
+ text[0].key=(char *) property;
+ text[0].text=(char *) value;
+ text[0].text_length=strlen(value);
- if (logging != MagickFalse)
- {
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " Setting up text chunk");
+ if (ping_exclude_tEXt != MagickFalse)
+ text[0].compression=PNG_TEXT_COMPRESSION_zTXt;
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " keyword: %s",text[0].key);
+ else if (ping_exclude_zTXt != MagickFalse)
+ text[0].compression=PNG_TEXT_COMPRESSION_NONE;
+
+ else
+ {
+ text[0].compression=image_info->compression == NoCompression ||
+ (image_info->compression == UndefinedCompression &&
+ text[0].text_length < 128) ? PNG_TEXT_COMPRESSION_NONE :
+ PNG_TEXT_COMPRESSION_zTXt ;
}
- png_set_text(ping,ping_info,text,1);
- png_free(ping,text);
+ if (logging != MagickFalse)
+ {
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Setting up text chunk");
+
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " keyword: %s",text[0].key);
+ }
+
+ png_set_text(ping,ping_info,text,1);
+ png_free(ping,text);
+ }
}
property=GetNextImageProperty(image);
}
UnlockSemaphoreInfo(ping_semaphore);
#endif
- if (mng_info->need_blob != MagickFalse)
+ if (ping_have_blob != MagickFalse)
(void) CloseBlob(image);
image_info=DestroyImageInfo(image_info);
% be given the "png" file extension, this method also writes the following
% pseudo-formats which are subsets of PNG:
%
-% o PNG8: An 8-bit indexed PNG datastream is written. If transparency
+% o PNG8: An 8-bit indexed PNG datastream is written. If the image has
+% a depth greater than 8, the depth is reduced. If transparency
% is present, the tRNS chunk must only have values 0 and 255
% (i.e., transparency is binary: fully opaque or fully
-% transparent). The pixels contain 8-bit indices even if
-% they could be represented with 1, 2, or 4 bits. Note: grayscale
+% transparent). If other values are present they will be
+% 50%-thresholded to binary transparency. If more than 256
+% colors are present, they will be quantized to the 4-4-4-1,
+% 3-3-3-1, or 3-3-2-1 palette.
+%
+% If you want better quantization or dithering of the colors
+% or alpha than that, you need to do it before calling the
+% PNG encoder. The pixels contain 8-bit indices even if
+% they could be represented with 1, 2, or 4 bits. Grayscale
% images will be written as indexed PNG files even though the
-% PNG grayscale type might be slightly more efficient.
+% PNG grayscale type might be slightly more efficient. Please
+% note that writing to the PNG8 format may result in loss
+% of color and alpha data.
%
% o PNG24: An 8-bit per sample RGB PNG datastream is written. The tRNS
% chunk can be present to convey binary transparency by naming
-% one of the colors as transparent.
+% one of the colors as transparent. The only loss incurred
+% is reduction of sample depth to 8. If the image has more
+% than one transparent color, has semitransparent pixels, or
+% has an opaque pixel with the same RGB components as the
+% transparent color, an image is not written.
%
% o PNG32: An 8-bit per sample RGBA PNG is written. Partial
% transparency is permitted, i.e., the alpha sample for
% each pixel can have any value from 0 to 255. The alpha
% channel is present even if the image is fully opaque.
+% The only loss in data is the reduction of the sample depth
+% to 8.
%
% o -define: For more precise control of the PNG output, you can use the
% Image options "png:bit-depth" and "png:color-type". These
% When png:color-type is 4 (Gray-Matte) or 6 (RGB-Matte),
% png:bit-depth can be 8 or 16.
%
-% If the image cannot be written without loss in the requested PNG8, PNG24,
-% or PNG32 format or with the requested bit-depth and color-type without loss,
-% a PNG file will not be written, and the encoder will return MagickFalse.
+% If the image cannot be written without loss with the requested bit-depth
+% and color-type, a PNG file will not be written, and the encoder will
+% return MagickFalse.
+%
% Since image encoders should not be responsible for the "heavy lifting",
% the user should make sure that ImageMagick has already reduced the
% image depth and number of colors and limit transparency to binary
-% transparency prior to attempting to write the image in a format that
-% is subject to depth, color, or transparency limitations.
+% transparency prior to attempting to write the image with depth, color,
+% or transparency limitations.
%
-% TODO: Enforce the previous paragraph.
+% To do: Enforce the previous paragraph.
%
% Note that another definition, "png:bit-depth-written" exists, but it
% is not intended for external use. It is only used internally by the
assert(image != (Image *) NULL);
assert(image->signature == MagickSignature);
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
- logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WritePNGImage()");
+ logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WritePNGImage()");
/*
Allocate a MngInfo structure.
*/
mng_info->ping_exclude_bKGD=MagickFalse;
mng_info->ping_exclude_cHRM=MagickFalse;
+ mng_info->ping_exclude_date=MagickFalse;
mng_info->ping_exclude_EXIF=MagickFalse; /* hex-encoded EXIF in zTXt */
mng_info->ping_exclude_gAMA=MagickFalse;
- mng_info->ping_exclude_cHRM=MagickFalse;
mng_info->ping_exclude_iCCP=MagickFalse;
/* mng_info->ping_exclude_iTXt=MagickFalse; */
mng_info->ping_exclude_oFFs=MagickFalse;
mng_info->ping_exclude_zCCP=MagickFalse; /* hex-encoded iCCP in zTXt */
mng_info->ping_exclude_zTXt=MagickFalse;
+ mng_info->ping_preserve_colormap=MagickFalse;
+
+ value=GetImageArtifact(image,"png:preserve-colormap");
+ if (value == NULL)
+ value=GetImageOption(image_info,"png:preserve-colormap");
+ if (value != NULL)
+ mng_info->ping_preserve_colormap=MagickTrue;
+
excluding=MagickFalse;
for (source=0; source<1; source++)
{
mng_info->ping_exclude_bKGD=MagickTrue;
mng_info->ping_exclude_cHRM=MagickTrue;
+ mng_info->ping_exclude_date=MagickTrue;
mng_info->ping_exclude_EXIF=MagickTrue;
mng_info->ping_exclude_gAMA=MagickTrue;
mng_info->ping_exclude_iCCP=MagickTrue;
{
mng_info->ping_exclude_bKGD=MagickFalse;
mng_info->ping_exclude_cHRM=MagickFalse;
+ mng_info->ping_exclude_date=MagickFalse;
mng_info->ping_exclude_EXIF=MagickFalse;
mng_info->ping_exclude_gAMA=MagickFalse;
mng_info->ping_exclude_iCCP=MagickFalse;
if (LocaleNCompare(value+i,"chrm",4) == 0)
mng_info->ping_exclude_cHRM=MagickTrue;
+ if (LocaleNCompare(value+i,"date",4) == 0)
+ mng_info->ping_exclude_date=MagickTrue;
+
if (LocaleNCompare(value+i,"exif",4) == 0)
mng_info->ping_exclude_EXIF=MagickTrue;
{
mng_info->ping_exclude_bKGD=MagickFalse;
mng_info->ping_exclude_cHRM=MagickFalse;
+ mng_info->ping_exclude_date=MagickFalse;
mng_info->ping_exclude_EXIF=MagickFalse;
mng_info->ping_exclude_gAMA=MagickFalse;
mng_info->ping_exclude_iCCP=MagickFalse;
{
mng_info->ping_exclude_bKGD=MagickTrue;
mng_info->ping_exclude_cHRM=MagickTrue;
+ mng_info->ping_exclude_date=MagickTrue;
mng_info->ping_exclude_EXIF=MagickTrue;
mng_info->ping_exclude_gAMA=MagickTrue;
mng_info->ping_exclude_iCCP=MagickTrue;
if (LocaleNCompare(value+i,"chrm",4) == 0)
mng_info->ping_exclude_cHRM=MagickFalse;
+ if (LocaleNCompare(value+i,"date",4) == 0)
+ mng_info->ping_exclude_date=MagickFalse;
+
if (LocaleNCompare(value+i,"exif",4) == 0)
mng_info->ping_exclude_EXIF=MagickFalse;
if (mng_info->ping_exclude_cHRM != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" cHRM");
+ if (mng_info->ping_exclude_date != MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " date");
if (mng_info->ping_exclude_EXIF != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" EXIF");
jng_quality;
logging=LogMagickEvent(CoderEvent,GetMagickModule(),
- " enter WriteOneJNGImage()");
+ " Enter WriteOneJNGImage()");
blob=(unsigned char *) NULL;
jpeg_image=(Image *) NULL;
assert(image != (Image *) NULL);
assert(image->signature == MagickSignature);
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
- logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WriteJNGImage()");
+ logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteJNGImage()");
status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
if (status == MagickFalse)
return(status);
assert(image != (Image *) NULL);
assert(image->signature == MagickSignature);
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
- logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter WriteMNGImage()");
+ logging=LogMagickEvent(CoderEvent,GetMagickModule(),"Enter WriteMNGImage()");
status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
if (status == MagickFalse)
return(status);
" Writing PNG object.");
mng_info->need_blob = MagickFalse;
+ mng_info->ping_preserve_colormap = MagickFalse;
/* We don't want any ancillary chunks written */
mng_info->ping_exclude_bKGD=MagickTrue;
mng_info->ping_exclude_cHRM=MagickTrue;
+ mng_info->ping_exclude_date=MagickTrue;
mng_info->ping_exclude_EXIF=MagickTrue;
mng_info->ping_exclude_gAMA=MagickTrue;
- mng_info->ping_exclude_cHRM=MagickTrue;
mng_info->ping_exclude_iCCP=MagickTrue;
/* mng_info->ping_exclude_iTXt=MagickTrue; */
mng_info->ping_exclude_oFFs=MagickTrue;