((color).blue == (target).blue))
#endif
+/* Table of recognized sRGB ICC profiles */
+struct sRGB_info_struct
+{
+ png_uint_32 len;
+ png_uint_32 crc;
+ png_byte intent;
+};
+
+const struct sRGB_info_struct sRGB_info[] =
+{
+ /* ICC v2 perceptual no black compensation
+ * sRGB_IEC61966-2-1_black_scaled.icc
+ */
+ { 3048, 0x3b8772b9UL, 0},
+
+ /* ICC v2 relative no black compensation
+ * sRGB_IEC61966-2-1_no_black_scaling.icc
+ */
+ { 3052, 0x427ebb21UL, 1},
+
+ /* ICC v4 perceptual
+ * sRGB_v4_ICC_preference_displayclass.icc
+ */
+ {60988, 0x306fd8aeUL, 0},
+
+ /* ICC v4 perceptual
+ * sRGB_v4_ICC_preference.icc perceptual
+ */
+ {60960, 0xbbef7812UL, 0},
+
+ /* HP? sRGB v2 media-relative
+ * sRGB_IEC61966-2-1_noBPC.icc
+ */
+ { 3024, 0x5d5129ceUL, 1},
+
+ /* HP-Microsoft sRGB v2 perceptual */
+ { 3144, 0x182ea552UL, 0},
+
+ /* HP-Microsoft sRGB v2 media-relative */
+ { 3144, 0xf29e526dUL, 1},
+
+ /* Not recognized */
+ { 0, 0x00000000UL, 0},
+};
+
/* Macros for left-bit-replication to ensure that pixels
* and PixelInfos all have the same image->depth, and for use
* in PNG8 quantization.
*/
-
/* LBR01: Replicate top bit */
#define LBR01PacketRed(pixelpacket) \
ping_exclude_vpAg,
ping_exclude_zCCP, /* hex-encoded iCCP */
ping_exclude_zTXt,
- ping_preserve_colormap;
+ ping_preserve_colormap,
+ /* Added at version 6.8.5-7 */
+ ping_preserve_iCCP;
} MngInfo;
#endif /* VER */
ping_found_iCCP,
ping_found_sRGB,
ping_found_sRGB_cHRM,
+ ping_preserve_iCCP,
status;
PixelInfo
ping_found_gAMA = MagickFalse;
ping_found_iCCP = MagickFalse;
ping_found_sRGB = MagickFalse;
+ ping_preserve_iCCP = MagickFalse;
+
+ {
+ const char
+ *value;
+
+ value=GetImageOption(image_info,"png:preserve-iCCP");
+
+ if (value == NULL)
+ value=GetImageArtifact(image,"png:preserve-iCCP");
+
+ if (value != NULL)
+ ping_preserve_iCCP=MagickTrue;
+ }
/*
Allocate the PNG structures
ping_interlace_method,ping_filter_method);
}
+ if (png_get_valid(ping,ping_info, PNG_INFO_iCCP))
+ {
+ ping_found_iCCP=MagickTrue;
+ if (logging != MagickFalse)
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Found PNG iCCP chunk.");
+ }
+
if (png_get_valid(ping,ping_info,PNG_INFO_gAMA))
{
ping_found_gAMA=MagickTrue;
" Found PNG cHRM chunk.");
}
- if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
+ if (ping_found_iCCP != MagickTrue && png_get_valid(ping,ping_info,
+ PNG_INFO_sRGB))
{
- ping_found_iCCP=MagickTrue;
+ ping_found_sRGB=MagickTrue;
if (logging != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " Found PNG iCCP chunk.");
+ " Found PNG sRGB chunk.");
}
- if (png_get_valid(ping,ping_info,PNG_INFO_sRGB))
+#ifdef PNG_READ_iCCP_SUPPORTED
+ if (ping_found_iCCP !=MagickTrue &&
+ ping_found_sRGB != MagickTrue &&
+ png_get_valid(ping,ping_info, PNG_INFO_iCCP))
{
- ping_found_sRGB=MagickTrue;
+ ping_found_iCCP=MagickTrue;
if (logging != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " Found PNG sRGB chunk.");
+ " Found PNG iCCP chunk.");
}
-#ifdef PNG_READ_iCCP_SUPPORTED
if (png_get_valid(ping,ping_info,PNG_INFO_iCCP))
{
int
if (logging != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" Reading PNG iCCP chunk.");
+
profile=BlobToStringInfo(info,profile_length);
+
if (profile == (StringInfo *) NULL)
+ {
+ png_warning(ping, "ICC profile is NULL");
+ profile=DestroyStringInfo(profile);
+ }
+ else
+ {
+ if (ping_preserve_iCCP == MagickFalse)
{
- png_warning(ping, "ICC profile is NULL");
- profile=DestroyStringInfo(profile);
+ int
+ icheck,
+ got_crc=0;
+
+
+ png_uint_32
+ length,
+ profile_crc=0;
+
+ unsigned char
+ *data;
+
+ length=(png_uint_32) GetStringInfoLength(profile);
+
+ for (icheck=0; sRGB_info[icheck].len > 0; icheck++)
+ {
+ if (length == sRGB_info[icheck].len)
+ {
+ if (got_crc == 0)
+ {
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Got a %lu-byte ICC profile (potentially sRGB)",
+ (unsigned long) length);
+
+ data=GetStringInfoDatum(profile);
+ profile_crc=crc32(0,data,length);
+
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " with crc=%8x",(unsigned int) profile_crc);
+ got_crc++;
+ }
+
+ if (profile_crc == sRGB_info[icheck].crc)
+ {
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " It is sRGB with rendering intent = %s",
+ Magick_RenderingIntentString_from_PNG_RenderingIntent(
+ sRGB_info[icheck].intent));
+ if (image->rendering_intent==UndefinedIntent)
+ {
+ image->rendering_intent=
+ Magick_RenderingIntent_from_PNG_RenderingIntent(
+ sRGB_info[icheck].intent);
+ }
+ break;
+ }
+ }
+ }
+ if (sRGB_info[icheck].len == 0)
+ {
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Got a %lu-byte ICC profile not recognized as sRGB",
+ (unsigned long) length);
+ (void) SetImageProfile(image,"icc",profile,exception);
+ }
}
- else
+ else /* Preserve-iCCP */
{
- (void) SetImageProfile(image,"icc",profile,exception);
- profile=DestroyStringInfo(profile);
+ (void) SetImageProfile(image,"icc",profile,exception);
}
+
+ profile=DestroyStringInfo(profile);
+ }
}
}
#endif
+
#if defined(PNG_READ_sRGB_SUPPORTED)
{
- if (mng_info->have_global_srgb)
- {
- image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
- (mng_info->global_srgb_intent);
- }
-
- if (png_get_sRGB(ping,ping_info,&intent))
+ if (ping_found_iCCP==MagickFalse && png_get_valid(ping,ping_info,
+ PNG_INFO_sRGB))
+ {
+ if (png_get_sRGB(ping,ping_info,&intent))
{
- image->rendering_intent=Magick_RenderingIntent_from_PNG_RenderingIntent
- (intent);
+ if (image->rendering_intent == UndefinedIntent)
+ image->rendering_intent=
+ Magick_RenderingIntent_from_PNG_RenderingIntent (intent);
if (logging != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
" Reading PNG sRGB chunk: rendering_intent: %d",intent);
}
+ }
+
+ else if (mng_info->have_global_srgb)
+ {
+ if (image->rendering_intent == UndefinedIntent)
+ image->rendering_intent=
+ Magick_RenderingIntent_from_PNG_RenderingIntent
+ (mng_info->global_srgb_intent);
+ }
}
#endif
+
+
{
if (!png_get_gAMA(ping,ping_info,&file_gamma))
if (mng_info->have_global_gama)
&image->chromaticity.blue_primary.x,
&image->chromaticity.blue_primary.y);
+ ping_found_cHRM=MagickTrue;
+
if (image->chromaticity.red_primary.x>0.6399f &&
image->chromaticity.red_primary.x<0.6401f &&
image->chromaticity.red_primary.y>0.3299f &&
image->chromaticity.white_point.y>0.3289f &&
image->chromaticity.white_point.y<0.3291f)
ping_found_sRGB_cHRM=MagickTrue;
-
- ping_found_cHRM=MagickTrue;
}
if (image->rendering_intent != UndefinedIntent)
(char *) profile_type, (double) length);
}
-#if PNG_LIBPNG_VER >= 14000
+#if PNG_LIBPNG_VER >= 10400
text=(png_textp) png_malloc(ping,(png_alloc_size_t) sizeof(png_text));
#else
text=(png_textp) png_malloc(ping,(png_size_t) sizeof(png_text));
description_length=(png_uint_32) strlen((const char *) profile_description);
allocated_length=(png_uint_32) (length*2 + (length >> 5) + 20
+ description_length);
-#if PNG_LIBPNG_VER >= 14000
+#if PNG_LIBPNG_VER >= 10400
text[0].text=(png_charp) png_malloc(ping,
(png_alloc_size_t) allocated_length);
text[0].key=(png_charp) png_malloc(ping, (png_alloc_size_t) 80);
ping_exclude_zTXt,
ping_preserve_colormap,
+ ping_preserve_iCCP,
ping_need_colortype_warning,
status,
ping_exclude_zTXt=mng_info->ping_exclude_zTXt;
ping_preserve_colormap = mng_info->ping_preserve_colormap;
+ ping_preserve_iCCP = mng_info->ping_preserve_iCCP;
ping_need_colortype_warning = MagickFalse;
/* Recognize the ICC sRGB profile and convert it to the sRGB chunk,
* Note that this will not involve any changes to the actual pixels
* but merely passes information to applications that read the resulting
* PNG image.
+ *
+ * To do: recognize other variants of the sRGB profile, using the CRC to
+ * verify all recognized variants including the 7 already known.
+ *
+ * Work around libpng16+ rejecting some "known invalid sRGB profiles".
+ *
+ * Use something other than image->rendering_intent to record the fact
+ * that the sRGB profile was found.
+ *
+ * Record the ICC version (currently v2 or v4) of the incoming sRGB ICC
+ * profile. Record the Blackpoint Compensation, if any.
*/
- if (ping_exclude_sRGB == MagickFalse)
+ if (ping_exclude_sRGB == MagickFalse && ping_preserve_iCCP == MagickFalse)
{
char
*name;
if (profile != (StringInfo *) NULL)
{
if ((LocaleCompare(name,"ICC") == 0) ||
- (LocaleCompare(name,"ICM") == 0))
- {
+ (LocaleCompare(name,"ICM") == 0))
+
+ {
int
- icheck;
+ icheck,
+ got_crc=0;
- /* 0: not a known sRGB profile
- * 1: HP-Microsoft sRGB v2
- * 2: ICC sRGB v4 perceptual
- * 3: ICC sRGB v2 perceptual no black-compensation
- */
- png_uint_32
- check_crc[4] = {0, 0xf29e526dUL, 0xbbef7812UL, 0x427ebb21UL},
- check_len[4] = {0, 3144, 60960, 3052};
png_uint_32
length,
- profile_crc;
+ profile_crc=0;
unsigned char
*data;
length=(png_uint_32) GetStringInfoLength(profile);
- for (icheck=3; icheck > 0; icheck--)
+ for (icheck=0; sRGB_info[icheck].len > 0; icheck++)
{
- if (length == check_len[icheck])
+ if (length == sRGB_info[icheck].len)
{
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ if (got_crc == 0)
+ {
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
" Got a %lu-byte ICC profile (potentially sRGB)",
(unsigned long) length);
- data=GetStringInfoDatum(profile);
- profile_crc=crc32(0,data,length);
+ data=GetStringInfoDatum(profile);
+ profile_crc=crc32(0,data,length);
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " with crc=%8x",(unsigned int) profile_crc);
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " with crc=%8x",(unsigned int) profile_crc);
+ got_crc++;
+ }
- if (profile_crc == check_crc[icheck])
+ if (profile_crc == sRGB_info[icheck].crc)
{
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " It is sRGB.");
+ " It is sRGB with rendering intent = %s",
+ Magick_RenderingIntentString_from_PNG_RenderingIntent(
+ sRGB_info[icheck].intent));
if (image->rendering_intent==UndefinedIntent)
- image->rendering_intent=PerceptualIntent;
+ {
+ image->rendering_intent=
+ Magick_RenderingIntent_from_PNG_RenderingIntent(
+ sRGB_info[icheck].intent);
+ }
+ ping_exclude_iCCP = MagickTrue;
+ ping_exclude_zCCP = MagickTrue;
+ ping_have_sRGB = MagickTrue;
break;
}
}
}
- if (icheck == 0)
+ if (sRGB_info[icheck].len == 0)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
- " Got a %lu-byte ICC profile",
+ " Got a %lu-byte ICC profile not recognized as sRGB",
(unsigned long) length);
}
}
if (ping_exclude_iCCP == MagickFalse)
{
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Setting up iCCP chunk");
+
png_set_iCCP(ping,ping_info,(png_charp) name,0,
#if (PNG_LIBPNG_VER < 10500)
(png_charp) GetStringInfoDatum(profile),
#endif
if (ping_exclude_zCCP == MagickFalse)
{
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ " Setting up zTXT chunk with uuencoded ICC");
Magick_png_write_raw_profile(image_info,ping,ping_info,
(unsigned char *) name,(unsigned char *) name,
GetStringInfoDatum(profile),
(png_uint_32) GetStringInfoLength(profile));
+ ping_have_iCCP = MagickTrue;
}
}
#if defined(PNG_WRITE_sRGB_SUPPORTED)
if ((mng_info->have_write_global_srgb == 0) &&
- (png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
+ ping_have_iCCP != MagickTrue &&
+ (ping_have_sRGB != MagickFalse ||
+ png_get_valid(ping,ping_info,PNG_INFO_sRGB)))
{
if (ping_exclude_sRGB == MagickFalse)
{
if (value != (const char *) NULL)
{
-#if PNG_LIBPNG_VER >= 14000
+#if PNG_LIBPNG_VER >= 10400
text=(png_textp) png_malloc(ping,
(png_alloc_size_t) sizeof(png_text));
#else
if (value != NULL)
mng_info->ping_preserve_colormap=MagickTrue;
- /* Thes compression-level, compression-strategy, and compression-filter
+ mng_info->ping_preserve_iCCP=MagickFalse;
+
+ value=GetImageOption(image_info,"png:preserve-iCCP");
+ if (value == NULL)
+ value=GetImageArtifact(image,"png:preserve-iCCP");
+ if (value != NULL)
+ mng_info->ping_preserve_iCCP=MagickTrue;
+
+ /* These compression-level, compression-strategy, and compression-filter
* defines take precedence over values from the -quality option.
*/
value=GetImageOption(image_info,"png:compression-level");