/* #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
#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 */
static MagickBooleanType
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;
{
/* 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[]=
{
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 (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(),
- " length: %lu",(unsigned long) length);
- (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.
*/
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 (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;
}
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--)
*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_exclude_bKGD,
ping_exclude_cHRM,
+ ping_exclude_date,
/* ping_exclude_EXIF, */
ping_exclude_gAMA,
ping_exclude_iCCP,
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;
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_exclude_bKGD=mng_info->ping_exclude_bKGD;
ping_exclude_cHRM=mng_info->ping_exclude_cHRM;
+ 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_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;
(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 (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
- for (j=0; j<3; j++)
+ /* 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
*
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" (zero means unknown)");
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " Regenerate the colormap");
+ if (ping_preserve_colormap == MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Regenerate the colormap");
}
exception=(&image->exception);
for (x=0; x < (ssize_t) image->columns; x++)
{
- if (image->matte == MagickFalse || q->opacity == OpaqueOpacity)
+ if (image->matte == MagickFalse ||
+ GetOpacityPixelComponent(q) == OpaqueOpacity)
{
if (number_opaque < 259)
{
if (number_opaque == 0)
{
- opaque[0]=*q;
+ GetRGBPixelComponents(q, opaque[0]);
opaque[0].opacity=OpaqueOpacity;
number_opaque=1;
}
for (i=0; i< (ssize_t) number_opaque; i++)
{
- if (IsColorEqual(opaque+i, (PixelPacket *) q))
+ if (IsColorEqual(q, opaque+i))
break;
}
number_opaque < 259)
{
number_opaque++;
- opaque[i] = *q;
- opaque[i].opacity = OpaqueOpacity;
+ GetRGBPixelComponents(q, opaque[i]);
+ opaque[i].opacity=OpaqueOpacity;
}
}
}
{
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);
+ 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;
}
for (i=0; i< (ssize_t) number_transparent; i++)
{
- if (IsColorEqual(transparent+i, (PixelPacket *) q))
+ if (IsColorEqual(q, transparent+i))
break;
}
number_transparent < 259)
{
number_transparent++;
- transparent[i] = *q;
+ GetRGBOPixelComponents(q, transparent[i]);
}
}
}
{
if (number_semitransparent == 0)
{
- semitransparent[0]=*q;
+ GetRGBOPixelComponents(q, semitransparent[0]);
number_semitransparent = 1;
}
for (i=0; i< (ssize_t) number_semitransparent; i++)
{
- if (IsColorEqual(semitransparent+i,
- (PixelPacket *) q) &&
- q->opacity == semitransparent[i].opacity)
+ if (IsColorEqual(q, semitransparent+i)
+ && GetOpacityPixelComponent(q) ==
+ semitransparent[i].opacity)
break;
}
number_semitransparent < 259)
{
number_semitransparent++;
- semitransparent[i] = *q;
+ GetRGBOPixelComponents(q, semitransparent[i]);
}
}
}
/* Add the background color to the palette, if it
* isn't already there.
*/
+ if (logging != MagickFalse)
+ {
+ (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 (IsColorEqual(opaque+i,
- &image->background_color))
- break;
+ 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;
- opaque[i].opacity = OpaqueOpacity;
- 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 if (logging != MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " No room in the colormap to add background color");
}
image_colors=number_opaque+number_transparent+number_semitransparent;
+ 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)
" 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;
s=q;
for (x=0; x < (ssize_t) image->columns; x++)
{
- if (s->red != s->green || s->red != s->blue)
+ if (GetRedPixelComponent(s) != GetGreenPixelComponent(s)
+ || GetRedPixelComponent(s) != GetBluePixelComponent(s))
{
ping_have_color=MagickTrue;
ping_have_non_bw=MagickTrue;
s=q;
for (x=0; x < (ssize_t) image->columns; x++)
{
- if (s->red != 0 && s->red != QuantumRange)
+ if (GetRedPixelComponent(s) != 0 &&
+ GetRedPixelComponent(s) != QuantumRange)
{
ping_have_non_bw=MagickTrue;
}
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
if (AcquireImageColormap(image,image_colors) ==
MagickFalse)
ThrowWriterException(ResourceLimitError,
- "MemoryAllocationFailed");
+ "MemoryAllocationFailed");
for (i=0; i< (ssize_t) image_colors; i++)
image->colormap[i] = colormap[i];
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)))
+ image->colormap[i].opacity ==
+ GetOpacityPixelComponent(q)) &&
+ image->colormap[i].red ==
+ GetRedPixelComponent(q) &&
+ image->colormap[i].green ==
+ GetGreenPixelComponent(q) &&
+ image->colormap[i].blue ==
+ GetBluePixelComponent(q))
{
- indexes[x]=(IndexPacket) i;
+ SetIndexPixelComponent(indexes+x,i);
break;
}
}
for (i=0; i < (ssize_t) image->colors; i++)
{
- if (i < 300 || i >= image->colors - 10)
+ if (i < 300 || i >= (ssize_t) image->colors - 10)
{
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" %d (%d,%d,%d,%d)",
" Exit BUILD_PALETTE:");
}
- if (mng_info->write_png8)
- {
- if (image_colors <= 256 &&
- image_colors != 0 &&
- number_semitransparent == 0 &&
- number_transparent <= 1)
- break;
+ if (mng_info->write_png8 == MagickFalse)
+ break;
- /* PNG8 can't have semitransparent colors so we threshold them
- * to 0 or OpaqueOpacity
- */
- if (number_semitransparent != 0)
- {
+ /* 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(),
- " Thresholding the alpha channel to binary");
+ " 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);
- for (y=0; y < (ssize_t) image->rows; y++)
- {
- r=GetAuthenticPixels(image,0,y,image->columns,1,
- exception);
+ if (logging != MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Quantizing the pixel colors to 4-4-4");
- if (r == (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);
- for (x=0; x < (ssize_t) image->columns; x++)
- {
- r->opacity = r->opacity > OpaqueOpacity/2 ? 0 :
- OpaqueOpacity;
- r++;
- }
-
- if (SyncAuthenticPixels(image,exception) == MagickFalse)
- break;
+ if (r == (PixelPacket *) NULL)
+ break;
- if (image->colors != 0 && image->colors <= 256)
- for (i=0; i<image_colors; i++)
- image->colormap[i].opacity =
- image->colormap[i].opacity > OpaqueOpacity/2 ? 0 :
- OpaqueOpacity;
- }
- continue;
- }
+ 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;
+ }
+ }
- /* PNG8 can't have more than 256 colors so we do a quick and dirty
- * quantization of the pixels and background color to the 3-3-2
- * palette.
- */
- if (image_colors == 0 || image_colors > 256)
- {
- if (logging != MagickFalse)
+ else /* Should not reach this; colormap already exists and
+ must be <= 256 */
+ {
+ if (logging != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " Quantizing the background color to 3-3-2");
-
- image->background_color.red =
- (image->background_color.red & 0xe0) |
- ((image->background_color.red & 0xe0) >> 3) |
- ((image->background_color.red & 0xc0) >> 6);
- image->background_color.green =
- (image->background_color.green & 0xe0) |
- ((image->background_color.green & 0xe0) >> 3) |
- ((image->background_color.green & 0xc0) >> 6);
- image->background_color.blue =
- (image->background_color.blue & 0xe0) |
- ((image->background_color.blue & 0xe0) >> 3) |
- ((image->background_color.blue & 0xc0) >> 6);
+ " 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 (MAGICKCORE_QUANTUM_DEPTH > 8)
- image->background_color.red <<= (MAGICKCORE_QUANTUM_DEPTH-8);
- image->background_color.green <<= (MAGICKCORE_QUANTUM_DEPTH-8);
- image->background_color.blue <<= (MAGICKCORE_QUANTUM_DEPTH-8);
-#endif
+ 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-2");
- for (y=0; y < (ssize_t) image->rows; y++)
- {
- r=GetAuthenticPixels(image,0,y,image->columns,1,
- exception);
+ if (logging != MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Quantizing the pixel colors to 3-3-3-1");
- if (r == (PixelPacket *) NULL)
+ 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)) & 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;
+ }
+ }
- for (x=0; x < (ssize_t) image->columns; x++)
- {
- r->red = (r->red & 0xe0) | ((r->red & 0xe0) >> 3) |
- ((r->red & 0xc0) >> 6);
- r->green = (r->green & 0xe0) | ((r->green & 0xe0) >> 3) |
- ((r->green & 0xc0) >> 6);
- r->blue = (r->blue & 0xe0) | ((r->blue & 0xe0) >> 3) |
- ((r->blue & 0xc0) >> 6);
-#if (MAGICKCORE_QUANTUM_DEPTH > 8)
- r->red <<= (MAGICKCORE_QUANTUM_DEPTH-8);
- r->green <<= (MAGICKCORE_QUANTUM_DEPTH-8);
- r->blue <<= (MAGICKCORE_QUANTUM_DEPTH-8);
-#endif
- r++;
- }
+ 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 (image_colors == 0 || image_colors > 256)
+ {
+ if (logging != MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Quantizing the background color to 3-3-2");
+
+ /* Red and green were already done so we only quantize the blue
+ * channel
+ */
+
+ 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);
+
+ if (logging != MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Quantizing the pixel colors to 3-3-2-1");
+
+ 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
+ {
+ 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;
- }
+ if (SyncAuthenticPixels(image,exception) == MagickFalse)
+ break;
+ }
+ }
- if (image_colors != 0 && image_colors <= 256)
- {
- if (logging != MagickFalse)
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " Quantizing the colormap to 3-3-2");
- for (i=0; i<image_colors; i++)
- {
- image->colormap[i].red = (image->colormap[i].red & 0xe0) |
- ((image->colormap[i].red & 0xe0) >> 3) |
- ((image->colormap[i].red & 0xc0) >> 6);
- image->colormap[i].green = (image->colormap[i].green & 0xe0) |
- ((image->colormap[i].green & 0xe0) >> 3) |
- ((image->colormap[i].green & 0xc0) >> 6);
- image->colormap[i].blue = (image->colormap[i].blue & 0xe0) |
- ((image->colormap[i].blue & 0xe0) >> 3) |
- ((image->colormap[i].blue & 0xc0) >> 6);
-#if (MAGICKCORE_QUANTUM_DEPTH > 8)
- image->colormap[i].red <<= (MAGICKCORE_QUANTUM_DEPTH-8);
- image->colormap[i].green <<= (MAGICKCORE_QUANTUM_DEPTH-8);
- image->colormap[i].blue <<= (MAGICKCORE_QUANTUM_DEPTH-8);
-#endif
- }
- }
- continue;
- }
- break;
- }
- else
- 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-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;
+ }
+ break;
}
/* END OF BUILD_PALETTE */
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;
mng_info->write_png_colortype = 7;
if (colortype != 0 &&
- mng_info->write_png_colortype != (ssize_t) colortype)
+ 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.
+ * 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)
+ if (number_transparent == 1 &&
+ mng_info->write_png_colortype < 4)
{
ping_have_cheap_transparency = MagickTrue;
for (x=0; x < (ssize_t) image->columns; x++)
{
if (q->opacity != TransparentOpacity &&
- (unsigned short) q->red == ping_trans_color.red &&
- (unsigned short) q->green == ping_trans_color.green &&
- (unsigned short) q->blue == ping_trans_color.blue)
+ (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;
mng_info->IsPalette=image->storage_class == PseudoClass &&
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);
return(MagickFalse);
}
-
- if ((mng_info->write_png_colortype == 4 || mng_info->write_png8) &&
- (image->colors == 0 || image->colormap == NULL))
- {
- png_error(ping, "Cannot write PNG8 or color-type 3; colormap is NULL");
- }
-
/*
Prepare PNG for writing.
*/
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);
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 (mng_info->IsPalette)
{
- ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA;
+ if (mng_info->write_png_colortype == 0)
+ {
+ 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
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 (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)
}
}
-#if 1 /* To do: Enable this when low bit-depth grayscale is working */
else if (ping_color_type ==
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;
}
if (depth_1_ok && mng_info->write_png_depth <= 1)
ping_bit_depth=1;
-#if 0 /* To do: Enable this when bit depths 2 and 4 are working. */
else if (depth_2_ok && mng_info->write_png_depth <= 2)
ping_bit_depth=2;
else if (depth_4_ok && mng_info->write_png_depth <= 4)
ping_bit_depth=4;
-#endif
}
-#endif /* 1 */
}
image_depth=ping_bit_depth;
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;
}
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 (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);
(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
{
- /* To do:
- *
- * This is failing to account for 1, 2, 4-bit depths
- * The call to png_set_packing() above is supposed to
- * take care of those.
- */
-
- /* GrayQuantum does not work here */
(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)");
+ " Writing row of non-gray pixels (4)");
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" ping_pixels[0]=%d,ping_pixels[1]=%d",
" 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
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");
" 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;