From 0fe50b47f88ea0fc74b8bdb0e552fc7c58e2b5a0 Mon Sep 17 00:00:00 2001 From: glennrp Date: Tue, 16 Nov 2010 03:52:51 +0000 Subject: [PATCH] Fixed some indentation in coders/png.c and added some whitespace. --- coders/png.c | 1466 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 1103 insertions(+), 363 deletions(-) diff --git a/coders/png.c b/coders/png.c index 62e0095fa..6cb0334e4 100644 --- a/coders/png.c +++ b/coders/png.c @@ -478,17 +478,21 @@ static MagickBooleanType static int PNG_RenderingIntent_from_Magick_RenderingIntent(const RenderingIntent intent) -{ +{ switch (intent) { case PerceptualIntent: return 0; + case RelativeIntent: return 1; + case SaturationIntent: return 2; + case AbsoluteIntent: return 3; + default: return -1; } @@ -496,17 +500,21 @@ PNG_RenderingIntent_from_Magick_RenderingIntent(const RenderingIntent intent) static RenderingIntent PNG_RenderingIntent_to_Magick_RenderingIntent(const int png_intent) -{ +{ switch (png_intent) { case 0: return PerceptualIntent; + case 1: return RelativeIntent; + case 2: return SaturationIntent; + case 3: return AbsoluteIntent; + default: return UndefinedIntent; } @@ -516,12 +524,14 @@ static inline ssize_t MagickMax(const ssize_t x,const ssize_t y) { if (x > y) return(x); + return(y); } static inline ssize_t MagickMin(const ssize_t x,const ssize_t y) { if (x < y) return(x); + return(y); } @@ -629,11 +639,14 @@ static MagickBooleanType ImageIsMonochrome(Image *image) { 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++; } } @@ -672,8 +685,10 @@ static MagickBooleanType IsMNG(const unsigned char *magick,const size_t length) { if (length < 8) return(MagickFalse); + if (memcmp(magick,"\212MNG\r\n\032\n",8) == 0) return(MagickTrue); + return(MagickFalse); } @@ -707,8 +722,10 @@ static MagickBooleanType IsJNG(const unsigned char *magick,const size_t length) { if (length < 8) return(MagickFalse); + if (memcmp(magick,"\213JNG\r\n\032\n",8) == 0) return(MagickTrue); + return(MagickFalse); } @@ -741,8 +758,10 @@ static MagickBooleanType IsPNG(const unsigned char *magick,const size_t length) { if (length < 8) return(MagickFalse); + if (memcmp(magick,"\211PNG\r\n\032\n",8) == 0) return(MagickTrue); + return(MagickFalse); } @@ -967,8 +986,10 @@ static void mng_get_data(png_structp png_ptr,png_bytep data,png_size_t length) if (length) { check=(png_size_t) ReadBlob(image,(size_t) length,(char *) data); + if (check != length) png_error(png_ptr,"Read Exception"); + if (length == 4) { if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) && @@ -986,6 +1007,7 @@ static void mng_get_data(png_structp png_ptr,png_bytep data,png_size_t length) mng_info->have_saved_bkgd_index=MagickFalse; } } + if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0) && (data[3] == 1)) { @@ -1025,6 +1047,7 @@ static void png_put_data(png_structp png_ptr,png_bytep data,png_size_t length) check; check=(png_size_t) WriteBlob(image,(size_t) length,data); + if (check != length) png_error(png_ptr,"WriteBlob Failed"); } @@ -1043,10 +1066,13 @@ static int PalettesAreEqual(Image *a,Image *b) if ((a == (Image *) NULL) || (b == (Image *) NULL)) return((int) MagickFalse); + if (a->storage_class != PseudoClass || b->storage_class != PseudoClass) return((int) MagickFalse); + if (a->colors != b->colors) return((int) MagickFalse); + for (i=0; i < (ssize_t) a->colors; i++) { if ((a->colormap[i].red != b->colormap[i].red) || @@ -1054,6 +1080,7 @@ static int PalettesAreEqual(Image *a,Image *b) (a->colormap[i].blue != b->colormap[i].blue)) return((int) MagickFalse); } + return((int) MagickTrue); } #endif @@ -1068,10 +1095,12 @@ static void MngInfoDiscardObject(MngInfo *mng_info,int i) { if (mng_info->ob[i]->reference_count > 0) mng_info->ob[i]->reference_count--; + if (mng_info->ob[i]->reference_count == 0) { if (mng_info->ob[i]->image != (Image *) NULL) mng_info->ob[i]->image=DestroyImage(mng_info->ob[i]->image); + mng_info->ob[i]=DestroyString(mng_info->ob[i]); } } @@ -1099,9 +1128,11 @@ static void MngInfoFreeStruct(MngInfo *mng_info,int *have_mng_structure) for (i=1; i < MNG_MAX_OBJECTS; i++) MngInfoDiscardObject(mng_info,i); + if (mng_info->global_plte != (png_colorp) NULL) mng_info->global_plte=(png_colorp) RelinquishMagickMemory(mng_info->global_plte); + mng_info=(MngInfo *) RelinquishMagickMemory(mng_info); *have_mng_structure=MagickFalse; } @@ -1115,12 +1146,16 @@ static MngBox mng_minimum_box(MngBox box1,MngBox box2) box=box1; if (box.left < box2.left) box.left=box2.left; + if (box.top < box2.top) box.top=box2.top; + if (box.right > box2.right) box.right=box2.right; + if (box.bottom > box2.bottom) box.bottom=box2.bottom; + return box; } @@ -1143,6 +1178,7 @@ static MngBox mng_read_box(MngBox previous_box,char delta_type,unsigned char *p) box.top+=previous_box.top; box.bottom+=previous_box.bottom; } + return(box); } @@ -1156,11 +1192,13 @@ static MngPair mng_read_pair(MngPair previous_pair,int delta_type, */ pair.a=(long) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]); pair.b=(long) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]); + if (delta_type != 0) { pair.a+=previous_pair.a; pair.b+=previous_pair.b; } + return(pair); } @@ -1175,11 +1213,14 @@ static void PNGErrorHandler(png_struct *ping,png_const_charp message) *image; image=(Image *) png_get_error_ptr(ping); + if (image->debug != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " libpng-%s error: %s", PNG_LIBPNG_VER_STRING,message); + (void) ThrowMagickException(&image->exception,GetMagickModule(),CoderError, message,"`%s'",image->filename); + #if PNG_LIBPNG_VER < 10500 longjmp(ping->jmpbuf,1); #else @@ -1194,10 +1235,12 @@ static void PNGWarningHandler(png_struct *ping,png_const_charp message) if (LocaleCompare(message, "Missing PLTE before tRNS") == 0) png_error(ping, message); + image=(Image *) png_get_error_ptr(ping); if (image->debug != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " libpng-%s warning: %s", PNG_LIBPNG_VER_STRING,message); + (void) ThrowMagickException(&image->exception,GetMagickModule(),CoderWarning, message,"`%s'",image->filename); } @@ -1211,8 +1254,10 @@ static png_voidp png_IM_malloc(png_structp png_ptr,png_uint_32 size) png_ptr=png_ptr; ret=((png_voidp) AcquireMagickMemory((size_t) size)); + if (ret == NULL) png_error("Insufficient memory."); + return(ret); #else png_ptr=png_ptr; @@ -1267,12 +1312,16 @@ png_read_raw_profile(Image *image, const ImageInfo *image_info, /* look for newline */ while (*sp != '\n') sp++; + /* look for length */ while (*sp == '\0' || *sp == ' ' || *sp == '\n') sp++; + length=(png_uint_32) StringToLong(sp); + while (*sp != ' ' && *sp != '\n') sp++; + /* allocate space */ if (length == 0) { @@ -1280,7 +1329,9 @@ png_read_raw_profile(Image *image, const ImageInfo *image_info, CoderWarning,"UnableToCopyProfile","`%s'","invalid profile length"); return(MagickFalse); } + profile=AcquireStringInfo(length); + if (profile == (StringInfo *) NULL) { (void) ThrowMagickException(&image->exception,GetMagickModule(), @@ -1288,9 +1339,11 @@ png_read_raw_profile(Image *image, const ImageInfo *image_info, "unable to copy profile"); return(MagickFalse); } + /* copy profile, skipping white space and column 1 "=" signs */ dp=GetStringInfoDatum(profile); nibbles=length*2; + for (i=0; i < (ssize_t) nibbles; i++) { while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f') @@ -1304,8 +1357,10 @@ png_read_raw_profile(Image *image, const ImageInfo *image_info, } sp++; } + if (i%2 == 0) *dp=(unsigned char) (16*unhex[(int) *sp++]); + else (*dp++)+=unhex[(int) *sp++]; } @@ -1314,8 +1369,10 @@ png_read_raw_profile(Image *image, const ImageInfo *image_info, */ (void) SetImageProfile(image,&text[ii].key[17],profile); profile=DestroyStringInfo(profile); + if (image_info->verbose) (void) printf(" Found a generic profile, type %s\n",&text[ii].key[17]); + return MagickTrue; } @@ -1351,6 +1408,7 @@ static int read_vpag_chunk_callback(png_struct *ping, png_unknown_chunkp chunk) image->page.width=(size_t) ((chunk->data[0] << 24) | (chunk->data[1] << 16) | (chunk->data[2] << 8) | chunk->data[3]); + image->page.height=(size_t) ((chunk->data[4] << 24) | (chunk->data[5] << 16) | (chunk->data[6] << 8) | chunk->data[7]); @@ -1521,19 +1579,25 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, #endif if (ping == (png_struct *) NULL) ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); + ping_info=png_create_info_struct(ping); + if (ping_info == (png_info *) NULL) { png_destroy_read_struct(&ping,(png_info **) NULL,(png_info **) NULL); ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); } + end_info=png_create_info_struct(ping); + if (end_info == (png_info *) NULL) { png_destroy_read_struct(&ping,&ping_info,(png_info **) NULL); ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); } + png_pixels=(unsigned char *) NULL; + if (setjmp(png_jmpbuf(ping))) { /* @@ -1546,11 +1610,13 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " exit ReadOnePNGImage() with error."); + if (image != (Image *) NULL) { InheritException(exception,&image->exception); image->columns=0; } + return(GetFirstImageInList(image)); } /* @@ -1559,6 +1625,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, mng_info->image_found++; png_set_sig_bytes(ping,8); + if (LocaleCompare(image_info->magick,"MNG") == 0) { #if defined(PNG_MNG_FEATURES_SUPPORTED) @@ -1577,6 +1644,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, #endif #endif } + else png_set_read_fn(ping,image,png_get_data); @@ -1638,12 +1706,15 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, (void) LogMagickEvent(CoderEvent,GetMagickModule(), " PNG width: %.20g, height: %.20g", (double) ping_width, (double) ping_height); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " PNG color_type: %d, bit_depth: %d", ping_color_type, ping_bit_depth); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " PNG compression_method: %d", ping_compression_method); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " PNG interlace_method: %d, filter_method: %d", ping_interlace_method,ping_filter_method); @@ -1664,6 +1735,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, (void) png_get_iCCP(ping,ping_info,&name,(int *) &compression,&info, &profile_length); + if (profile_length != 0) { StringInfo @@ -1687,10 +1759,12 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, if (mng_info->have_global_srgb) image->rendering_intent=PNG_RenderingIntent_to_Magick_RenderingIntent( mng_info->global_srgb_intent); + if (png_get_sRGB(ping,ping_info,&intent)) { image->rendering_intent=PNG_RenderingIntent_to_Magick_RenderingIntent( intent); + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Reading PNG sRGB chunk: rendering_intent: %d",intent); @@ -1704,6 +1778,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, 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_gAMA(ping,ping_info,&file_gamma)) { image->gamma=(float) file_gamma; @@ -1727,6 +1802,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, mng_info->global_chrm.blue_primary.y); } } + if (png_get_valid(ping,ping_info,PNG_INFO_cHRM)) { (void) png_get_cHRM(ping,ping_info, @@ -1738,10 +1814,12 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, &image->chromaticity.green_primary.y, &image->chromaticity.blue_primary.x, &image->chromaticity.blue_primary.y); + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Reading PNG cHRM chunk."); } + if (image->rendering_intent != UndefinedIntent) { png_set_sRGB(ping,ping_info, @@ -1757,6 +1835,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, { image->page.x=png_get_x_offset_pixels(ping, ping_info); image->page.y=png_get_y_offset_pixels(ping, ping_info); + if (logging != MagickFalse) if (image->page.x || image->page.y) (void) LogMagickEvent(CoderEvent,GetMagickModule(), @@ -1792,12 +1871,14 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, &unit_type); image->x_resolution=(double) x_resolution; image->y_resolution=(double) y_resolution; + if (unit_type == PNG_RESOLUTION_METER) { image->units=PixelsPerCentimeterResolution; image->x_resolution=(double) x_resolution/100.0; image->y_resolution=(double) y_resolution/100.0; } + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Reading PNG pHYs chunk: xres: %.20g, yres: %.20g, units: %d.", @@ -1813,6 +1894,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, palette; (void) png_get_PLTE(ping,ping_info,&palette,&number_colors); + if ((number_colors == 0) && ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE)) { @@ -1820,6 +1902,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, { png_set_PLTE(ping,ping_info,mng_info->global_plte, (int) mng_info->global_plte_length); + if (!png_get_valid(ping,ping_info,PNG_INFO_tRNS)) if (mng_info->global_trns_length) { @@ -1848,12 +1931,16 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, #endif if (png_get_valid(ping, ping_info, PNG_INFO_bKGD)) background.index=ping_background->index; + background.red=(png_uint_16) mng_info->global_plte[background.index].red; + background.green=(png_uint_16) mng_info->global_plte[background.index].green; + background.blue=(png_uint_16) mng_info->global_plte[background.index].blue; + png_set_bKGD(ping,ping_info,&background); } #endif @@ -1869,6 +1956,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, 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)) { /* @@ -1877,12 +1965,14 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, if (logging != MagickFalse) (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 @@ -1894,12 +1984,16 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, ping_background->green,ping_background->blue); bkgd_scale = 1; + if (ping_bit_depth == 1) bkgd_scale = 255; + else if (ping_bit_depth == 2) bkgd_scale = 85; + else if (ping_bit_depth == 4) bkgd_scale = 17; + if (ping_bit_depth <= 8) bkgd_scale *= 257; @@ -1911,6 +2005,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, { (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); @@ -1918,10 +2013,13 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, image->background_color.red= ScaleShortToQuantum(ping_background->red); + image->background_color.green= ScaleShortToQuantum(ping_background->green); + image->background_color.blue= ScaleShortToQuantum(ping_background->blue); + image->background_color.opacity=OpaqueOpacity; if (logging != MagickFalse) @@ -1994,6 +2092,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, { (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Raw tRNS graylevel is %d.",ping_trans_color->gray); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " scaled graylevel is %d.",transparent_color.opacity); } @@ -2030,10 +2129,12 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, mng_info->frame=mng_info->image_box; mng_info->clip=mng_info->image_box; } + else { image->page.y=mng_info->y_off[mng_info->object_id]; } + image->compression=ZipCompression; image->columns=ping_width; image->rows=ping_height; @@ -2064,6 +2165,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, (void) png_get_PLTE(ping,ping_info,&palette,&number_colors); image->colors=(size_t) number_colors; + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Reading PNG PLTE chunk: number_colors: %d.",number_colors); @@ -2077,6 +2179,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, */ if (AcquireImageColormap(image,image->colors) == MagickFalse) ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); + if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) { int @@ -2086,6 +2189,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, palette; (void) png_get_PLTE(ping,ping_info,&palette,&number_colors); + for (i=0; i < (ssize_t) image->colors; i++) { image->colormap[i].red=ScaleCharToQuantum(palette[i].red); @@ -2093,14 +2197,17 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, image->colormap[i].blue=ScaleCharToQuantum(palette[i].blue); } } + else { size_t scale; scale=(QuantumRange/((1UL << ping_bit_depth)-1)); + if (scale < 1) scale=1; + for (i=0; i < (ssize_t) image->colors; i++) { image->colormap[i].red=(Quantum) (i*scale); @@ -2114,6 +2221,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, */ if (image->delay != 0) mng_info->scenes_found++; + if ((mng_info->mng_type == 0 && (image->ping != MagickFalse)) || ( (image_info->number_scenes != 0) && (mng_info->scenes_found > (ssize_t) (image_info->first_scene+image_info->number_scenes)))) @@ -2129,19 +2237,25 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " exit ReadOnePNGImage()."); + return(image); } + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Reading PNG IDAT chunk(s)"); + if (num_passes > 1) png_pixels=(unsigned char *) AcquireQuantumMemory(image->rows, ping_rowbytes*sizeof(*png_pixels)); + else png_pixels=(unsigned char *) AcquireQuantumMemory(ping_rowbytes, sizeof(*png_pixels)); + if (png_pixels == (unsigned char *) NULL) ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Converting PNG pixels to pixel packets"); @@ -2159,21 +2273,28 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, #endif if (quantum_info != (QuantumInfo *) NULL) quantum_info = DestroyQuantumInfo(quantum_info); + if (png_pixels != (unsigned char *) NULL) png_pixels=(unsigned char *) RelinquishMagickMemory(png_pixels); + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " exit ReadOnePNGImage() with error."); + if (image != (Image *) NULL) { InheritException(exception,&image->exception); image->columns=0; } + return(GetFirstImageInList(image)); } + quantum_info=AcquireQuantumInfo(image_info,image); + if (quantum_info == (QuantumInfo *) NULL) ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); + if (image->storage_class == DirectClass) for (pass=0; pass < num_passes; pass++) { @@ -2195,10 +2316,13 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, { if (num_passes > 1) row_offset=ping_rowbytes*y; + else row_offset=0; + png_read_row(ping,png_pixels+row_offset,NULL); q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); + if (q == (PixelPacket *) NULL) break; #if (0 && (MAGICKCORE_QUANTUM_DEPTH == 8) && !defined(MAGICKCORE_HDRI_SUPPORT)) @@ -2259,12 +2383,14 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, *r++=OpaqueOpacity; } } + else if (ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) for (x=(ssize_t) (4*image->columns); x != 0; x--) { *r++=*p++; p++; } + else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) for (x=(ssize_t) (2*image->columns); x != 0; x--) { @@ -2275,6 +2401,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, if (depth == 8 && ping_color_type == PNG_COLOR_TYPE_GRAY) (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info, GrayQuantum,png_pixels+row_offset); + if (ping_color_type == PNG_COLOR_TYPE_GRAY || ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { @@ -2282,9 +2409,11 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info, GrayAlphaQuantum,png_pixels+row_offset); } + else if (depth == 8 && ping_color_type == PNG_COLOR_TYPE_RGB) (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info, RGBQuantum,png_pixels+row_offset); + else if (ping_color_type == PNG_COLOR_TYPE_RGB || ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) { @@ -2292,22 +2421,28 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info, RGBAQuantum,png_pixels+row_offset); } + else if (ping_color_type == PNG_COLOR_TYPE_PALETTE) (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info, IndexQuantum,png_pixels+row_offset); #else /* (MAGICKCORE_QUANTUM_DEPTH != 8) */ + if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY) (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info, GrayQuantum,png_pixels+row_offset,exception); + else if ((int) ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info, GrayAlphaQuantum,png_pixels+row_offset,exception); + else if ((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info, RGBAQuantum,png_pixels+row_offset,exception); + else if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info, IndexQuantum,png_pixels+row_offset,exception); + else (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info, RGBQuantum,png_pixels+row_offset,exception); @@ -2316,12 +2451,14 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, { status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, image->rows); + if (status == MagickFalse) break; } if (SyncAuthenticPixels(image,exception) == MagickFalse) break; } + if ((image->previous == (Image *) NULL) && (num_passes != 1)) { status=SetImageProgress(image,LoadImageTag,pass,num_passes); @@ -2329,6 +2466,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, break; } } + else /* image->storage_class != DirectClass */ for (pass=0; pass < num_passes; pass++) { @@ -2343,10 +2481,13 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, */ image->matte=ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ? MagickTrue : MagickFalse; + quantum_scanline=(Quantum *) AcquireQuantumMemory(image->columns, (image->matte ? 2 : 1)*sizeof(*quantum_scanline)); + if (quantum_scanline == (Quantum *) NULL) ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); + for (y=0; y < (ssize_t) image->rows; y++) { if (num_passes > 1) @@ -2355,8 +2496,10 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, row_offset=0; png_read_row(ping,png_pixels+row_offset,NULL); q=GetAuthenticPixels(image,0,y,image->columns,1,exception); + if (q == (PixelPacket *) NULL) break; + indexes=GetAuthenticIndexQueue(image); p=png_pixels+row_offset; r=quantum_scanline; @@ -2373,11 +2516,13 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, *r++=(Quantum) ((*p) & (0x01 << bit) ? 0x01 : 0x00); p++; } + if ((image->columns % 8) != 0) { for (bit=7; bit >= (ssize_t) (8-(image->columns % 8)); bit--) *r++=(Quantum) ((*p) & (0x01 << bit) ? 0x01 : 0x00); } + break; } case 2: @@ -2389,11 +2534,13 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, *r++=(*p >> 2) & 0x03; *r++=(*p++) & 0x03; } + if ((image->columns % 4) != 0) { for (i=3; i >= (ssize_t) (4-(image->columns % 4)); i--) *r++=(Quantum) ((*p >> (i*2)) & 0x03); } + break; } case 4: @@ -2403,8 +2550,10 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, *r++=(*p >> 4) & 0x0f; *r++=(*p++) & 0x0f; } + if ((image->columns % 2) != 0) *r++=(*p++ >> 4) & 0x0f; + break; } case 8: @@ -2421,9 +2570,11 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, q->opacity=ScaleCharToQuantum((unsigned char) (255-(*p++))); q++; } + else for (x=(ssize_t) image->columns-1; x >= 0; x--) *r++=*p++; + break; } case 16: @@ -2436,8 +2587,10 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, if (image->colors > 256) *r=((*p++) << 8); + else *r=0; + quantum=(*r); quantum|=(*p++); *r=(Quantum) quantum; @@ -2456,12 +2609,15 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, if (image->colors > 256) *r=((*p++) << 8); + else *r=0; + quantum=(*r); quantum|=(*p++); *r=quantum; r++; + if (ping_color_type == 4) { q->opacity=(*p << 8) | *(p+1); @@ -2491,10 +2647,13 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, Transfer image scanline. */ r=quantum_scanline; + for (x=0; x < (ssize_t) image->columns; x++) indexes[x]=(IndexPacket) (*r++); + if (SyncAuthenticPixels(image,exception) == MagickFalse) break; + if ((image->previous == (Image *) NULL) && (num_passes == 1)) { status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, @@ -2513,6 +2672,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, } if (quantum_info != (QuantumInfo *) NULL) quantum_info=DestroyQuantumInfo(quantum_info); + if (image->storage_class == PseudoClass) { MagickBooleanType @@ -2554,64 +2714,69 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, #if 1 /* balfour fix */ /* From imagemagick discourse server, 5 Feb 2010 */ - if (storage_class == PseudoClass) - { - if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) - { - for (x=0; x < ping_num_trans; x++) - { - image->colormap[x].opacity = - ScaleCharToQuantum((unsigned char)(255-ping_trans_alpha[x])); - } - } - else if (ping_color_type == PNG_COLOR_TYPE_GRAY) - { - for (x=0; x < (int) image->colors; x++) - { - if (ScaleQuantumToShort(image->colormap[x].red) == - transparent_color.opacity) + if (storage_class == PseudoClass) + { + if ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) { - image->colormap[x].opacity = (Quantum) TransparentOpacity; + for (x=0; x < ping_num_trans; x++) + { + image->colormap[x].opacity = + ScaleCharToQuantum((unsigned char)(255-ping_trans_alpha[x])); + } } - } - } - (void) SyncImage(image); - } - else - { + else if (ping_color_type == PNG_COLOR_TYPE_GRAY) + { + for (x=0; x < (int) image->colors; x++) + { + if (ScaleQuantumToShort(image->colormap[x].red) == + transparent_color.opacity) + { + image->colormap[x].opacity = (Quantum) TransparentOpacity; + } + } + } + (void) SyncImage(image); + } + else + { + for (y=0; y < (ssize_t) image->rows; y++) + { + image->storage_class=storage_class; + q=GetAuthenticPixels(image,0,y,image->columns,1,exception); - for (y=0; y < (ssize_t) image->rows; y++) - { - image->storage_class=storage_class; - q=GetAuthenticPixels(image,0,y,image->columns,1,exception); - if (q == (PixelPacket *) NULL) - break; - indexes=GetAuthenticIndexQueue(image); + if (q == (PixelPacket *) NULL) + break; - 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) - q->opacity=(Quantum) TransparentOpacity; - else - SetOpacityPixelComponent(q,OpaqueOpacity); - q++; + indexes=GetAuthenticIndexQueue(image); + + 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) + q->opacity=(Quantum) TransparentOpacity; + + else + SetOpacityPixelComponent(q,OpaqueOpacity); + + q++; + } + + if (SyncAuthenticPixels(image,exception) == MagickFalse) + break; } - if (SyncAuthenticPixels(image,exception) == MagickFalse) - break; - } - } + } #else /* not balfour */ - for (y=0; y < (ssize_t) image->rows; y++) { image->storage_class=storage_class; q=GetAuthenticPixels(image,0,y,image->columns,1,exception); + if (q == (PixelPacket *) NULL) break; + indexes=GetAuthenticIndexQueue(image); if (storage_class == PseudoClass) @@ -2623,11 +2788,14 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, for (x=0; x < (ssize_t) image->columns; x++) { indexpacket=indexes[x]; + if (indexpacket < ping_num_trans) q->opacity=ScaleCharToQuantum((unsigned char) (255-ping_trans_alpha[(ssize_t) indexpacket])); + else SetOpacityPixelComponent(q,OpaqueOpacity); + q++; } else if (ping_color_type == PNG_COLOR_TYPE_GRAY) @@ -2637,10 +2805,13 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, q->red=image->colormap[(ssize_t) indexpacket].red; q->green=q->red; q->blue=q->red; + if (ScaleQuantomToShort(q->red) == transparent_color.opacity) q->opacity=(Quantum) TransparentOpacity; + else SetOpacityPixelComponent(q,OpaqueOpacity); + q++; } } @@ -2651,8 +2822,10 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, ScaleQuantumToShort(q->green) == transparent_color.green && ScaleQuantumToShort(q->blue) == transparent_color.blue) q->opacity=(Quantum) TransparentOpacity; + else SetOpacityPixelComponent(q,OpaqueOpacity); + q++; } if (SyncAuthenticPixels(image,exception) == MagickFalse) @@ -2672,8 +2845,10 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Reading PNG text chunk"); + if (memcmp(text[i].key, "Raw profile type ",17) == 0) (void) png_read_raw_profile(image,image_info,text,(int) i); + else { char @@ -2692,9 +2867,11 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, *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); } } @@ -2711,6 +2888,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, */ mng_info->ob[object_id]=(MngBuffer *) AcquireMagickMemory(sizeof(MngBuffer)); + if (mng_info->ob[object_id] != (MngBuffer *) NULL) { mng_info->ob[object_id]->image=(Image *) NULL; @@ -2724,27 +2902,34 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, (void) ThrowMagickException(&image->exception,GetMagickModule(), ResourceLimitError,"MemoryAllocationFailed","`%s'", image->filename); + if (mng_info->ob[object_id]->frozen) (void) ThrowMagickException(&image->exception,GetMagickModule(), ResourceLimitError,"Cannot overwrite frozen MNG object buffer", "`%s'",image->filename); } + else { if (mng_info->ob[object_id]->image != (Image *) NULL) mng_info->ob[object_id]->image=DestroyImage (mng_info->ob[object_id]->image); + mng_info->ob[object_id]->image=CloneImage(image,0,0,MagickTrue, &image->exception); + if (mng_info->ob[object_id]->image != (Image *) NULL) mng_info->ob[object_id]->image->file=(FILE *) NULL; + else (void) ThrowMagickException(&image->exception,GetMagickModule(), ResourceLimitError,"Cloning image for object buffer failed", "`%s'",image->filename); + if (ping_width > 250000L || ping_height > 250000L) png_error(ping,"PNG Image dimensions are too large."); + mng_info->ob[object_id]->width=ping_width; mng_info->ob[object_id]->height=ping_height; mng_info->ob[object_id]->color_type=ping_color_type; @@ -2753,6 +2938,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, mng_info->ob[object_id]->compression_method= ping_compression_method; mng_info->ob[object_id]->filter_method=ping_filter_method; + if (png_get_valid(ping,ping_info,PNG_INFO_PLTE)) { int @@ -2789,6 +2975,7 @@ static Image *ReadOnePNGImage(MngInfo *mng_info, if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " exit ReadOnePNGImage()"); + return(image); /* end of reading one PNG image */ @@ -2861,12 +3048,15 @@ static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception) { if (previous->signature != MagickSignature) ThrowReaderException(CorruptImageError,"CorruptImage"); + (void) CloseBlob(previous); (void) DestroyImageList(previous); } + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), "exit ReadPNGImage() with error"); + return((Image *) NULL); } (void) CloseBlob(image); @@ -2875,11 +3065,13 @@ static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception) if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), "exit ReadPNGImage() with error."); + ThrowReaderException(CorruptImageError,"CorruptImage"); } if (LocaleCompare(image_info->magick,"PNG8") == 0) { (void) SetImageType(image,PaletteType); + if (image->matte != MagickFalse) { /* To do: Reduce to binary transparency */ @@ -2890,10 +3082,13 @@ static Image *ReadPNGImage(const ImageInfo *image_info,ExceptionInfo *exception) (void) SetImageType(image,TrueColorType); image->matte=MagickFalse; } + if (LocaleCompare(image_info->magick,"PNG32") == 0) (void) SetImageType(image,TrueColorMatteType); + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadPNGImage()"); + return(image); } @@ -3001,6 +3196,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, " enter ReadOneJNGImage()"); image=mng_info->image; + if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL) { /* @@ -3009,9 +3205,12 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " AcquireNextImage()"); + AcquireNextImage(image_info,image); + if (GetNextImageInList(image) == (Image *) NULL) return((Image *) NULL); + image=SyncNextImageInList(image); } mng_info->image=image; @@ -3039,8 +3238,10 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, */ status=SetImageProgress(image,LoadImagesTag,TellBlob(image), 2*GetBlobSize(image)); + if (status == MagickFalse) break; + type[0]='\0'; (void) ConcatenateMagickString(type,"errr",MaxTextExtent); length=ReadBlobMSBLong(image); @@ -3053,15 +3254,19 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, if (length > PNG_UINT_31_MAX || count == 0) ThrowReaderException(CorruptImageError,"CorruptImage"); + p=NULL; chunk=(unsigned char *) NULL; if (length) { chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk)); + if (chunk == (unsigned char *) NULL) ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); + for (i=0; i < (ssize_t) length; i++) chunk[i]=(unsigned char) ReadBlobByte(image); + p=chunk; } (void) ReadBlobMSBLong(image); /* read crc word */ @@ -3144,15 +3349,18 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); GetImageInfo(color_image_info); color_image=AcquireImage(color_image_info); + if (color_image == (Image *) NULL) ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Creating color_blob."); + (void) AcquireUniqueFilename(color_image->filename); status=OpenBlob(color_image_info,color_image,WriteBinaryBlobMode, exception); + if (status == MagickFalse) return((Image *) NULL); @@ -3160,24 +3368,31 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, { alpha_image_info=(ImageInfo *) AcquireMagickMemory(sizeof(ImageInfo)); + if (alpha_image_info == (ImageInfo *) NULL) ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); + GetImageInfo(alpha_image_info); alpha_image=AcquireImage(alpha_image_info); + if (alpha_image == (Image *) NULL) { alpha_image=DestroyImage(alpha_image); ThrowReaderException(ResourceLimitError, "MemoryAllocationFailed"); } + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Creating alpha_blob."); + (void) AcquireUniqueFilename(alpha_image->filename); status=OpenBlob(alpha_image_info,alpha_image,WriteBinaryBlobMode, exception); + if (status == MagickFalse) return((Image *) NULL); + if (jng_alpha_compression_method == 0) { unsigned char @@ -3186,8 +3401,10 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Writing IHDR chunk to alpha_blob."); + (void) WriteBlob(alpha_image,8,(const unsigned char *) "\211PNG\r\n\032\n"); + (void) WriteBlobMSBULong(alpha_image,13L); PNGType(data,mng_IHDR); LogPNGChunk((int) logging,mng_IHDR,13L); @@ -3244,8 +3461,10 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, (void) WriteBlobMSBULong(alpha_image, crc32(crc32(0,data,4),chunk,(uInt) length)); } + if (length) chunk=(unsigned char *) RelinquishMagickMemory(chunk); + continue; } @@ -3263,16 +3482,20 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, (void) WriteBlob(alpha_image,length,chunk); } + if (length) chunk=(unsigned char *) RelinquishMagickMemory(chunk); + continue; } if (memcmp(type,mng_JSEP,4) == 0) { read_JSEP=MagickTrue; + if (length) chunk=(unsigned char *) RelinquishMagickMemory(chunk); + continue; } @@ -3284,12 +3507,14 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, image->background_color.green=image->background_color.red; image->background_color.blue=image->background_color.red; } + if (length == 6) { image->background_color.red=ScaleCharToQuantum(p[1]); image->background_color.green=ScaleCharToQuantum(p[3]); image->background_color.blue=ScaleCharToQuantum(p[5]); } + chunk=(unsigned char *) RelinquishMagickMemory(chunk); continue; } @@ -3298,6 +3523,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, { if (length == 4) image->gamma=((float) mng_get_long(p))*0.00001; + chunk=(unsigned char *) RelinquishMagickMemory(chunk); continue; } @@ -3345,6 +3571,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, { image->page.x=mng_get_long(p); image->page.y=mng_get_long(&p[4]); + if ((int) p[8] != 0) { image->page.x/=10000; @@ -3353,6 +3580,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, } if (length) chunk=(unsigned char *) RelinquishMagickMemory(chunk); + continue; } @@ -3369,6 +3597,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, image->y_resolution=image->y_resolution/100.0f; } } + chunk=(unsigned char *) RelinquishMagickMemory(chunk); continue; } @@ -3379,6 +3608,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, /* To do. */ if (length) chunk=(unsigned char *) RelinquishMagickMemory(chunk); + continue; } #endif @@ -3388,6 +3618,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, if (memcmp(type,mng_IEND,4)) continue; + break; } @@ -3419,10 +3650,13 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Reading jng_image from color_blob."); + (void) FormatMagickString(color_image_info->filename,MaxTextExtent,"%s", color_image->filename); + color_image_info->ping=MagickFalse; /* To do: avoid this */ jng_image=ReadImage(color_image_info,exception); + if (jng_image == (Image *) NULL) return((Image *) NULL); @@ -3436,9 +3670,11 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Copying jng_image pixels to main image."); + image->rows=jng_height; image->columns=jng_width; length=image->columns*sizeof(PixelPacket); + for (y=0; y < (ssize_t) image->rows; y++) { s=GetVirtualPixels(jng_image,0,y,image->columns,1,&image->exception); @@ -3447,7 +3683,9 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, if (SyncAuthenticPixels(image,exception) == MagickFalse) break; } + jng_image=DestroyImage(jng_image); + if (image_info->ping == MagickFalse) { if (jng_color_type >= 12) @@ -3462,7 +3700,9 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, (void) WriteBlob(alpha_image,4,data); (void) WriteBlobMSBULong(alpha_image,crc32(0,data,4)); } + (void) CloseBlob(alpha_image); + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Reading opacity from alpha_blob."); @@ -3471,6 +3711,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, "%s",alpha_image->filename); jng_image=ReadImage(alpha_image_info,exception); + if (jng_image != (Image *) NULL) for (y=0; y < (ssize_t) image->rows; y++) { @@ -3480,6 +3721,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, if (image->matte != MagickFalse) for (x=(ssize_t) image->columns; x != 0; x--,q++,s++) q->opacity=(Quantum) QuantumRange-s->red; + else for (x=(ssize_t) image->columns; x != 0; x--,q++,s++) { @@ -3487,6 +3729,7 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, if (q->opacity != OpaqueOpacity) image->matte=MagickTrue; } + if (SyncAuthenticPixels(image,exception) == MagickFalse) break; } @@ -3506,26 +3749,32 @@ static Image *ReadOneJNGImage(MngInfo *mng_info, mng_info->mng_width=jng_width; mng_info->mng_height=jng_height; } + if (image->page.width == 0 && image->page.height == 0) - { - image->page.width=jng_width; - image->page.height=jng_height; - } + { + image->page.width=jng_width; + image->page.height=jng_height; + } + if (image->page.x == 0 && image->page.y == 0) - { - image->page.x=mng_info->x_off[mng_info->object_id]; - image->page.y=mng_info->y_off[mng_info->object_id]; - } + { + image->page.x=mng_info->x_off[mng_info->object_id]; + image->page.y=mng_info->y_off[mng_info->object_id]; + } + else - { - image->page.y=mng_info->y_off[mng_info->object_id]; - } + { + image->page.y=mng_info->y_off[mng_info->object_id]; + } + mng_info->image_found++; status=SetImageProgress(image,LoadImagesTag,2*TellBlob(image), 2*GetBlobSize(image)); + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " exit ReadOneJNGImage()"); + return(image); } @@ -3594,23 +3843,29 @@ static Image *ReadJNGImage(const ImageInfo *image_info,ExceptionInfo *exception) image=AcquireImage(image_info); mng_info=(MngInfo *) NULL; status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); + if (status == MagickFalse) return((Image *) NULL); + if (LocaleCompare(image_info->magick,"JNG") != 0) ThrowReaderException(CorruptImageError,"ImproperImageHeader"); + /* Verify JNG signature. */ count=(size_t) ReadBlob(image,8,(unsigned char *) magic_number); if (memcmp(magic_number,"\213JNG\r\n\032\n",8) != 0) ThrowReaderException(CorruptImageError,"ImproperImageHeader"); + /* Allocate a MngInfo structure. */ have_mng_structure=MagickFalse; mng_info=(MngInfo *) AcquireMagickMemory(sizeof(*mng_info)); + if (mng_info == (MngInfo *) NULL) ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); + /* Initialize members of the MngInfo structure. */ @@ -3621,6 +3876,7 @@ static Image *ReadJNGImage(const ImageInfo *image_info,ExceptionInfo *exception) previous=image; image=ReadOneJNGImage(mng_info,image_info,exception); MngInfoFreeStruct(mng_info,&have_mng_structure); + if (image == (Image *) NULL) { if (IsImageObject(previous) != MagickFalse) @@ -3628,9 +3884,11 @@ static Image *ReadJNGImage(const ImageInfo *image_info,ExceptionInfo *exception) (void) CloseBlob(previous); (void) DestroyImageList(previous); } + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), "exit ReadJNGImage() with error"); + return((Image *) NULL); } (void) CloseBlob(image); @@ -3639,10 +3897,13 @@ static Image *ReadJNGImage(const ImageInfo *image_info,ExceptionInfo *exception) if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), "exit ReadJNGImage() with error"); + ThrowReaderException(CorruptImageError,"CorruptImage"); } + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadJNGImage()"); + return(image); } #endif @@ -3748,21 +4009,6 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) default_fb.left=0; default_fb.right=0; - /* - Set image_info->type=OptimizeType (new in version 5.4.0) to get the - following optimizations: - - o 16-bit depth is reduced to 8 if all pixels contain samples whose - high byte and low byte are identical. - o Opaque matte channel is removed. - o If matte channel is present but only one transparent color is - present, RGB+tRNS is written instead of RGBA - o Grayscale images are reduced to 1, 2, or 4 bit depth if - this can be done without loss. - o Palette is sorted to remove unused entries and to put a - transparent color first, if PNG_SORT_PALETTE is also defined. - */ - /* Open image file. */ @@ -3775,8 +4021,10 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) image=AcquireImage(image_info); mng_info=(MngInfo *) NULL; status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); + if (status == MagickFalse) return((Image *) NULL); + first_mng_object=MagickFalse; skipping_loop=(-1); have_mng_structure=MagickFalse; @@ -3784,8 +4032,10 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) Allocate a MngInfo structure. */ mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo)); + if (mng_info == (MngInfo *) NULL) ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); + /* Initialize members of the MngInfo structure. */ @@ -3861,10 +4111,13 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) if (length > PNG_UINT_31_MAX) status=MagickFalse; + if (count == 0) ThrowReaderException(CorruptImageError,"CorruptImage"); + p=NULL; chunk=(unsigned char *) NULL; + if (length) { chunk=(unsigned char *) AcquireQuantumMemory(length,sizeof(*chunk)); @@ -3874,24 +4127,29 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) chunk[i]=(unsigned char) ReadBlobByte(image); p=chunk; } + (void) ReadBlobMSBLong(image); /* read crc word */ #if !defined(JNG_SUPPORTED) if (memcmp(type,mng_JHDR,4) == 0) { skip_to_iend=MagickTrue; + if (mng_info->jhdr_warning == 0) (void) ThrowMagickException(&image->exception,GetMagickModule(), CoderError,"JNGCompressNotSupported","`%s'",image->filename); + mng_info->jhdr_warning++; } #endif if (memcmp(type,mng_DHDR,4) == 0) { skip_to_iend=MagickTrue; + if (mng_info->dhdr_warning == 0) (void) ThrowMagickException(&image->exception,GetMagickModule(), CoderError,"DeltaPNGNotSupported","`%s'",image->filename); + mng_info->dhdr_warning++; } if (memcmp(type,mng_MEND,4) == 0) @@ -3900,19 +4158,25 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) { if (memcmp(type,mng_IEND,4) == 0) skip_to_iend=MagickFalse; + if (length) chunk=(unsigned char *) RelinquishMagickMemory(chunk); + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Skip to IEND."); + continue; } + if (memcmp(type,mng_MHDR,4) == 0) { mng_info->mng_width=(size_t) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]); + mng_info->mng_height=(size_t) ((p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]); + if (logging != MagickFalse) { (void) LogMagickEvent(CoderEvent,GetMagickModule(), @@ -3920,25 +4184,34 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " MNG height: %.20g",(double) mng_info->mng_height); } + p+=8; mng_info->ticks_per_second=(size_t) mng_get_long(p); + if (mng_info->ticks_per_second == 0) default_frame_delay=0; + else default_frame_delay=1UL*image->ticks_per_second/ mng_info->ticks_per_second; + frame_delay=default_frame_delay; simplicity=0; + if (length > 16) { p+=16; simplicity=(size_t) mng_get_long(p); } + mng_type=1; /* Full MNG */ + if ((simplicity != 0) && ((simplicity | 11) == 11)) mng_type=2; /* LC */ + if ((simplicity != 0) && ((simplicity | 9) == 9)) mng_type=3; /* VLC */ + #if defined(MNG_INSERT_LAYERS) if (mng_type != 3) insert_layers=MagickTrue; @@ -3949,8 +4222,10 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) Allocate next image structure. */ AcquireNextImage(image_info,image); + if (GetNextImageInList(image) == (Image *) NULL) return((Image *) NULL); + image=SyncNextImageInList(image); mng_info->image=image; } @@ -3958,16 +4233,20 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) if ((mng_info->mng_width > 65535L) || (mng_info->mng_height > 65535L)) ThrowReaderException(ImageError,"WidthOrHeightExceedsLimit"); + (void) FormatMagickString(page_geometry,MaxTextExtent, "%.20gx%.20g+0+0",(double) mng_info->mng_width,(double) mng_info->mng_height); + mng_info->frame.left=0; mng_info->frame.right=(ssize_t) mng_info->mng_width; mng_info->frame.top=0; mng_info->frame.bottom=(ssize_t) mng_info->mng_height; mng_info->clip=default_fb=previous_fb=mng_info->frame; + for (i=0; i < MNG_MAX_OBJECTS; i++) mng_info->object_clip[i]=mng_info->frame; + chunk=(unsigned char *) RelinquishMagickMemory(chunk); continue; } @@ -3980,24 +4259,31 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) if (length) repeat=p[0]; + if (repeat == 3) { final_delay=(png_uint_32) mng_get_long(&p[2]); mng_iterations=(png_uint_32) mng_get_long(&p[6]); + if (mng_iterations == PNG_UINT_31_MAX) mng_iterations=0; + image->iterations=mng_iterations; term_chunk_found=MagickTrue; } + if (logging != MagickFalse) { (void) LogMagickEvent(CoderEvent,GetMagickModule(), " repeat=%d",repeat); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " final_delay=%.20g",(double) final_delay); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " image->iterations=%.20g",(double) image->iterations); } + chunk=(unsigned char *) RelinquishMagickMemory(chunk); continue; } @@ -4007,11 +4293,14 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) (void) ThrowMagickException(&image->exception,GetMagickModule(), CoderError,"DEFI chunk found in MNG-VLC datastream","`%s'", image->filename); + object_id=(p[0] << 8) | p[1]; + if (mng_type == 2 && object_id != 0) (void) ThrowMagickException(&image->exception,GetMagickModule(), CoderError,"Nonzero object_id in MNG-LC datastream","`%s'", image->filename); + if (object_id > MNG_MAX_OBJECTS) { /* @@ -4022,6 +4311,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) CoderError,"object id too large","`%s'",image->filename); object_id=MNG_MAX_OBJECTS; } + if (mng_info->exists[object_id]) if (mng_info->frozen[object_id]) { @@ -4032,50 +4322,63 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) image->filename); continue; } + mng_info->exists[object_id]=MagickTrue; + if (length > 2) mng_info->invisible[object_id]=p[2]; + /* Extract object offset info. */ if (length > 11) { - mng_info->x_off[object_id]=(ssize_t) ((p[4] << 24) | (p[5] << 16) | - (p[6] << 8) | p[7]); - mng_info->y_off[object_id]=(ssize_t) ((p[8] << 24) | (p[9] << 16) | - (p[10] << 8) | p[11]); + mng_info->x_off[object_id]=(ssize_t) ((p[4] << 24) | + (p[5] << 16) | (p[6] << 8) | p[7]); + + mng_info->y_off[object_id]=(ssize_t) ((p[8] << 24) | + (p[9] << 16) | (p[10] << 8) | p[11]); + if (logging != MagickFalse) { (void) LogMagickEvent(CoderEvent,GetMagickModule(), " x_off[%d]: %.20g",object_id,(double) mng_info->x_off[object_id]); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " y_off[%d]: %.20g",object_id,(double) mng_info->y_off[object_id]); } } + /* Extract object clipping info. */ if (length > 27) mng_info->object_clip[object_id]=mng_read_box(mng_info->frame,0, &p[12]); + chunk=(unsigned char *) RelinquishMagickMemory(chunk); continue; } if (memcmp(type,mng_bKGD,4) == 0) { mng_info->have_global_bkgd=MagickFalse; + if (length > 5) { mng_info->mng_global_bkgd.red= ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1])); + mng_info->mng_global_bkgd.green= ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3])); + mng_info->mng_global_bkgd.blue= ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5])); + mng_info->have_global_bkgd=MagickTrue; } + chunk=(unsigned char *) RelinquishMagickMemory(chunk); continue; } @@ -4084,18 +4387,24 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) #if defined(MNG_INSERT_LAYERS) if (length > 6) mandatory_back=p[6]; + else mandatory_back=0; + if (mandatory_back && length > 5) { mng_background_color.red= ScaleShortToQuantum((unsigned short) ((p[0] << 8) | p[1])); + mng_background_color.green= ScaleShortToQuantum((unsigned short) ((p[2] << 8) | p[3])); + mng_background_color.blue= ScaleShortToQuantum((unsigned short) ((p[4] << 8) | p[5])); + mng_background_color.opacity=OpaqueOpacity; } + #ifdef MNG_OBJECT_BUFFERS if (length > 8) mng_background_object=(p[7] << 8) | p[8]; @@ -4114,12 +4423,14 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) if (mng_info->global_plte == (png_colorp) NULL) mng_info->global_plte=(png_colorp) AcquireQuantumMemory(256, sizeof(*mng_info->global_plte)); + for (i=0; i < (ssize_t) (length/3); i++) { mng_info->global_plte[i].red=p[3*i]; mng_info->global_plte[i].green=p[3*i+1]; mng_info->global_plte[i].blue=p[3*i+2]; } + mng_info->global_plte_length=(unsigned int) (length/3); } #ifdef MNG_LOOSE @@ -4129,11 +4440,13 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) mng_info->global_plte[i].green=i; mng_info->global_plte[i].blue=i; } + if (length) mng_info->global_plte_length=256; #endif else mng_info->global_plte_length=0; + chunk=(unsigned char *) RelinquishMagickMemory(chunk); continue; } @@ -4164,8 +4477,10 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) mng_info->global_gamma=((float) igamma)*0.00001; mng_info->have_global_gama=MagickTrue; } + else mng_info->have_global_gama=MagickFalse; + chunk=(unsigned char *) RelinquishMagickMemory(chunk); continue; } @@ -4230,17 +4545,21 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) (void) ThrowMagickException(&image->exception,GetMagickModule(), CoderError,"FRAM chunk found in MNG-VLC datastream","`%s'", image->filename); + if ((mng_info->framing_mode == 2) || (mng_info->framing_mode == 4)) image->delay=frame_delay; + frame_delay=default_frame_delay; frame_timeout=default_frame_timeout; fb=default_fb; if (length) if (p[0]) mng_info->framing_mode=p[0]; + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Framing_mode=%d",mng_info->framing_mode); + if (length > 6) { /* @@ -4265,13 +4584,18 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) { frame_delay=1UL*image->ticks_per_second* mng_get_long(p); + if (mng_info->ticks_per_second != 0) frame_delay/=mng_info->ticks_per_second; + else frame_delay=PNG_UINT_31_MAX; + if (change_delay == 2) default_frame_delay=frame_delay; + p+=4; + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Framing_delay=%.20g",(double) frame_delay); @@ -4280,13 +4604,18 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) { frame_timeout=1UL*image->ticks_per_second* mng_get_long(p); + if (mng_info->ticks_per_second != 0) frame_timeout/=mng_info->ticks_per_second; + else frame_timeout=PNG_UINT_31_MAX; + if (change_delay == 2) default_frame_timeout=frame_timeout; + p+=4; + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Framing_timeout=%.20g",(double) frame_timeout); @@ -4296,9 +4625,10 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) fb=mng_read_box(previous_fb,(char) p[0],&p[1]); p+=17; previous_fb=fb; + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), - " Frame_clipping: L=%.20g R=%.20g T=%.20g B=%.20g", + " Frame_clip: L=%.20g R=%.20g T=%.20g B=%.20g", (double) fb.left,(double) fb.right,(double) fb.top, (double) fb.bottom); if (change_clipping == 2) @@ -4308,8 +4638,10 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) } mng_info->clip=fb; mng_info->clip=mng_minimum_box(fb,mng_info->frame); + subframe_width=(size_t) (mng_info->clip.right -mng_info->clip.left); + subframe_height=(size_t) (mng_info->clip.bottom -mng_info->clip.top); /* @@ -4320,6 +4652,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " subframe_width=%.20g, subframe_height=%.20g",(double) subframe_width,(double) subframe_height); + if (insert_layers && (mng_info->framing_mode == 4) && (subframe_width) && (subframe_height)) { @@ -4337,15 +4670,19 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) } image=SyncNextImageInList(image); } + mng_info->image=image; + if (term_chunk_found) { image->start_loop=MagickTrue; image->iterations=mng_iterations; term_chunk_found=MagickFalse; } + else image->start_loop=MagickFalse; + image->columns=subframe_width; image->rows=subframe_height; image->page.width=subframe_width; @@ -4356,9 +4693,10 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) image->matte=MagickFalse; image->delay=0; (void) SetImageBackgroundColor(image); + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), - " Inserted background layer, L=%.20g, R=%.20g T=%.20g, B=%.20g", + " Insert backgd layer, L=%.20g, R=%.20g T=%.20g, B=%.20g", (double) mng_info->clip.left,(double) mng_info->clip.right, (double) mng_info->clip.top,(double) mng_info->clip.bottom); } @@ -4402,8 +4740,10 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) mng_info->ob[i]->frozen=MagickTrue; #endif } + if (length) chunk=(unsigned char *) RelinquishMagickMemory(chunk); + continue; } @@ -4417,6 +4757,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) for (i=1; i < MNG_MAX_OBJECTS; i++) MngInfoDiscardObject(mng_info,i); } + else { register ssize_t @@ -4428,8 +4769,10 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) MngInfoDiscardObject(mng_info,i); } } + if (length) chunk=(unsigned char *) RelinquishMagickMemory(chunk); + continue; } if (memcmp(type,mng_MOVE,4) == 0) @@ -4473,17 +4816,21 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) Record starting point. */ loop_iters=mng_get_long(&chunk[1]); + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " LOOP level %.20g has %.20g iterations ",(double) loop_level, (double) loop_iters); + if (loop_iters == 0) skipping_loop=loop_level; + else { mng_info->loop_jump[loop_level]=TellBlob(image); mng_info->loop_count[loop_level]=loop_iters; } + mng_info->loop_iteration[loop_level]=0; chunk=(unsigned char *) RelinquishMagickMemory(chunk); continue; @@ -4508,15 +4855,17 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) { mng_info->loop_count[loop_level]--; mng_info->loop_iteration[loop_level]++; + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), - " ENDL: LOOP level %.20g has %.20g remaining iterations ", + " ENDL: LOOP level %.20g has %.20g remaining iters ", (double) loop_level,(double) mng_info->loop_count[loop_level]); if (mng_info->loop_count[loop_level] != 0) { offset=SeekBlob(image,mng_info->loop_jump[loop_level], SEEK_SET); + if (offset < 0) ThrowReaderException(CorruptImageError, "ImproperImageHeader"); @@ -4565,10 +4914,13 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) if (length > 1) magn_first=(p[0] << 8) | p[1]; + else magn_first=0; + if (length > 3) magn_last=(p[2] << 8) | p[3]; + else magn_last=magn_first; #ifndef MNG_OBJECT_BUFFERS @@ -4866,13 +5218,16 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) } image=SyncNextImageInList(image); } + mng_info->image=image; + if (term_chunk_found) { image->start_loop=MagickTrue; image->iterations=mng_iterations; term_chunk_found=MagickFalse; } + else image->start_loop=MagickFalse; image->delay=0; @@ -4885,9 +5240,10 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) image->background_color=mng_background_color; image->matte=MagickFalse; (void) SetImageBackgroundColor(image); + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), - " Inserted background layer, L=%.20g, R=%.20g T=%.20g, B=%.20g", + " Insert background layer, L=%.20g, R=%.20g T=%.20g, B=%.20g", (double) mng_info->clip.left,(double) mng_info->clip.right, (double) mng_info->clip.top,(double) mng_info->clip.bottom); } @@ -4910,22 +5266,28 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) mng_info->image=image; status=SetImageProgress(image,LoadImagesTag,TellBlob(image), GetBlobSize(image)); + if (status == MagickFalse) break; + if (term_chunk_found) { image->start_loop=MagickTrue; term_chunk_found=MagickFalse; } + else image->start_loop=MagickFalse; + if (mng_info->framing_mode == 1 || mng_info->framing_mode == 3) { image->delay=frame_delay; frame_delay=default_frame_delay; } + else image->delay=0; + image->page.width=mng_info->mng_width; image->page.height=mng_info->mng_height; image->page.x=mng_info->x_off[object_id]; @@ -4965,6 +5327,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) MngInfoFreeStruct(mng_info,&have_mng_structure); return((Image *) NULL); } + if (image->columns == 0 || image->rows == 0) { (void) CloseBlob(image); @@ -4972,6 +5335,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) MngInfoFreeStruct(mng_info,&have_mng_structure); return((Image *) NULL); } + mng_info->image=image; if (mng_type) @@ -5550,6 +5914,7 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " No images found. Inserting a background layer."); + if (GetAuthenticPixelQueue(image) != (PixelPacket *) NULL) { /* @@ -5575,14 +5940,18 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) image->page.y=0; image->background_color=mng_background_color; image->matte=MagickFalse; + if (image_info->ping == MagickFalse) (void) SetImageBackgroundColor(image); + mng_info->image_found++; } #endif image->iterations=mng_iterations; + if (mng_iterations == 1) image->start_loop=MagickTrue; + while (GetPreviousImageInList(image) != (Image *) NULL) { image_count++; @@ -5595,7 +5964,9 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) "`%s'",image_info->filename); return((Image *) NULL); } + image=GetPreviousImageInList(image); + if (GetNextImageInList(image) == (Image *) NULL) { if (logging != MagickFalse) @@ -5632,23 +6003,30 @@ static Image *ReadMNGImage(const ImageInfo *image_info,ExceptionInfo *exception) if (mng_info->ticks_per_second) final_delay=1UL*MagickMax(image->ticks_per_second,1L)* final_delay/mng_info->ticks_per_second; + else image->start_loop=MagickTrue; + /* Find final nonzero image delay */ final_image_delay=0; + while (GetNextImageInList(image) != (Image *) NULL) { if (image->delay) final_image_delay=image->delay; image=GetNextImageInList(image); } + if (final_delay < final_image_delay) final_delay=final_image_delay; + image->delay=final_delay; + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " image->delay=%.20g, final_delay=%.20g",(double) image->delay, (double) final_delay); + if (logging != MagickFalse) { int @@ -6050,9 +6428,10 @@ png_write_raw_profile(const ImageInfo *image_info,png_struct *ping, if (image_info->verbose) { - (void) printf("writing raw profile: type=%s, length=%.20g\n", - (char *) profile_type, (double) length); + (void) printf("writing raw profile: type=%s, length=%.20g\n", + (char *) profile_type, (double) length); } + text=(png_textp) png_malloc(ping,(png_uint_32) sizeof(png_text)); description_length=(png_uint_32) strlen((const char *) profile_description); allocated_length=(png_uint_32) (length*2 + (length >> 5) + 20 @@ -6308,10 +6687,13 @@ static MagickBooleanType OptimizePNGColormap(Image *image, IndexPacket (void) LogMagickEvent(CoderEvent,GetMagickModule(), " new_number_colors in OptimizePNGColormap=%d", (int) new_number_colors); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " In OptimizePNGColormap:"); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " i plte_map (red,green,blue,opacity)"); + for (i=0; i < image->colors; i++) { (void) LogMagickEvent(CoderEvent,GetMagickModule(), @@ -6341,14 +6723,14 @@ static MagickBooleanType OptimizePNGColormap(Image *image, IndexPacket Eliminate unused colormap entries. */ for (i=0; i < number_colors; i++) - ping_plte_map[i]=i; + ping_plte_map[i]=i; k=0; for (i=0; i < number_colors; i++) { if (marker[i]) { - ping_plte_map[i]=(IndexPacket) k; + ping_plte_map[i]=(IndexPacket) k; for (j=i+1; j < number_colors; j++) { if ((image->colormap[i].opacity == image->colormap[j].opacity) && @@ -6362,7 +6744,7 @@ static MagickBooleanType OptimizePNGColormap(Image *image, IndexPacket } } - if (have_transparency && (image->colormap[0].opacity != + if (have_transparency && (image->colormap[0].opacity != (Quantum) TransparentOpacity)) { /* @@ -6446,7 +6828,7 @@ static MagickBooleanType CompressColormapTransFirst(Image *image) colormap[ping_plte_map[i]] = image->colormap[i]; if (ping_plte_map[i] != i) - remap_needed = MagickTrue; + remap_needed = MagickTrue; if (ping_plte_map[i] >= ping_number_colors) ping_number_colors=ping_plte_map[i]+1; @@ -6464,22 +6846,28 @@ static MagickBooleanType CompressColormapTransFirst(Image *image) for (y=0; y < (ssize_t) image->rows; y++) { q=GetAuthenticPixels(image,0,y,image->columns,1,exception); + if (q == (PixelPacket *) NULL) break; + pixels=GetAuthenticIndexQueue(image); + for (x=0; x < (ssize_t) image->columns; x++) { j=(int) pixels[x]; pixels[x]=(IndexPacket) ping_plte_map[j]; } + if (SyncAuthenticPixels(image,exception) == MagickFalse) break; } (void) LogMagickEvent(CoderEvent,GetMagickModule(), " After OptimizePNGColormap:"); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " i plte_map (red,green,blue,opacity)"); + for (i=0; i < image->colors; i++) { (void) LogMagickEvent(CoderEvent,GetMagickModule(), @@ -6589,7 +6977,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, matte; volatile int - ping_bit_depth, + ping_bit_depth, ping_color_type, ping_interlace_method, ping_compression_method, @@ -6622,7 +7010,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, #endif /* Initialize some stuff */ - ping_bit_depth=0, + ping_bit_depth=0, ping_color_type=0, ping_interlace_method=0, ping_compression_method=0, @@ -6657,7 +7045,8 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, if (image->colorspace != RGBColorspace) (void) TransformImageColorspace(image,RGBColorspace); - mng_info->IsPalette=image->storage_class == PseudoClass && + + mng_info->IsPalette=image->storage_class == PseudoClass && image_colors <= 256 && !IsOpaqueImage(image,&image->exception); /* @@ -6667,18 +7056,23 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, ping=png_create_write_struct_2(PNG_LIBPNG_VER_STRING,image, PNGErrorHandler,PNGWarningHandler,(void *) NULL, (png_malloc_ptr) png_IM_malloc,(png_free_ptr) png_IM_free); + #else ping=png_create_write_struct(PNG_LIBPNG_VER_STRING,image, PNGErrorHandler,PNGWarningHandler); + #endif if (ping == (png_struct *) NULL) ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); + ping_info=png_create_info_struct(ping); + if (ping_info == (png_info *) NULL) { png_destroy_write_struct(&ping,(png_info **) NULL); ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); } + png_set_write_fn(ping,image,png_put_data,png_flush_data); png_pixels=(unsigned char *) NULL; @@ -6714,15 +7108,20 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, ping_height=(png_uint_32) image->rows; if (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32) image_depth=8; + if (mng_info->write_png_depth != 0) image_depth=mng_info->write_png_depth; + /* Adjust requested depth to next higher valid depth if necessary */ if (image_depth > 8) image_depth=16; + if ((image_depth > 4) && (image_depth < 8)) image_depth=8; + if (image_depth == 3) image_depth=4; + if (logging != MagickFalse) { (void) LogMagickEvent(CoderEvent,GetMagickModule(), @@ -6743,7 +7142,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, if ((image->x_resolution != 0) && (image->y_resolution != 0) && (!mng_info->write_mng || !mng_info->equal_physs)) { - if (logging != MagickFalse) + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Setting up pHYs chunk"); @@ -6780,225 +7179,262 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, mask=0xffff; if (ping_bit_depth == 8) mask=0x00ff; + if (ping_bit_depth == 4) mask=0x000f; + if (ping_bit_depth == 2) mask=0x0003; + if (ping_bit_depth == 1) mask=0x0001; + ping_background.red=(png_uint_16) (ScaleQuantumToShort(image->background_color.red) & mask); + ping_background.green=(png_uint_16) (ScaleQuantumToShort(image->background_color.green) & mask); + ping_background.blue=(png_uint_16) (ScaleQuantumToShort(image->background_color.blue) & mask); - } + } + + if (logging != MagickFalse) + (void) LogMagickEvent(CoderEvent,GetMagickModule(), + " Setting up bKGd chunk"); + + ping_have_bKGD = MagickTrue; - if (logging != MagickFalse) - (void) LogMagickEvent(CoderEvent,GetMagickModule(), - " Setting up bKGd chunk"); - ping_have_bKGD = MagickTrue; /* Select the color type. */ matte=image_matte; old_bit_depth=0; + if ((mng_info->write_png_colortype-1) == PNG_COLOR_TYPE_PALETTE) mng_info->write_png8=MagickTrue; + if (mng_info->write_png8) { - ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE; + QuantizeInfo + quantize_info; + + /* TO DO: make this a function cause it's used twice, except + for reducing the sample depth from 8. */ + + ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE; ping_bit_depth=8; image_depth=ping_bit_depth; - { - /* TO DO: make this a function cause it's used twice, except - for reducing the sample depth from 8. */ - - QuantizeInfo - quantize_info; + number_colors=image_colors; + if ((image->storage_class == DirectClass) || (number_colors > 256)) + { + GetQuantizeInfo(&quantize_info); + quantize_info.dither=IsPaletteImage(image,&image->exception) == + MagickFalse ? MagickTrue : MagickFalse; + quantize_info.number_colors= (matte != MagickFalse ? 255UL : + 256UL); + (void) QuantizeImage(&quantize_info,image); number_colors=image_colors; - if ((image->storage_class == DirectClass) || (number_colors > 256)) - { - GetQuantizeInfo(&quantize_info); - quantize_info.dither=IsPaletteImage(image,&image->exception) == - MagickFalse ? MagickTrue : MagickFalse; - quantize_info.number_colors= (matte != MagickFalse ? 255UL : - 256UL); - (void) QuantizeImage(&quantize_info,image); - number_colors=image_colors; - (void) SyncImage(image); - if (logging != MagickFalse) - (void) LogMagickEvent(CoderEvent,GetMagickModule(), - " Colors quantized to %.20g",(double) number_colors); - } - if (matte) - ping_have_tRNS=MagickFalse; - /* - Set image palette. - */ - ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE; - if (CompressColormapTransFirst(image) == MagickFalse) - ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); - number_colors=image->colors; - image_colors=number_colors; + (void) SyncImage(image); if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), - " Setting up PLTE chunk with %d colors (%d)", - (int) number_colors, (int) image_colors); - for (i=0; i < (ssize_t) number_colors; i++) - { - palette[i].red=ScaleQuantumToChar(image->colormap[i].red); - palette[i].green=ScaleQuantumToChar(image->colormap[i].green); - palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue); - if (logging != MagickFalse) - (void) LogMagickEvent(CoderEvent,GetMagickModule(), + " Colors quantized to %.20g",(double) number_colors); + } + + if (matte) + ping_have_tRNS=MagickFalse; + + /* + Set image palette. + */ + ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE; + + if (CompressColormapTransFirst(image) == MagickFalse) + ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); + + number_colors=image->colors; + image_colors=number_colors; + + if (logging != MagickFalse) + (void) LogMagickEvent(CoderEvent,GetMagickModule(), + " Setting up PLTE chunk with %d colors (%d)", + (int) number_colors, (int) image_colors); + + for (i=0; i < (ssize_t) number_colors; i++) + { + palette[i].red=ScaleQuantumToChar(image->colormap[i].red); + palette[i].green=ScaleQuantumToChar(image->colormap[i].green); + palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue); + if (logging != MagickFalse) + (void) LogMagickEvent(CoderEvent,GetMagickModule(), #if MAGICKCORE_QUANTUM_DEPTH == 8 - " %3ld (%3d,%3d,%3d)", + " %3ld (%3d,%3d,%3d)", #else - " %5ld (%5d,%5d,%5d)", + " %5ld (%5d,%5d,%5d)", #endif - (long) i,palette[i].red,palette[i].green,palette[i].blue); + (long) i,palette[i].red,palette[i].green,palette[i].blue); - } - if (matte) - { - number_colors++; - palette[i].red=ScaleQuantumToChar((Quantum) QuantumRange); - palette[i].green=ScaleQuantumToChar((Quantum) QuantumRange); - palette[i].blue=ScaleQuantumToChar((Quantum) QuantumRange); - } - ping_have_PLTE=MagickTrue; - image_depth=ping_bit_depth; - ping_num_trans=0; - if (matte) - { - ExceptionInfo - *exception; + } + if (matte) + { + number_colors++; + palette[i].red=ScaleQuantumToChar((Quantum) QuantumRange); + palette[i].green=ScaleQuantumToChar((Quantum) QuantumRange); + palette[i].blue=ScaleQuantumToChar((Quantum) QuantumRange); + } + ping_have_PLTE=MagickTrue; + image_depth=ping_bit_depth; + ping_num_trans=0; + if (matte) + { + ExceptionInfo + *exception; - int - trans_alpha[256]; + int + trans_alpha[256]; - /* - Identify which colormap entry is transparent. - */ - assert(number_colors <= 256); - for (i=0; i < (ssize_t) number_colors; i++) - trans_alpha[i]=255; - exception=(&image->exception); - for (y=0; y < (ssize_t) image->rows; y++) - { - register const PixelPacket - *p; + /* + Identify which colormap entry is transparent. + */ + assert(number_colors <= 256); - p=GetVirtualPixels(image,0,y,image->columns,1,exception); - if (p == (PixelPacket *) NULL) - break; - for (x=0; x < (ssize_t) image->columns; x++) - { - if (p->opacity != OpaqueOpacity) - { - trans_alpha[(ssize_t) number_colors-1]=(png_byte) (255- - ScaleQuantumToChar(GetOpacityPixelComponent(p))); - } - p++; - } - } - for (i=0; i < (ssize_t) number_colors; i++) - if (trans_alpha[i] != 255) - ping_num_trans=(unsigned short) (i+1); - - if (ping_num_trans == 0) - ping_have_tRNS=MagickFalse; - if (ping_have_tRNS==MagickFalse) - ping_num_trans=0; - if (ping_num_trans != 0) + for (i=0; i < (ssize_t) number_colors; i++) + trans_alpha[i]=255; + + exception=(&image->exception); + + for (y=0; y < (ssize_t) image->rows; y++) + { + register const PixelPacket + *p; + + p=GetVirtualPixels(image,0,y,image->columns,1,exception); + + if (p == (PixelPacket *) NULL) + break; + + for (x=0; x < (ssize_t) image->columns; x++) + { + if (p->opacity != OpaqueOpacity) { - for (i=0; i<256; i++) - ping_trans_alpha[i]=(png_byte) trans_alpha[i]; + trans_alpha[(ssize_t) number_colors-1]=(png_byte) (255- + ScaleQuantumToChar(GetOpacityPixelComponent(p))); } + p++; + } + } + for (i=0; i < (ssize_t) number_colors; i++) + if (trans_alpha[i] != 255) + ping_num_trans=(unsigned short) (i+1); + + if (ping_num_trans == 0) + ping_have_tRNS=MagickFalse; + + if (ping_have_tRNS==MagickFalse) + ping_num_trans=0; - ping_have_tRNS=MagickTrue; + if (ping_num_trans != 0) + { + for (i=0; i<256; i++) + ping_trans_alpha[i]=(png_byte) trans_alpha[i]; } - /* - 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; + + ping_have_tRNS=MagickTrue; } + + /* + 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 (image_matte != MagickFalse) { /* TO DO: reduce to binary transparency */ } } /* end of write_png8 */ + else if (mng_info->write_png24) { image_matte=MagickFalse; ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB; } + else if (mng_info->write_png32) { image_matte=MagickTrue; ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA; } + else { image_depth=ping_bit_depth; + if (mng_info->write_png_colortype) { ping_color_type=(png_byte) mng_info->write_png_colortype-1; image_matte=MagickFalse; + if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA || ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) image_matte=MagickTrue; } + else { if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), "Selecting PNG colortype"); + ping_color_type=(png_byte) ((matte == MagickTrue)? PNG_COLOR_TYPE_RGB_ALPHA:PNG_COLOR_TYPE_RGB); + if(image_info->type == TrueColorType) { ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB; image_matte=MagickFalse; } + if(image_info->type == TrueColorMatteType) { ping_color_type=(png_byte) PNG_COLOR_TYPE_RGB_ALPHA; image_matte=MagickTrue; } - if ((image_info->type == UndefinedType || - image_info->type == OptimizeType || + + if ((image_info->type == UndefinedType || + image_info->type == OptimizeType || image_info->type == GrayscaleType) && image_matte == MagickFalse && ImageIsGray(image)) { ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY; image_matte=MagickFalse; } + if ((image_info->type == UndefinedType || - image_info->type == OptimizeType || + image_info->type == OptimizeType || image_info->type == GrayscaleMatteType) && image_matte == MagickTrue && ImageIsGray(image)) { ping_color_type=(png_byte) PNG_COLOR_TYPE_GRAY_ALPHA; image_matte=MagickTrue; - } + } } + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), "Selected PNG colortype=%d",ping_color_type); if (ping_bit_depth < 8) - { - if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA || - ping_color_type == PNG_COLOR_TYPE_RGB || - ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) - ping_bit_depth=8; - } + { + if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA || + ping_color_type == PNG_COLOR_TYPE_RGB || + ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) + ping_bit_depth=8; + } if (ping_color_type == PNG_COLOR_TYPE_GRAY) { @@ -7007,6 +7443,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, if (ImageIsMonochrome(image)) { ping_bit_depth=1; + if (ping_bit_depth < (int)mng_info->write_png_depth) ping_bit_depth = mng_info->write_png_depth; } @@ -7019,7 +7456,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, if (image->colors == 0) { - /* DO SOMETHING */ + /* DO SOMETHING */ (void) ThrowMagickException(&image->exception, GetMagickModule(),CoderError, "image has 0 colors", "`%s'",""); @@ -7028,6 +7465,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " SyncImage.2."); + while ((int) (one << ping_bit_depth) < (ssize_t) image_colors) ping_bit_depth <<= 1; @@ -7035,17 +7473,21 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, { (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Number of colors: %.20g",(double) image_colors); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Tentative PNG bit depth: %d",ping_bit_depth); } + if (mng_info->write_png_depth) { old_bit_depth=ping_bit_depth; if (ping_bit_depth < (int)mng_info->write_png_depth) { ping_bit_depth = mng_info->write_png_depth; + if (ping_bit_depth > 8) ping_bit_depth = 8; + if (ping_bit_depth != (int) old_bit_depth) { if (logging != MagickFalse) @@ -7062,10 +7504,13 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, { (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Tentative PNG color type: %.20g",(double) ping_color_type); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " image_info->type: %.20g",(double) image_info->type); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " image_depth: %.20g",(double) image_depth); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " ping_bit_depth: %.20g",(double) ping_bit_depth); } @@ -7082,6 +7527,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception); if (p == (const PixelPacket *) NULL) break; + for (x=(ssize_t) image->columns-1; x >= 0; x--) { if (IsGray(p) == MagickFalse) @@ -7098,17 +7544,21 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, for (y=0; y < (ssize_t) image->rows; y++) { p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception); + if (p == (const PixelPacket *) NULL) break; + for (x=(ssize_t) image->columns-1; x >= 0; x--) { if (p->opacity != OpaqueOpacity) break; p++; } + if (x != 0) break; } + if ((y == (ssize_t) image->rows) && (x == (ssize_t) image->columns)) { /* @@ -7117,32 +7567,44 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, image_matte=MagickFalse; ping_color_type&=0x03; } + else { unsigned int mask; mask=0xffff; + if (ping_bit_depth == 8) mask=0x00ff; + if (ping_bit_depth == 4) mask=0x000f; + if (ping_bit_depth == 2) mask=0x0003; + if (ping_bit_depth == 1) mask=0x0001; + ping_trans_color.red=(png_uint_16) (ScaleQuantumToShort(GetRedPixelComponent(p)) & mask); + ping_trans_color.green=(png_uint_16) (ScaleQuantumToShort(GetGreenPixelComponent(p)) & mask); + ping_trans_color.blue=(png_uint_16) (ScaleQuantumToShort(GetBluePixelComponent(p)) & mask); + ping_trans_color.gray=(png_uint_16) (ScaleQuantumToShort(PixelIntensityToQuantum(p)) & mask); + ping_trans_color.index=(png_byte) (ScaleQuantumToChar((Quantum) (GetAlphaPixelComponent(p)))); + ping_have_tRNS=MagickTrue; } + if (ping_have_tRNS != MagickFalse) { /* @@ -7154,23 +7616,27 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, p=GetVirtualPixels(image,0,y,image->columns,1, &image->exception); x=0; + if (p == (const PixelPacket *) NULL) break; + for (x=(ssize_t) image->columns-1; x >= 0; x--) { if (p->opacity != OpaqueOpacity) { if (IsPNGColorEqual(ping_trans_color,*p) == 0) - { - break; /* Can't use RGB + tRNS for multiple - transparent colors. */ - } + { + break; /* Can't use RGB + tRNS for multiple + transparent colors. */ + } + if (p->opacity != (Quantum) TransparentOpacity) - { - break; /* Can't use RGB + tRNS for - semitransparency. */ - } + { + break; /* Can't use RGB + tRNS for + semitransparency. */ + } } + else { if (IsPNGColorEqual(ping_trans_color,*p)) @@ -7189,6 +7655,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, if (ping_have_tRNS != MagickFalse) { ping_color_type &= 0x03; /* changes 4 or 6 to 0 or 2 */ + if (image_depth == 8) { ping_trans_color.red&=0xff; @@ -7199,27 +7666,35 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, } } matte=image_matte; + if (ping_have_tRNS != MagickFalse) image_matte=MagickFalse; + if ((mng_info->IsPalette) && mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE && ImageIsGray(image) && (!image_matte || image_depth >= 8)) { size_t one=1; + if (image_matte != MagickFalse) ping_color_type=PNG_COLOR_TYPE_GRAY_ALPHA; + else { ping_color_type=PNG_COLOR_TYPE_GRAY; if (save_image_depth == 16 && image_depth == 8) ping_trans_color.gray*=0x0101; } + if (image_depth > MAGICKCORE_QUANTUM_DEPTH) image_depth=MAGICKCORE_QUANTUM_DEPTH; + if (image_colors == 0 || image_colors-1 > MaxColormapSize) image_colors=one << image_depth; + if (image_depth > 8) ping_bit_depth=16; + else { ping_bit_depth=8; @@ -7228,13 +7703,14 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, if(!mng_info->write_png_depth) { ping_bit_depth=1; + while ((int) (one << ping_bit_depth) < (ssize_t) image_colors) ping_bit_depth <<= 1; } } - else if (ping_color_type == - PNG_COLOR_TYPE_GRAY && image_colors < 17 && + else if (ping_color_type == + PNG_COLOR_TYPE_GRAY && image_colors < 17 && mng_info->IsPalette) { @@ -7253,22 +7729,28 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, 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; + 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; } } image_depth=ping_bit_depth; } + else + if (mng_info->IsPalette) { number_colors=image_colors; @@ -7279,13 +7761,16 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, Set image palette. */ ping_color_type=(png_byte) PNG_COLOR_TYPE_PALETTE; + if (mng_info->have_write_global_plte && !matte) { png_set_PLTE(ping,ping_info,NULL,0); + if (logging) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Setting up empty PLTE chunk"); } + else { if (CompressColormapTransFirst(image) == MagickFalse) @@ -7293,18 +7778,22 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, "MemoryAllocationFailed"); number_colors=image->colors; image_colors=number_colors; + for (i=0; i < (ssize_t) number_colors; i++) { palette[i].red=ScaleQuantumToChar(image->colormap[i].red); palette[i].green=ScaleQuantumToChar(image->colormap[i].green); palette[i].blue=ScaleQuantumToChar(image->colormap[i].blue); } + if (logging) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Setting up PLTE chunk with %d colors", (int) number_colors); + ping_have_PLTE=MagickTrue; } + /* color_type is PNG_COLOR_TYPE_PALETTE */ if (!mng_info->write_png_depth) { @@ -7313,105 +7802,126 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, ping_bit_depth=1; one=1; + while ((one << ping_bit_depth) < number_colors) ping_bit_depth <<= 1; } + ping_num_trans=0; + if (matte) - { - ExceptionInfo - *exception; + { + ExceptionInfo + *exception; - register const PixelPacket - *p; + register const PixelPacket + *p; - int - trans[256]; + int + trans[256]; - register const IndexPacket - *packet_indexes; + register const IndexPacket + *packet_indexes; + + /* + Identify which colormap entry is transparent. + */ + assert(number_colors <= 256); - /* - Identify which colormap entry is transparent. - */ - assert(number_colors <= 256); - for (i=0; i < (ssize_t) number_colors; i++) - trans[i]=256; - exception=(&image->exception); - for (y=0; y < (ssize_t) image->rows; y++) - { - p=GetVirtualPixels(image,0,y,image->columns,1,exception); - if (p == (const PixelPacket *) NULL) - break; - packet_indexes=GetVirtualIndexQueue(image); - for (x=0; x < (ssize_t) image->columns; x++) - { - if (p->opacity != OpaqueOpacity) - { - IndexPacket - packet_index; - - packet_index=packet_indexes[x]; - if((size_t) packet_index >= number_colors) - (void) LogMagickEvent(CoderEvent, GetMagickModule(), - "packet_index=%d, number_colors=%d", - (int) packet_index, (int) number_colors); - assert((size_t) packet_index < number_colors); - if (trans[(ssize_t) packet_index] != 256) - { - if (trans[(ssize_t) packet_index] != (png_byte) (255- - ScaleQuantumToChar(GetOpacityPixelComponent(p)))) - { - ping_color_type=(png_byte) - PNG_COLOR_TYPE_RGB_ALPHA; - break; - } - } - trans[(ssize_t) packet_index]=(png_byte) (255- - ScaleQuantumToChar(GetOpacityPixelComponent(p))); - } - p++; - } - if ((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) - { - ping_num_trans=0; - ping_have_tRNS=MagickFalse; - ping_have_PLTE=MagickFalse; - mng_info->IsPalette=MagickFalse; - (void) SyncImage(image); - if (logging) - (void) LogMagickEvent(CoderEvent, GetMagickModule(), - " Cannot write image as indexed PNG, writing RGBA."); - break; - } - } - if (ping_have_tRNS != MagickFalse) - { for (i=0; i < (ssize_t) number_colors; i++) + trans[i]=256; + + exception=(&image->exception); + + for (y=0; y < (ssize_t) image->rows; y++) { - if (trans[i] == 256) - trans[i]=255; - if (trans[i] != 255) - ping_num_trans=(unsigned short) (i+1); + p=GetVirtualPixels(image,0,y,image->columns,1,exception); + + if (p == (const PixelPacket *) NULL) + break; + + packet_indexes=GetVirtualIndexQueue(image); + + for (x=0; x < (ssize_t) image->columns; x++) + { + if (p->opacity != OpaqueOpacity) + { + IndexPacket + packet_index; + + packet_index=packet_indexes[x]; + + if((size_t) packet_index >= number_colors) + (void) LogMagickEvent(CoderEvent, GetMagickModule(), + "packet_index=%d, number_colors=%d", + (int) packet_index, (int) number_colors); + + assert((size_t) packet_index < number_colors); + + if (trans[(ssize_t) packet_index] != 256) + { + if (trans[(ssize_t) packet_index] != (png_byte) (255- + ScaleQuantumToChar(GetOpacityPixelComponent(p)))) + { + ping_color_type=(png_byte) + PNG_COLOR_TYPE_RGB_ALPHA; + break; + } + } + + trans[(ssize_t) packet_index]=(png_byte) (255- + ScaleQuantumToChar(GetOpacityPixelComponent(p))); + } + p++; + } + + if ((int) ping_color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + ping_num_trans=0; + ping_have_tRNS=MagickFalse; + ping_have_PLTE=MagickFalse; + mng_info->IsPalette=MagickFalse; + (void) SyncImage(image); + + if (logging) + (void) LogMagickEvent(CoderEvent, GetMagickModule(), + " Cannot write image as indexed PNG, writing RGBA."); + break; + } } - } - if (ping_num_trans == 0) - ping_have_tRNS=MagickFalse; - if (ping_have_tRNS == MagickFalse) - ping_num_trans=0; - if (ping_num_trans != 0) + + if (ping_have_tRNS != MagickFalse) { for (i=0; i < (ssize_t) number_colors; i++) - ping_trans_alpha[i]=(png_byte) trans[i]; + { + if (trans[i] == 256) + trans[i]=255; + + if (trans[i] != 255) + ping_num_trans=(unsigned short) (i+1); + } } - } + if (ping_num_trans == 0) + ping_have_tRNS=MagickFalse; + + if (ping_have_tRNS == MagickFalse) + ping_num_trans=0; + + if (ping_num_trans != 0) + { + for (i=0; i < (ssize_t) number_colors; i++) + ping_trans_alpha[i]=(png_byte) trans[i]; + } + } } } + else { if (image_depth < 8) image_depth=8; + if ((save_image_depth == 16) && (image_depth == 8)) { ping_trans_color.red*=0x0101; @@ -7463,23 +7973,23 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, ping_background.index=(png_byte) i; if (logging) - { - (void) LogMagickEvent(CoderEvent,GetMagickModule(), - " Setting up bKGD chunk with index=%d",(int) i); - } + { + (void) LogMagickEvent(CoderEvent,GetMagickModule(), + " Setting up bKGD chunk with index=%d",(int) i); + } if (i < number_colors) - { - ping_have_bKGD = MagickTrue; - if (logging) { - (void) LogMagickEvent(CoderEvent,GetMagickModule(), - " background =(%d,%d,%d)", - (int) ping_background.red, - (int) ping_background.green, - (int) ping_background.blue); + ping_have_bKGD = MagickTrue; + if (logging) + { + (void) LogMagickEvent(CoderEvent,GetMagickModule(), + " background =(%d,%d,%d)", + (int) ping_background.red, + (int) ping_background.green, + (int) ping_background.blue); + } } - } else ping_have_bKGD = MagickFalse; @@ -7492,36 +8002,48 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, Initialize compression level and filtering. */ if (logging != MagickFalse) - (void) LogMagickEvent(CoderEvent,GetMagickModule(), - " Setting up deflate compression"); - if (logging != MagickFalse) - (void) LogMagickEvent(CoderEvent,GetMagickModule(), - " Compression buffer size: 32768"); + { + (void) LogMagickEvent(CoderEvent,GetMagickModule(), + " Setting up deflate compression"); + + (void) LogMagickEvent(CoderEvent,GetMagickModule(), + " Compression buffer size: 32768"); + } + png_set_compression_buffer_size(ping,32768L); + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Compression mem level: 9"); + png_set_compression_mem_level(ping, 9); + quality=image->quality == UndefinedCompressionQuality ? 75UL : image->quality; + if (quality > 9) { int level; level=(int) MagickMin((ssize_t) quality/10,9); + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Compression level: %d",level); + png_set_compression_level(ping,level); } + else { if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Compression strategy: Z_HUFFMAN_ONLY"); + png_set_compression_strategy(ping, Z_HUFFMAN_ONLY); } + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Setting up filtering"); @@ -7533,8 +8055,10 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Filter_type: PNG_INTRAPIXEL_DIFFERENCING"); + ping_filter_method=PNG_INTRAPIXEL_DIFFERENCING; } + else if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), @@ -7546,16 +8070,20 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, if ((quality % 10) > 5) base_filter=PNG_ALL_FILTERS; + else if ((quality % 10) != 5) base_filter=(int) quality % 10; + else if (((int) ping_color_type == PNG_COLOR_TYPE_GRAY) || ((int) ping_color_type == PNG_COLOR_TYPE_PALETTE) || (quality < 50)) base_filter=PNG_NO_FILTERS; + else base_filter=PNG_ALL_FILTERS; + if (logging != MagickFalse) { if (base_filter == PNG_ALL_FILTERS) @@ -7577,9 +8105,11 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, #ifdef PNG_WRITE_iCCP_SUPPORTED if ((LocaleCompare(name,"ICC") == 0) || (LocaleCompare(name,"ICM") == 0)) + png_set_iCCP(ping,ping_info,(const png_charp) name,0,(png_charp) GetStringInfoDatum(profile), (png_uint_32) GetStringInfoLength(profile)); + else #endif png_write_raw_profile(image_info,ping,ping_info,(unsigned char *) @@ -7589,6 +8119,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Setting up text chunk with %s profile",name); + name=GetNextImageProfile(image); } @@ -7603,9 +8134,11 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Setting up sRGB chunk"); + (void) png_set_sRGB(ping,ping_info,( PNG_RenderingIntent_from_Magick_RenderingIntent( image->rendering_intent))); + png_set_gAMA(ping,ping_info,0.45455); } if ((!mng_info->write_mng) || (!png_get_valid(ping,ping_info,PNG_INFO_sRGB))) @@ -7664,7 +8197,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, if (ping_bit_depth < 8) ping_bit_depth=8; } - + if (mng_info->write_png_colortype-1 == PNG_COLOR_TYPE_GRAY_ALPHA) if (ImageIsGray(image) == MagickFalse) ping_color_type = PNG_COLOR_TYPE_RGB_ALPHA; @@ -7703,6 +8236,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, /* Add an opaque matte channel */ image->matte = MagickTrue; (void) SetImageOpacity(image,0); + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Added an opaque matte channel"); @@ -7727,27 +8261,28 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, if (ping_color_type == 3 && ping_have_PLTE != MagickFalse) { png_set_PLTE(ping,ping_info,palette,(int) number_colors); + if (logging) - { - for (i=0; i< number_colors; i++) { - if (ping_num_trans != 0) - (void) LogMagickEvent(CoderEvent,GetMagickModule(), - " PLTE[%d] + tRNS[%d] =(%d,%d,%d,%d)", - (int) i,(int) i, - (int) palette[i].red, - (int) palette[i].green, - (int) palette[i].blue, - (int) ping_trans_alpha[i]); - else - (void) LogMagickEvent(CoderEvent,GetMagickModule(), - " PLTE[%d] =(%d,%d,%d)", - (int) i, - (int) palette[i].red, - (int) palette[i].green, - (int) palette[i].blue); + for (i=0; i< number_colors; i++) + { + if (ping_num_trans != 0) + (void) LogMagickEvent(CoderEvent,GetMagickModule(), + " PLTE[%d] + tRNS[%d] =(%d,%d,%d,%d)", + (int) i,(int) i, + (int) palette[i].red, + (int) palette[i].green, + (int) palette[i].blue, + (int) ping_trans_alpha[i]); + else + (void) LogMagickEvent(CoderEvent,GetMagickModule(), + " PLTE[%d] =(%d,%d,%d)", + (int) i, + (int) palette[i].red, + (int) palette[i].green, + (int) palette[i].blue); + } } - } } if (ping_have_bKGD != MagickFalse) @@ -7777,35 +8312,36 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, png_write_info_before_PLTE(ping, ping_info); if (ping_have_tRNS != MagickFalse && ping_color_type < 4) - { - if (logging) { - (void) LogMagickEvent(CoderEvent,GetMagickModule(), - " Calling png_set_tRNS with num_trans=%d",ping_num_trans); - } + if (logging) + { + (void) LogMagickEvent(CoderEvent,GetMagickModule(), + " Calling png_set_tRNS with num_trans=%d",ping_num_trans); + } - if (ping_color_type == 3) - (void) png_set_tRNS(ping, ping_info, - ping_trans_alpha, - ping_num_trans, - NULL); + if (ping_color_type == 3) + (void) png_set_tRNS(ping, ping_info, + ping_trans_alpha, + ping_num_trans, + NULL); - else - { - (void) png_set_tRNS(ping, ping_info, - NULL, - 0, - &ping_trans_color); - if (logging) - { - (void) LogMagickEvent(CoderEvent,GetMagickModule(), - " background =(%d,%d,%d)", - (int) ping_trans_color.red, - (int) ping_trans_color.green, - (int) ping_trans_color.blue); - } - } - } + else + { + (void) png_set_tRNS(ping, ping_info, + NULL, + 0, + &ping_trans_color); + + if (logging) + { + (void) LogMagickEvent(CoderEvent,GetMagickModule(), + " background =(%d,%d,%d)", + (int) ping_trans_color.red, + (int) ping_trans_color.green, + (int) ping_trans_color.blue); + } + } + } /* write any png-chunk-b profiles */ (void) png_write_chunk_from_profile(image,"PNG-chunk-b",(int) logging); @@ -7848,12 +8384,15 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, case PNG_COLOR_TYPE_RGB: rowbytes*=3; break; + case PNG_COLOR_TYPE_GRAY_ALPHA: rowbytes*=2; break; + case PNG_COLOR_TYPE_RGBA: rowbytes*=4; break; + default: break; } @@ -7861,13 +8400,16 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, { (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Writing PNG image data"); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Allocating %.20g bytes of memory for pixels",(double) rowbytes); } png_pixels=(unsigned char *) AcquireQuantumMemory(rowbytes, sizeof(*png_pixels)); + if (png_pixels == (unsigned char *) NULL) ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); + /* Initialize image scanlines. */ @@ -7904,7 +8446,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, { register const PixelPacket *p; - + quantum_info->depth=8; for (pass=0; pass < num_passes; pass++) { @@ -7918,8 +8460,10 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, " Writing row of pixels (0)"); p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception); + if (p == (const PixelPacket *) NULL) break; + if (mng_info->IsPalette) { (void) ExportQuantumPixels(image,(const CacheView *) NULL, @@ -7934,18 +8478,22 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, >> (8-old_bit_depth)); } } + else { (void) ExportQuantumPixels(image,(const CacheView *) NULL, quantum_info,RedQuantum,png_pixels,&image->exception); } + if (mng_info->write_png_colortype-1 != PNG_COLOR_TYPE_PALETTE) for (i=0; i < (ssize_t) image->columns; i++) *(png_pixels+i)=(unsigned char) ((*(png_pixels+i) > 127) ? 255 : 0); + if (logging && y == 0) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Writing row of pixels (1)"); + png_write_row(ping,png_pixels); } if (image->previous == (Image *) NULL) @@ -7956,13 +8504,14 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, } } } + else for (pass=0; pass < num_passes; pass++) { register const PixelPacket *p; - if ((!mng_info->write_png8 && !mng_info->write_png24 && + if ((!mng_info->write_png8 && !mng_info->write_png24 && !mng_info->write_png32) && (image_matte || (ping_bit_depth >= MAGICKCORE_QUANTUM_DEPTH)) && @@ -7971,33 +8520,41 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, for (y=0; y < (ssize_t) image->rows; y++) { p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception); + if (p == (const PixelPacket *) NULL) break; + if (ping_color_type == PNG_COLOR_TYPE_GRAY) { if (mng_info->IsPalette) (void) ExportQuantumPixels(image,(const CacheView *) NULL, quantum_info,GrayQuantum,png_pixels,&image->exception); + else (void) ExportQuantumPixels(image,(const CacheView *) NULL, quantum_info,RedQuantum,png_pixels,&image->exception); + if (logging && y == 0) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Writing GRAY PNG pixels (2)"); } + else /* PNG_COLOR_TYPE_GRAY_ALPHA */ { if (logging && y == 0) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Writing GRAY_ALPHA PNG pixels (2)"); + (void) ExportQuantumPixels(image,(const CacheView *) NULL, quantum_info,GrayAlphaQuantum,png_pixels,&image->exception); } if (logging && y == 0) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Writing row of pixels (2)"); + png_write_row(ping,png_pixels); } + if (image->previous == (Image *) NULL) { status=SetImageProgress(image,LoadImageTag,pass,num_passes); @@ -8014,36 +8571,46 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, for (y=0; y < (ssize_t) image->rows; y++) { p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception); + if (p == (const PixelPacket *) NULL) break; + if (ping_color_type == PNG_COLOR_TYPE_GRAY) { if (image->storage_class == DirectClass) (void) ExportQuantumPixels(image,(const CacheView *) NULL, quantum_info,RedQuantum,png_pixels,&image->exception); + else (void) ExportQuantumPixels(image,(const CacheView *) NULL, quantum_info,GrayQuantum,png_pixels,&image->exception); } + else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { (void) ExportQuantumPixels(image,(const CacheView *) NULL, quantum_info,GrayAlphaQuantum,png_pixels,&image->exception); + if (logging && y == 0) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Writing GRAY_ALPHA PNG pixels (3)"); } + else if (image_matte != MagickFalse) (void) ExportQuantumPixels(image,(const CacheView *) NULL, quantum_info,RGBAQuantum,png_pixels,&image->exception); + else (void) ExportQuantumPixels(image,(const CacheView *) NULL, quantum_info,RGBQuantum,png_pixels,&image->exception); + if (logging && y == 0) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Writing row of pixels (3)"); + png_write_row(ping,png_pixels); } + else /* not ((image_depth > 8) || (mng_info->write_png24 || mng_info->write_png32 || @@ -8055,6 +8622,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, if (logging) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " pass %d, Image Is not GRAY or GRAY_ALPHA",pass); + quantum_info->depth=8; image_depth=8; } @@ -8063,27 +8631,35 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, if (logging && y == 0) (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); + if (p == (const PixelPacket *) NULL) break; + if (ping_color_type == PNG_COLOR_TYPE_GRAY) (void) ExportQuantumPixels(image,(const CacheView *) NULL, quantum_info,GrayQuantum,png_pixels,&image->exception); + else if (ping_color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { if (logging && y == 0) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Writing GRAY_ALPHA PNG pixels (4)"); + (void) ExportQuantumPixels(image,(const CacheView *) NULL, quantum_info,GrayAlphaQuantum,png_pixels,&image->exception); } + else (void) ExportQuantumPixels(image,(const CacheView *) NULL, quantum_info,IndexQuantum,png_pixels,&image->exception); + if (logging && y <= 2) { (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Writing row of pixels (4)"); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " png_pixels[0]=%d,png_pixels[1]=%d", (int)png_pixels[0],(int)png_pixels[1]); @@ -8106,24 +8682,31 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, { (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Wrote PNG image data"); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Width: %.20g",(double) ping_width); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Height: %.20g",(double) ping_height); + if (mng_info->write_png_depth) { (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Defined PNG:bit-depth: %d",mng_info->write_png_depth); } + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " PNG bit-depth written: %d",ping_bit_depth); + if (mng_info->write_png_colortype) { (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Defined PNG:color-type: %d",mng_info->write_png_colortype-1); } + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " PNG color-type written: %d",ping_color_type); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " PNG Interlace method: %d",ping_interlace_method); } @@ -8147,13 +8730,16 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, text[0].compression=image_info->compression == NoCompression || (image_info->compression == UndefinedCompression && text[0].text_length < 128) ? -1 : 0; + 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); } @@ -8166,7 +8752,9 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Writing PNG end info"); + png_write_end(ping,ping_info); + if (mng_info->need_fram && (int) image->dispose == BackgroundDispose) { if (mng_info->page.x || mng_info->page.y || @@ -8201,6 +8789,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, mng_info->old_framing_mode=4; mng_info->framing_mode=1; } + else mng_info->framing_mode=3; } @@ -8209,6 +8798,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, (void) ThrowMagickException(&image->exception,GetMagickModule(), CoderError,"Cannot convert GIF with disposal method 3 to MNG-LC", "`%s'",image->filename); + image_depth=save_image_depth; /* Save depth actually written */ @@ -8233,6 +8823,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " exit WriteOnePNGImage()"); + return(MagickTrue); /* End write one PNG image */ } @@ -8286,7 +8877,7 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, % 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. +% channel is present even if the image is fully opaque. % % o -define: For more precise control of the PNG output, you can use the % Image options "png:bit-depth" and "png:color-type". These @@ -8345,6 +8936,25 @@ static MagickBooleanType WriteOnePNGImage(MngInfo *mng_info, % % -profile PNG-chunk-b01:file01 -profile PNG-chunk-b02:file02 % +% Set image_info->type=OptimizeType (new in version 5.4.0) to get the +% following optimizations: +% +% o 16-bit depth is reduced to 8 if all pixels contain samples whose +% high byte and low byte are identical. +% o Opaque matte channel is removed. +% o If matte channel is present but only one transparent color is +% present, RGB+tRNS is written instead of RGBA +% o Grayscale images are reduced to 1, 2, or 4 bit depth if +% this can be done without loss. +% +% TO DO: Always do the above. +% +% As of version 6.6.5 the following optimizations are always done: +% +% o Palette is sorted to remove unused entries and to put a +% transparent color first, if PNG_SORT_PALETTE is defined. +% o Opaque matte channel is removed when writing an indexed PNG. +% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */ static MagickBooleanType WritePNGImage(const ImageInfo *image_info, @@ -8382,8 +8992,10 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info, */ have_mng_structure=MagickFalse; mng_info=(MngInfo *) AcquireMagickMemory(sizeof(MngInfo)); + if (mng_info == (MngInfo *) NULL) ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); + /* Initialize members of the MngInfo structure. */ @@ -8406,8 +9018,10 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info, #if 0 /* this does not work */ if (image->matte == MagickTrue) (void) SetImageType(image,PaletteMatteType); + else (void) SetImageType(image,PaletteType); + (void) SyncImage(image); #endif } @@ -8417,10 +9031,13 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info, mng_info->write_png_colortype = /* 2 */ 3; mng_info->write_png_depth = 8; image->depth = 8; + if (image->matte == MagickTrue) (void) SetImageType(image,TrueColorMatteType); + else (void) SetImageType(image,TrueColorType); + (void) SyncImage(image); } @@ -8429,10 +9046,13 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info, mng_info->write_png_colortype = /* 6 */ 7; mng_info->write_png_depth = 8; image->depth = 8; + if (image->matte == MagickTrue) (void) SetImageType(image,TrueColorMatteType); + else (void) SetImageType(image,TrueColorType); + (void) SyncImage(image); } @@ -8441,14 +9061,19 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info, { if (LocaleCompare(value,"1") == 0) mng_info->write_png_depth = 1; + else if (LocaleCompare(value,"2") == 0) mng_info->write_png_depth = 2; + else if (LocaleCompare(value,"4") == 0) mng_info->write_png_depth = 4; + else if (LocaleCompare(value,"8") == 0) mng_info->write_png_depth = 8; + else if (LocaleCompare(value,"16") == 0) mng_info->write_png_depth = 16; + else (void) ThrowMagickException(&image->exception, GetMagickModule(),CoderWarning, @@ -8459,20 +9084,27 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info, (void) LogMagickEvent(CoderEvent,GetMagickModule(), " png:bit-depth=%d was defined.\n",mng_info->write_png_depth); } + value=GetImageOption(image_info,"png:color-type"); + if (value != (char *) NULL) { /* We must store colortype+1 because 0 is a valid colortype */ if (LocaleCompare(value,"0") == 0) mng_info->write_png_colortype = 1; + else if (LocaleCompare(value,"2") == 0) mng_info->write_png_colortype = 3; + else if (LocaleCompare(value,"3") == 0) mng_info->write_png_colortype = 4; + else if (LocaleCompare(value,"4") == 0) mng_info->write_png_colortype = 5; + else if (LocaleCompare(value,"6") == 0) mng_info->write_png_colortype = 7; + else (void) ThrowMagickException(&image->exception, GetMagickModule(),CoderWarning, @@ -8489,8 +9121,10 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info, (void) CloseBlob(image); MngInfoFreeStruct(mng_info,&have_mng_structure); + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WritePNGImage()"); + return(status); } @@ -8553,27 +9187,37 @@ static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info, if (transparent) { jng_color_type=14; + /* Create JPEG blob, image, and image_info */ if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Creating jpeg_image_info for opacity."); + jpeg_image_info=(ImageInfo *) CloneImageInfo(image_info); + if (jpeg_image_info == (ImageInfo *) NULL) ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Creating jpeg_image."); + jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception); + if (jpeg_image == (Image *) NULL) ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); + (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent); status=SeparateImageChannel(jpeg_image,OpacityChannel); status=NegateImage(jpeg_image,MagickFalse); jpeg_image->matte=MagickFalse; + if (jng_quality >= 1000) jpeg_image_info->quality=jng_quality/1000; + else jpeg_image_info->quality=jng_quality; + jpeg_image_info->type=GrayscaleType; (void) SetImageType(jpeg_image,GrayscaleType); (void) AcquireUniqueFilename(jpeg_image->filename); @@ -8631,6 +9275,7 @@ static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info, blob=ImageToBlob(jpeg_image_info,jpeg_image,&length, &image->exception); jng_alpha_sample_depth=8; + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Successfully read jpeg_image into a blob, length=%.20g.", @@ -8663,27 +9308,36 @@ static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info, { (void) LogMagickEvent(CoderEvent,GetMagickModule(), " JNG width:%15lu",(unsigned long) image->columns); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " JNG height:%14lu",(unsigned long) image->rows); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " JNG color type:%10d",jng_color_type); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " JNG sample depth:%8d",8); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " JNG compression:%9d",8); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " JNG interlace:%11d",0); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " JNG alpha depth:%9d",jng_alpha_sample_depth); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " JNG alpha compression:%3d",jng_alpha_compression_method); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " JNG alpha filter:%8d",0); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " JNG alpha interlace:%5d",0); } - /* Write any JNG-chunk-b profiles */ + /* Write any JNG-chunk-b profiles */ (void) png_write_chunk_from_profile(image,"JNG-chunk-b",(int) logging); /* @@ -8732,14 +9386,17 @@ static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info, (void) WriteBlobMSBULong(image,1L); PNGType(chunk,mng_sRGB); LogPNGChunk((int) logging,mng_sRGB,1L); + if (image->rendering_intent != UndefinedIntent) chunk[4]=(unsigned char) PNG_RenderingIntent_from_Magick_RenderingIntent( (image->rendering_intent)); + else chunk[4]=(unsigned char) PNG_RenderingIntent_from_Magick_RenderingIntent( (PerceptualIntent)); + (void) WriteBlob(image,5,chunk); (void) WriteBlobMSBULong(image,crc32(0,chunk,5)); } @@ -8757,6 +9414,7 @@ static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info, (void) WriteBlob(image,8,chunk); (void) WriteBlobMSBULong(image,crc32(0,chunk,8)); } + if ((mng_info->equal_chrms == MagickFalse) && (image->chromaticity.red_primary.x != 0.0)) { @@ -8785,6 +9443,7 @@ static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info, (void) WriteBlobMSBULong(image,crc32(0,chunk,36)); } } + if (image->x_resolution && image->y_resolution && !mng_info->equal_physs) { /* @@ -8797,20 +9456,26 @@ static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info, { PNGLong(chunk+4,(png_uint_32) (image->x_resolution*100.0/2.54+0.5)); + PNGLong(chunk+8,(png_uint_32) (image->y_resolution*100.0/2.54+0.5)); + chunk[12]=1; } + else { if (image->units == PixelsPerCentimeterResolution) { PNGLong(chunk+4,(png_uint_32) (image->x_resolution*100.0+0.5)); + PNGLong(chunk+8,(png_uint_32) (image->y_resolution*100.0+0.5)); + chunk[12]=1; } + else { PNGLong(chunk+4,(png_uint_32) (image->x_resolution+0.5)); @@ -8872,6 +9537,7 @@ static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info, { len=(*p<<24)|((*(p+1))<<16)|((*(p+2))<<8)|(*(p+3)); p+=4; + if (*(p)==73 && *(p+1)==68 && *(p+2)==65 && *(p+3)==84) /* IDAT */ { /* Found an IDAT chunk. */ @@ -8881,6 +9547,7 @@ static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info, (void) WriteBlobMSBULong(image, crc32(0,p,(uInt) len+4)); } + else { if (logging != MagickFalse) @@ -8940,13 +9607,17 @@ static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info, if (jng_color_type == 8 || jng_color_type == 12) jpeg_image_info->type=GrayscaleType; + jpeg_image_info->quality=jng_quality % 1000; (void) CopyMagickString(jpeg_image_info->magick,"JPEG",MaxTextExtent); (void) CopyMagickString(jpeg_image->magick,"JPEG",MaxTextExtent); + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Creating blob."); + blob=ImageToBlob(jpeg_image_info,jpeg_image,&length,&image->exception); + if (logging != MagickFalse) { (void) LogMagickEvent(CoderEvent,GetMagickModule(), @@ -8956,6 +9627,7 @@ static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info, (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Write JDAT chunk, length=%.20g.",(double) length); } + /* Write JDAT chunk(s) */ (void) WriteBlobMSBULong(image,(size_t) length); PNGType(chunk,mng_JDAT); @@ -8982,6 +9654,7 @@ static MagickBooleanType WriteOneJNGImage(MngInfo *mng_info, if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " exit WriteOneJNGImage()"); + return(status); } @@ -9175,6 +9848,7 @@ static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image) if (mng_info->write_png8 || mng_info->write_png24 || mng_info->write_png32) optimize=MagickFalse; + else optimize=(image_info->type == OptimizeType || image_info->type == UndefinedType); @@ -9187,14 +9861,18 @@ static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Checking input image(s)"); + if (optimize) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Optimize: TRUE"); + else (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Optimize: FALSE"); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Image_info depth: %.20g",(double) image_info->depth); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Type: %d",image_info->type); @@ -9203,26 +9881,34 @@ static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image) { (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Scene: %.20g",(double) scene++); + (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Image depth: %.20g",(double) p->depth); + if (p->matte) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Matte: True"); + else (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Matte: False"); + if (p->storage_class == PseudoClass) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Storage class: PseudoClass"); + else (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Storage class: DirectClass"); + if (p->colors) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Number of colors: %.20g",(double) p->colors); + else (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Number of colors: unspecified"); + if (mng_info->adjoin == MagickFalse) break; } @@ -9240,6 +9926,7 @@ static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image) { if (p->taint && p->storage_class == PseudoClass) (void) SyncImage(p); + if (mng_info->adjoin == MagickFalse) break; } @@ -9263,8 +9950,10 @@ static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image) if (p->colors <= 256) { p->colors=0; + if (p->matte != MagickFalse) (void) SetImageType(p,PaletteMatteType); + else (void) SetImageType(p,PaletteType); } @@ -9332,24 +10021,32 @@ static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image) { if ((next_image->columns+next_image->page.x) > mng_info->page.width) mng_info->page.width=next_image->columns+next_image->page.x; + if ((next_image->rows+next_image->page.y) > mng_info->page.height) mng_info->page.height=next_image->rows+next_image->page.y; } + if (next_image->page.x || next_image->page.y) need_defi=MagickTrue; + if (next_image->matte) need_matte=MagickTrue; + if ((int) next_image->dispose >= BackgroundDispose) if (next_image->matte || next_image->page.x || next_image->page.y || ((next_image->columns < mng_info->page.width) && (next_image->rows < mng_info->page.height))) mng_info->need_fram=MagickTrue; + if (next_image->iterations) need_iterations=MagickTrue; + final_delay=next_image->delay; + if (final_delay != initial_delay || final_delay > 1UL* next_image->ticks_per_second) mng_info->need_fram=1; + #if defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) || \ defined(PNG_MNG_FEATURES_SUPPORTED) /* @@ -9357,6 +10054,7 @@ static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image) */ if (image->matte != MagickFalse) need_local_plte=MagickTrue; + if (need_local_plte == 0) { if (ImageIsGray(image) == MagickFalse) @@ -9376,15 +10074,19 @@ static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image) next_image->background_color.blue != next_image->next->background_color.blue) mng_info->equal_backgrounds=MagickFalse; + if (next_image->gamma != next_image->next->gamma) mng_info->equal_gammas=MagickFalse; + if (next_image->rendering_intent != next_image->next->rendering_intent) mng_info->equal_srgbs=MagickFalse; + if ((next_image->units != next_image->next->units) || (next_image->x_resolution != next_image->next->x_resolution) || (next_image->y_resolution != next_image->next->y_resolution)) mng_info->equal_physs=MagickFalse; + if (mng_info->equal_chrms) { if (next_image->chromaticity.red_primary.x != @@ -9422,6 +10124,7 @@ static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image) #endif need_iterations=MagickFalse; } + if (mng_info->need_fram == MagickFalse) { /* @@ -9451,16 +10154,20 @@ static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image) mng_info->ticks_per_second=(png_uint_32) (image->ticks_per_second/final_delay); if (final_delay > 50) mng_info->ticks_per_second=2; + if (final_delay > 75) mng_info->ticks_per_second=1; + if (final_delay > 125) mng_info->need_fram=MagickTrue; + if (need_defi && final_delay > 2 && (final_delay != 4) && (final_delay != 5) && (final_delay != 10) && (final_delay != 20) && (final_delay != 25) && (final_delay != 50) && (final_delay != 1UL*image->ticks_per_second)) mng_info->need_fram=MagickTrue; /* make it exact; cannot be VLC */ } + if (mng_info->need_fram != MagickFalse) mng_info->ticks_per_second=1UL*image->ticks_per_second; /* @@ -9487,30 +10194,37 @@ static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image) { if (need_defi || mng_info->need_fram || use_global_plte) PNGLong(chunk+28,27L); /* simplicity=LC+JNG */ + else PNGLong(chunk+28,25L); /* simplicity=VLC+JNG */ } + else { if (need_defi || mng_info->need_fram || use_global_plte) PNGLong(chunk+28,19L); /* simplicity=LC+JNG, no transparency */ + else PNGLong(chunk+28,17L); /* simplicity=VLC+JNG, no transparency */ } } + else { if (need_matte) { if (need_defi || mng_info->need_fram || use_global_plte) PNGLong(chunk+28,11L); /* simplicity=LC */ + else PNGLong(chunk+28,9L); /* simplicity=VLC */ } + else { if (need_defi || mng_info->need_fram || use_global_plte) PNGLong(chunk+28,3L); /* simplicity=LC, no transparency */ + else PNGLong(chunk+28,1L); /* simplicity=VLC, no transparency */ } @@ -9548,18 +10262,23 @@ static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image) chunk[5]=0; /* show last frame when done */ PNGLong(chunk+6,(png_uint_32) (mng_info->ticks_per_second* final_delay/MagickMax(image->ticks_per_second,1))); + if (image->iterations == 0) PNGLong(chunk+10,PNG_UINT_31_MAX); + else PNGLong(chunk+10,(png_uint_32) image->iterations); + if (logging != MagickFalse) { (void) LogMagickEvent(CoderEvent,GetMagickModule(), " TERM delay: %.20g",(double) (mng_info->ticks_per_second* final_delay/MagickMax(image->ticks_per_second,1))); + if (image->iterations == 0) (void) LogMagickEvent(CoderEvent,GetMagickModule(), " TERM iterations: %.20g",(double) PNG_UINT_31_MAX); + else (void) LogMagickEvent(CoderEvent,GetMagickModule(), " Image iterations: %.20g",(double) image->iterations); @@ -9579,18 +10298,22 @@ static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image) (void) WriteBlobMSBULong(image,1L); PNGType(chunk,mng_sRGB); LogPNGChunk((int) logging,mng_sRGB,1L); + if (image->rendering_intent != UndefinedIntent) chunk[4]=(unsigned char) PNG_RenderingIntent_from_Magick_RenderingIntent( (image->rendering_intent)); + else chunk[4]=(unsigned char) PNG_RenderingIntent_from_Magick_RenderingIntent( (PerceptualIntent)); + (void) WriteBlob(image,5,chunk); (void) WriteBlobMSBULong(image,crc32(0,chunk,5)); mng_info->have_write_global_srgb=MagickTrue; } + else { if (image->gamma && mng_info->equal_gammas) @@ -9642,24 +10365,31 @@ static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image) (void) WriteBlobMSBULong(image,9L); PNGType(chunk,mng_pHYs); LogPNGChunk((int) logging,mng_pHYs,9L); + if (image->units == PixelsPerInchResolution) { PNGLong(chunk+4,(png_uint_32) (image->x_resolution*100.0/2.54+0.5)); + PNGLong(chunk+8,(png_uint_32) (image->y_resolution*100.0/2.54+0.5)); + chunk[12]=1; } + else { if (image->units == PixelsPerCentimeterResolution) { PNGLong(chunk+4,(png_uint_32) (image->x_resolution*100.0+0.5)); + PNGLong(chunk+8,(png_uint_32) (image->y_resolution*100.0+0.5)); + chunk[12]=1; } + else { PNGLong(chunk+4,(png_uint_32) (image->x_resolution+0.5)); @@ -9716,12 +10446,14 @@ static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image) (void) WriteBlobMSBULong(image,data_length); PNGType(chunk,mng_PLTE); LogPNGChunk((int) logging,mng_PLTE,data_length); + for (i=0; i < (ssize_t) image->colors; i++) { chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red) & 0xff; chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green) & 0xff; chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue) & 0xff; } + (void) WriteBlob(image,data_length+4,chunk); (void) WriteBlobMSBULong(image,crc32(0,chunk,(uInt) (data_length+4))); mng_info->have_write_global_plte=MagickTrue; @@ -9766,12 +10498,14 @@ static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image) (void) WriteBlobMSBULong(image,data_length); PNGType(chunk,mng_PLTE); LogPNGChunk((int) logging,mng_PLTE,data_length); + for (i=0; i < (ssize_t) image->colors; i++) { chunk[4+i*3]=ScaleQuantumToChar(image->colormap[i].red); chunk[5+i*3]=ScaleQuantumToChar(image->colormap[i].green); chunk[6+i*3]=ScaleQuantumToChar(image->colormap[i].blue); } + (void) WriteBlob(image,data_length+4,chunk); (void) WriteBlobMSBULong(image,crc32(0,chunk, (uInt) (data_length+4))); @@ -9898,9 +10632,12 @@ static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image) image=SyncNextImageInList(image); status=SetImageProgress(image,SaveImagesTag,scene++, GetImageListLength(image)); + if (status == MagickFalse) break; + } while (mng_info->adjoin); + if (write_mng) { while (GetPreviousImageInList(image) != (Image *) NULL) @@ -9919,8 +10656,10 @@ static MagickBooleanType WriteMNGImage(const ImageInfo *image_info,Image *image) */ (void) CloseBlob(image); MngInfoFreeStruct(mng_info,&have_mng_structure); + if (logging != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit WriteMNGImage()"); + return(MagickTrue); } #else /* PNG_LIBPNG_VER > 10011 */ @@ -9930,6 +10669,7 @@ static MagickBooleanType WritePNGImage(const ImageInfo *image_info,Image *image) image=image; printf("Your PNG library is too old: You have libpng-%s\n", PNG_LIBPNG_VER_STRING); + ThrowBinaryException(CoderError,"PNG library is too old", image_info->filename); } -- 2.50.1