X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=coders%2Ftiff.c;h=0b57bc3819b0a7fbeeacbbd5e936834c1d799e90;hb=45ef08fd6a09813e4a8f5ddadf85ba9e0ec2cdc7;hp=23637f5bd0a1db36ba1a32f93b0ba98fe4fbaf6d;hpb=8a11cb146177680bfc1b7d89a8cd0c8f2befe468;p=imagemagick diff --git a/coders/tiff.c b/coders/tiff.c index 23637f5bd..0b57bc381 100644 --- a/coders/tiff.c +++ b/coders/tiff.c @@ -17,7 +17,7 @@ % July 1992 % % % % % -% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization % +% Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization % % dedicated to making software imaging solutions freely available. % % % % You may not use this file except in compliance with the License. You may % @@ -40,6 +40,7 @@ Include declarations. */ #include "MagickCore/studio.h" +#include "MagickCore/artifact.h" #include "MagickCore/attribute.h" #include "MagickCore/blob.h" #include "MagickCore/blob-private.h" @@ -65,6 +66,7 @@ #include "MagickCore/monitor-private.h" #include "MagickCore/option.h" #include "MagickCore/pixel-accessor.h" +#include "MagickCore/pixel-private.h" #include "MagickCore/property.h" #include "MagickCore/quantum.h" #include "MagickCore/quantum-private.h" @@ -78,6 +80,7 @@ #include "MagickCore/string_.h" #include "MagickCore/string-private.h" #include "MagickCore/thread_.h" +#include "MagickCore/token.h" #include "MagickCore/utility.h" #if defined(MAGICKCORE_TIFF_DELEGATE) # if defined(MAGICKCORE_HAVE_TIFFCONF_H) @@ -366,7 +369,7 @@ static Image *ReadGROUP4Image(const ImageInfo *image_info, length=WriteLSBLong(file,(size_t) (strip_offset-8)); length=fwrite("\050\001\003\000\001\000\000\000\002\000\000\000",1,12,file); length=fwrite("\000\000\000\000",1,4,file); - length=WriteLSBLong(file,(long) image->x_resolution); + length=WriteLSBLong(file,(long) image->resolution.x); length=WriteLSBLong(file,1); for (length=0; (c=ReadBlobByte(image)) != EOF; length++) (void) fputc(c,file); @@ -424,6 +427,58 @@ static Image *ReadGROUP4Image(const ImageInfo *image_info, % */ +static MagickBooleanType DecodeLabImage(Image *image,ExceptionInfo *exception) +{ + CacheView + *image_view; + + MagickBooleanType + status; + + ssize_t + y; + + status=MagickTrue; + image_view=AcquireAuthenticCacheView(image,exception); + for (y=0; y < (ssize_t) image->rows; y++) + { + register Quantum + *restrict q; + + register ssize_t + x; + + if (status == MagickFalse) + continue; + q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception); + if (q == (Quantum *) NULL) + { + status=MagickFalse; + continue; + } + for (x=0; x < (ssize_t) image->columns; x++) + { + double + a, + b; + + a=QuantumScale*GetPixela(image,q)+0.5; + if (a > 1.0) + a-=1.0; + b=QuantumScale*GetPixelb(image,q)+0.5; + if (b > 1.0) + b-=1.0; + SetPixela(image,QuantumRange*a,q); + SetPixelb(image,QuantumRange*b,q); + q+=GetPixelChannels(image); + } + if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) + status=MagickFalse; + } + image_view=DestroyCacheView(image_view); + return(status); +} + static inline size_t MagickMax(const size_t x,const size_t y) { if (x > y) @@ -507,6 +562,11 @@ static void TIFFErrors(const char *module,const char *format,va_list error) "`%s'",module); } +static toff_t TIFFGetBlobSize(thandle_t image) +{ + return((toff_t) GetBlobSize((Image *) image)); +} + static void TIFFGetProfiles(TIFF *tiff,Image *image,ExceptionInfo *exception) { uint32 @@ -542,6 +602,8 @@ static void TIFFGetProfiles(TIFF *tiff,Image *image,ExceptionInfo *exception) length=0; if (TIFFGetField(tiff,37724,&length,&profile) == 1) (void) ReadProfile(image,"tiff:37724",profile,(ssize_t) length,exception); + if (TIFFGetField(tiff,34118,&length,&profile) == 1) + (void) ReadProfile(image,"tiff:34118",profile,(ssize_t) length,exception); } static void TIFFGetProperties(TIFF *tiff,Image *image,ExceptionInfo *exception) @@ -609,7 +671,11 @@ static void TIFFGetEXIFProperties(TIFF *tiff,Image *image, tdir_t directory; +#if defined(TIFF_VERSION_BIG) + uint64 +#else uint32 +#endif offset; void @@ -618,6 +684,7 @@ static void TIFFGetEXIFProperties(TIFF *tiff,Image *image, /* Read EXIF properties. */ + offset=0; if (TIFFGetField(tiff,TIFFTAG_EXIFIFD,&offset) == 0) return; directory=TIFFCurrentDirectory(tiff); @@ -635,9 +702,9 @@ static void TIFFGetEXIFProperties(TIFF *tiff,Image *image, *ascii; ascii=(char *) NULL; - if ((TIFFGetField(tiff,exif_info[i].tag,&ascii,&sans) != 0) && + if ((TIFFGetField(tiff,exif_info[i].tag,&ascii,&sans,&sans) != 0) && (ascii != (char *) NULL) && (*ascii != '\0')) - (void) CopyMagickMemory(value,ascii,MaxTextExtent); + (void) CopyMagickString(value,ascii,MaxTextExtent); break; } case TIFF_SHORT: @@ -645,7 +712,7 @@ static void TIFFGetEXIFProperties(TIFF *tiff,Image *image, uint16 shorty[2] = { 0, 0}; - if (TIFFGetField(tiff,exif_info[i].tag,&shorty,&sans) != 0) + if (TIFFGetField(tiff,exif_info[i].tag,&shorty,&sans,&sans) != 0) (void) FormatLocaleString(value,MaxTextExtent,"%d",(int) shorty[0]); break; } @@ -654,10 +721,22 @@ static void TIFFGetEXIFProperties(TIFF *tiff,Image *image, uint32 longy; - if (TIFFGetField(tiff,exif_info[i].tag,&longy,&sans) != 0) + if (TIFFGetField(tiff,exif_info[i].tag,&longy,&sans,&sans) != 0) (void) FormatLocaleString(value,MaxTextExtent,"%d",longy); break; } +#if defined(TIFF_VERSION_BIG) + case TIFF_LONG8: + { + uint64 + longy; + + if (TIFFGetField(tiff,exif_info[i].tag,&longy,&sans,&sans) != 0) + (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double) + ((MagickOffsetType) longy)); + break; + } +#endif case TIFF_RATIONAL: case TIFF_SRATIONAL: case TIFF_FLOAT: @@ -666,7 +745,7 @@ static void TIFFGetEXIFProperties(TIFF *tiff,Image *image, float rational[16]; - if (TIFFGetField(tiff,exif_info[i].tag,&rational,&sans) != 0) + if (TIFFGetField(tiff,exif_info[i].tag,&rational,&sans,&sans) != 0) (void) FormatLocaleString(value,MaxTextExtent,"%g",rational[0]); break; } @@ -719,11 +798,6 @@ static toff_t TIFFSeekBlob(thandle_t image,toff_t offset,int whence) return((toff_t) SeekBlob((Image *) image,(MagickOffsetType) offset,whence)); } -static toff_t TIFFGetBlobSize(thandle_t image) -{ - return((toff_t) GetBlobSize((Image *) image)); -} - static void TIFFUnmapBlob(thandle_t image,tdata_t base,toff_t size) { (void) image; @@ -810,7 +884,6 @@ static Image *ReadTIFFImage(const ImageInfo *image_info, size_t length, - lsb_first, pad; ssize_t @@ -904,11 +977,10 @@ static Image *ReadTIFFImage(const ImageInfo *image_info, { if (0 && (image_info->verbose != MagickFalse)) TIFFPrintDirectory(tiff,stdout,MagickFalse); - TIFFGetEXIFProperties(tiff,image,exception); - TIFFGetProfiles(tiff,image,exception); - TIFFGetProperties(tiff,image,exception); +#if defined(MAGICKCORE_HAVE_TIFFISBIGENDIAN) (void) SetImageProperty(image,"tiff:endian",TIFFIsBigEndian(tiff) == 0 ? "lsb" : "msb",exception); +#endif (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_COMPRESSION,&compress_tag); (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_ORIENTATION,&orientation); (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_IMAGEWIDTH,&width); @@ -990,25 +1062,27 @@ static Image *ReadTIFFImage(const ImageInfo *image_info, if (image->debug != MagickFalse) (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Image depth: %.20g", (double) image->depth); - lsb_first=1; image->endian=MSBEndian; - if ((int) (*(char *) &lsb_first) != 0) + if (endian == FILLORDER_LSB2MSB) image->endian=LSBEndian; + if ((photometric == PHOTOMETRIC_MINISBLACK) || + (photometric == PHOTOMETRIC_MINISWHITE)) + SetImageColorspace(image,GRAYColorspace,exception); if (photometric == PHOTOMETRIC_SEPARATED) - image->colorspace=CMYKColorspace; + SetImageColorspace(image,CMYKColorspace,exception); if (photometric == PHOTOMETRIC_CIELAB) - image->colorspace=LabColorspace; + SetImageColorspace(image,LabColorspace,exception); (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_SAMPLESPERPIXEL, &samples_per_pixel); (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_RESOLUTIONUNIT,&units); - x_resolution=(float) image->x_resolution; - y_resolution=(float) image->y_resolution; + x_resolution=(float) image->resolution.x; + y_resolution=(float) image->resolution.y; (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_XRESOLUTION,&x_resolution); (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_YRESOLUTION,&y_resolution); - image->x_resolution=x_resolution; - image->y_resolution=y_resolution; - x_position=(float) image->page.x/x_resolution; - y_position=(float) image->page.y/y_resolution; + image->resolution.x=x_resolution; + image->resolution.y=y_resolution; + x_position=(float) PerceptibleReciprocal(x_resolution)*image->page.x; + y_position=(float) PerceptibleReciprocal(y_resolution)*image->page.y; (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_XPOSITION,&x_position); (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_YPOSITION,&y_position); image->page.x=(ssize_t) ceil(x_position*x_resolution-0.5); @@ -1032,9 +1106,6 @@ static Image *ReadTIFFImage(const ImageInfo *image_info, image->chromaticity.blue_primary.x=chromaticity[4]; image->chromaticity.blue_primary.y=chromaticity[5]; } - /* - Allocate memory for the image and pixel buffer. - */ #if defined(MAGICKCORE_HAVE_TIFFISCODECCONFIGURED) || (TIFFLIB_VERSION > 20040919) if ((compress_tag != COMPRESSION_NONE) && (TIFFIsCODECConfigured(compress_tag) == 0)) @@ -1068,12 +1139,6 @@ static Image *ReadTIFFImage(const ImageInfo *image_info, sampling_factor,exception); (void) LogMagickEvent(CoderEvent,GetMagickModule(), "Sampling Factors: %s",sampling_factor); - if ((samples_per_pixel > 1) && (photometric == PHOTOMETRIC_YCBCR)) - { - (void) TIFFSetField(tiff,TIFFTAG_JPEGCOLORMODE, - JPEGCOLORMODE_RGB); - photometric=PHOTOMETRIC_RGB; - } } #endif break; @@ -1087,6 +1152,14 @@ static Image *ReadTIFFImage(const ImageInfo *image_info, case COMPRESSION_ADOBE_DEFLATE: image->compression=ZipCompression; break; default: image->compression=RLECompression; break; } + TIFFGetProfiles(tiff,image,exception); + TIFFGetProperties(tiff,image,exception); + option=GetImageOption(image_info,"tiff:exif-properties"); + if (IfMagickTrue(IsStringNotFalse(option))) /* enabled by default */ + TIFFGetEXIFProperties(tiff,image,exception); + /* + Allocate memory for the image and pixel buffer. + */ quantum_info=AcquireQuantumInfo(image_info,image); if (quantum_info == (QuantumInfo *) NULL) { @@ -1101,6 +1174,7 @@ static Image *ReadTIFFImage(const ImageInfo *image_info, status=SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat); if (status == MagickFalse) { + quantum_info=DestroyQuantumInfo(quantum_info); TIFFClose(tiff); ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); } @@ -1127,12 +1201,12 @@ static Image *ReadTIFFImage(const ImageInfo *image_info, if (extra_samples == 0) { if ((samples_per_pixel == 4) && (photometric == PHOTOMETRIC_RGB)) - image->matte=MagickTrue; + image->alpha_trait=BlendPixelTrait; } else for (i=0; i < extra_samples; i++) { - image->matte=MagickTrue; + image->alpha_trait=BlendPixelTrait; if (sample_info[i] == EXTRASAMPLE_ASSOCALPHA) SetQuantumAlphaType(quantum_info,DisassociatedQuantumAlpha); } @@ -1140,7 +1214,7 @@ static Image *ReadTIFFImage(const ImageInfo *image_info, if (option != (const char *) NULL) associated_alpha=LocaleCompare(option,"associated") == 0 ? MagickTrue : MagickFalse; - if (image->matte != MagickFalse) + if (image->alpha_trait == BlendPixelTrait) (void) SetImageProperty(image,"tiff:alpha", associated_alpha != MagickFalse ? "associated" : "unassociated", exception); @@ -1198,10 +1272,9 @@ static Image *ReadTIFFImage(const ImageInfo *image_info, if ((photometric != PHOTOMETRIC_SEPARATED) && (interlace == PLANARCONFIG_SEPARATE) && (bits_per_sample < 64)) method=ReadGenericMethod; - if (image->compression == JPEGCompression) - method=ReadGenericMethod; if (TIFFIsTiled(tiff) != MagickFalse) method=ReadTileMethod; + quantum_info->endian=LSBEndian; quantum_type=RGBQuantum; pixels=GetQuantumPixels(quantum_info); switch (method) @@ -1225,29 +1298,37 @@ static Image *ReadTIFFImage(const ImageInfo *image_info, /* Initialize colormap. */ + red_colormap=(uint16 *) NULL; + green_colormap=(uint16 *) NULL; + blue_colormap=(uint16 *) NULL; (void) TIFFGetField(tiff,TIFFTAG_COLORMAP,&red_colormap, &green_colormap,&blue_colormap); - range=255; /* might be old style 8-bit colormap */ - for (i=0; i < (ssize_t) image->colors; i++) - if ((red_colormap[i] >= 256) || (green_colormap[i] >= 256) || - (blue_colormap[i] >= 256)) + if ((red_colormap != (uint16 *) NULL) && + (green_colormap != (uint16 *) NULL) && + (blue_colormap != (uint16 *) NULL)) + { + range=255; /* might be old style 8-bit colormap */ + for (i=0; i < (ssize_t) image->colors; i++) + if ((red_colormap[i] >= 256) || (green_colormap[i] >= 256) || + (blue_colormap[i] >= 256)) + { + range=65535; + break; + } + for (i=0; i < (ssize_t) image->colors; i++) { - range=65535; - break; + image->colormap[i].red=ClampToQuantum(((double) + QuantumRange*red_colormap[i])/range); + image->colormap[i].green=ClampToQuantum(((double) + QuantumRange*green_colormap[i])/range); + image->colormap[i].blue=ClampToQuantum(((double) + QuantumRange*blue_colormap[i])/range); } - for (i=0; i < (ssize_t) image->colors; i++) - { - image->colormap[i].red=ClampToQuantum(((double) QuantumRange* - red_colormap[i])/range); - image->colormap[i].green=ClampToQuantum(((double) QuantumRange* - green_colormap[i])/range); - image->colormap[i].blue=ClampToQuantum(((double) QuantumRange* - blue_colormap[i])/range); - } + } } quantum_type=IndexQuantum; pad=(size_t) MagickMax((size_t) samples_per_pixel-1,0); - if (image->matte != MagickFalse) + if (image->alpha_trait == BlendPixelTrait) { if (image->storage_class != PseudoClass) { @@ -1310,7 +1391,7 @@ static Image *ReadTIFFImage(const ImageInfo *image_info, */ pad=(size_t) MagickMax((size_t) samples_per_pixel-3,0); quantum_type=RGBQuantum; - if (image->matte != MagickFalse) + if (image->alpha_trait == BlendPixelTrait) { quantum_type=RGBAQuantum; pad=(size_t) MagickMax((size_t) samples_per_pixel-4,0); @@ -1319,7 +1400,7 @@ static Image *ReadTIFFImage(const ImageInfo *image_info, { pad=(size_t) MagickMax((size_t) samples_per_pixel-4,0); quantum_type=CMYKQuantum; - if (image->matte != MagickFalse) + if (image->alpha_trait == BlendPixelTrait) { quantum_type=CMYKAQuantum; pad=(size_t) MagickMax((size_t) samples_per_pixel-5,0); @@ -1418,14 +1499,14 @@ static Image *ReadTIFFImage(const ImageInfo *image_info, } case ReadStripMethod: { - register unsigned char + register uint32 *p; /* Convert stripped TIFF image to DirectClass MIFF image. */ i=0; - p=(unsigned char *) NULL; + p=(uint32 *) NULL; for (y=0; y < (ssize_t) image->rows; y++) { register ssize_t @@ -1445,7 +1526,7 @@ static Image *ReadTIFFImage(const ImageInfo *image_info, image->rows-y); } i--; - p=(unsigned char *) (((uint32 *) pixels)+image->columns*i); + p=((uint32 *) pixels)+image->columns*i; for (x=0; x < (ssize_t) image->columns; x++) { SetPixelRed(image,ScaleCharToQuantum((unsigned char) @@ -1454,7 +1535,7 @@ static Image *ReadTIFFImage(const ImageInfo *image_info, (TIFFGetG(*p))),q); SetPixelBlue(image,ScaleCharToQuantum((unsigned char) (TIFFGetB(*p))),q); - if (image->matte != MagickFalse) + if (image->alpha_trait == BlendPixelTrait) SetPixelAlpha(image,ScaleCharToQuantum((unsigned char) (TIFFGetA(*p))),q); p++; @@ -1494,7 +1575,7 @@ static Image *ReadTIFFImage(const ImageInfo *image_info, TIFFClose(tiff); ThrowReaderException(CoderError,"ImageIsNotTiled"); } - (void) SetImageStorageClass(image,DirectClass,&image->exception); + (void) SetImageStorageClass(image,DirectClass,exception); number_pixels=columns*rows; tile_pixels=(uint32 *) AcquireQuantumMemory(number_pixels, sizeof(*tile_pixels)); @@ -1539,7 +1620,7 @@ static Image *ReadTIFFImage(const ImageInfo *image_info, x); for (row=rows_remaining; row > 0; row--) { - if (image->matte != MagickFalse) + if (image->alpha_trait == BlendPixelTrait) for (column=columns_remaining; column > 0; column--) { SetPixelRed(image,ScaleCharToQuantum((unsigned char) @@ -1634,7 +1715,7 @@ static Image *ReadTIFFImage(const ImageInfo *image_info, TIFFGetG(*p)),q); SetPixelBlue(image,ScaleCharToQuantum((unsigned char) TIFFGetB(*p)),q); - if (image->matte != MagickFalse) + if (image->alpha_trait == BlendPixelTrait) SetPixelAlpha(image,ScaleCharToQuantum((unsigned char) TIFFGetA(*p)),q); p--; @@ -1656,6 +1737,9 @@ static Image *ReadTIFFImage(const ImageInfo *image_info, } SetQuantumImageType(image,quantum_type); next_tiff_frame: + quantum_info=DestroyQuantumInfo(quantum_info); + if (photometric == PHOTOMETRIC_CIELAB) + DecodeLabImage(image,exception); if ((photometric == PHOTOMETRIC_LOGL) || (photometric == PHOTOMETRIC_MINISBLACK) || (photometric == PHOTOMETRIC_MINISWHITE)) @@ -1666,17 +1750,6 @@ static Image *ReadTIFFImage(const ImageInfo *image_info, } if (image->storage_class == PseudoClass) image->depth=GetImageDepth(image,exception); - image->endian=MSBEndian; - if (endian == FILLORDER_LSB2MSB) - image->endian=LSBEndian; - if ((photometric == PHOTOMETRIC_LOGL) || - (photometric == PHOTOMETRIC_MINISBLACK) || - (photometric == PHOTOMETRIC_MINISWHITE)) - { - image->type=GrayscaleType; - if (bits_per_sample == 1) - image->type=BilevelType; - } /* Proceed to next image. */ @@ -1701,7 +1774,6 @@ static Image *ReadTIFFImage(const ImageInfo *image_info, if (status == MagickFalse) break; } - quantum_info=DestroyQuantumInfo(quantum_info); } while (status == MagickTrue); (void) TIFFSetWarningHandler(warning_handler); (void) TIFFSetErrorHandler(error_handler); @@ -1733,6 +1805,29 @@ static Image *ReadTIFFImage(const ImageInfo *image_info, % size_t RegisterTIFFImage(void) % */ + +#if defined(MAGICKCORE_HAVE_TIFFMERGEFIELDINFO) && defined(MAGICKCORE_HAVE_TIFFSETTAGEXTENDER) +static TIFFExtendProc + tag_extender = (TIFFExtendProc) NULL; + +static void TIFFTagExtender(TIFF *tiff) +{ + static const TIFFFieldInfo + TIFFExtensions[] = + { + { 37724, -3, -3, TIFF_UNDEFINED, FIELD_CUSTOM, 1, 1, + (char *) "PhotoshopLayerData" }, + { 34118, -3, -3, TIFF_UNDEFINED, FIELD_CUSTOM, 1, 1, + (char *) "Microscope" } + }; + + TIFFMergeFieldInfo(tiff,TIFFExtensions,sizeof(TIFFExtensions)/ + sizeof(*TIFFExtensions)); + if (tag_extender != (TIFFExtendProc) NULL) + (*tag_extender)(tiff); +} +#endif + ModuleExport size_t RegisterTIFFImage(void) { #define TIFFDescription "Tagged Image File Format" @@ -1750,6 +1845,10 @@ ModuleExport size_t RegisterTIFFImage(void) { if (MagickCreateThreadKey(&tiff_exception) == MagickFalse) ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); +#if defined(MAGICKCORE_HAVE_TIFFMERGEFIELDINFO) && defined(MAGICKCORE_HAVE_TIFFSETTAGEXTENDER) + if (tag_extender == (TIFFExtendProc) NULL) + tag_extender=TIFFSetTagExtender(TIFFTagExtender); +#endif instantiate_key=MagickTrue; } UnlockSemaphoreInfo(tiff_semaphore); @@ -1828,7 +1927,7 @@ ModuleExport size_t RegisterTIFFImage(void) entry=SetMagickInfo("TIFF64"); #if defined(TIFF_VERSION_BIG) entry->decoder=(DecodeImageHandler *) ReadTIFFImage; - entry->encoder=(EncodeImageHandler *) WritePTIFImage; + entry->encoder=(EncodeImageHandler *) WriteTIFFImage; #endif entry->adjoin=MagickFalse; entry->endian_support=MagickTrue; @@ -1863,18 +1962,23 @@ ModuleExport size_t RegisterTIFFImage(void) */ ModuleExport void UnregisterTIFFImage(void) { - (void) UnregisterMagickInfo("RAWGROUP4"); - (void) UnregisterMagickInfo("PTIF"); - (void) UnregisterMagickInfo("TIF"); - (void) UnregisterMagickInfo("TIFF"); (void) UnregisterMagickInfo("TIFF64"); + (void) UnregisterMagickInfo("TIFF"); + (void) UnregisterMagickInfo("TIF"); + (void) UnregisterMagickInfo("PTIF"); if (tiff_semaphore == (SemaphoreInfo *) NULL) tiff_semaphore=AllocateSemaphoreInfo(); LockSemaphoreInfo(tiff_semaphore); if (instantiate_key != MagickFalse) - if (MagickDeleteThreadKey(tiff_exception) == MagickFalse) - ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); - instantiate_key=MagickFalse; + { +#if defined(MAGICKCORE_HAVE_TIFFMERGEFIELDINFO) && defined(MAGICKCORE_HAVE_TIFFSETTAGEXTENDER) + if (tag_extender == (TIFFExtendProc) NULL) + (void) TIFFSetTagExtender(tag_extender); +#endif + if (MagickDeleteThreadKey(tiff_exception) == MagickFalse) + ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); + instantiate_key=MagickFalse; + } UnlockSemaphoreInfo(tiff_semaphore); DestroySemaphoreInfo(&tiff_semaphore); } @@ -2091,6 +2195,9 @@ static MagickBooleanType WritePTIFImage(const ImageInfo *image_info, MagickBooleanType status; + PointInfo + resolution; + size_t columns, rows; @@ -2104,22 +2211,29 @@ static MagickBooleanType WritePTIFImage(const ImageInfo *image_info, AppendImageToList(&images,CloneImage(next,0,0,MagickFalse,exception)); columns=next->columns; rows=next->rows; + resolution=next->resolution; while ((columns > 64) && (rows > 64)) { columns/=2; rows/=2; - pyramid_image=ResizeImage(next,columns,rows,image->filter,image->blur, - exception); + resolution.x/=2; + resolution.y/=2; + pyramid_image=ResizeImage(next,columns,rows,image->filter,exception); + if (pyramid_image == (Image *) NULL) + break; + pyramid_image->resolution=resolution; AppendImageToList(&images,pyramid_image); } } + images=GetFirstImageInList(images); /* Write pyramid-encoded TIFF image. */ write_info=CloneImageInfo(image_info); - *write_info->magick='\0'; write_info->adjoin=MagickTrue; - status=WriteTIFFImage(write_info,GetFirstImageInList(images),exception); + (void) CopyMagickString(write_info->magick,"TIFF",MaxTextExtent); + (void) CopyMagickString(images->magick,"TIFF",MaxTextExtent); + status=WriteTIFFImage(write_info,images,exception); images=DestroyImageList(images); write_info=DestroyImageInfo(write_info); return(status); @@ -2176,6 +2290,58 @@ static void DestroyTIFFInfo(TIFFInfo *tiff_info) tiff_info->pixels); } +static MagickBooleanType EncodeLabImage(Image *image,ExceptionInfo *exception) +{ + CacheView + *image_view; + + MagickBooleanType + status; + + ssize_t + y; + + status=MagickTrue; + image_view=AcquireAuthenticCacheView(image,exception); + for (y=0; y < (ssize_t) image->rows; y++) + { + register Quantum + *restrict q; + + register ssize_t + x; + + if (status == MagickFalse) + continue; + q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception); + if (q == (Quantum *) NULL) + { + status=MagickFalse; + continue; + } + for (x=0; x < (ssize_t) image->columns; x++) + { + double + a, + b; + + a=QuantumScale*GetPixela(image,q)-0.5; + if (a < 0.0) + a+=1.0; + b=QuantumScale*GetPixelb(image,q)-0.5; + if (b < 0.0) + b+=1.0; + SetPixela(image,QuantumRange*a,q); + SetPixelb(image,QuantumRange*b,q); + q+=GetPixelChannels(image); + } + if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) + status=MagickFalse; + } + image_view=DestroyCacheView(image_view); + return(status); +} + static MagickBooleanType GetTIFFInfo(const ImageInfo *image_info,TIFF *tiff, TIFFInfo *tiff_info) { @@ -2256,8 +2422,8 @@ static int32 TIFFWritePixels(TIFF *tiff,TIFFInfo *tiff_info,ssize_t row, Write tile to TIFF image. */ status=0; - bytes_per_pixel=TIFFTileSize(tiff)/(ssize_t) (tiff_info->tile_geometry.height* - tiff_info->tile_geometry.width); + bytes_per_pixel=TIFFTileSize(tiff)/(ssize_t) ( + tiff_info->tile_geometry.height*tiff_info->tile_geometry.width); number_tiles=(image->columns+tiff_info->tile_geometry.width)/ tiff_info->tile_geometry.width; for (i=0; i < (ssize_t) number_tiles; i++) @@ -2341,7 +2507,10 @@ static void TIFFSetProfiles(TIFF *tiff,Image *image) GetStringInfoLength(profile),GetStringInfoDatum(profile)); #endif if (LocaleCompare(name,"tiff:37724") == 0) - (void) TIFFSetField(tiff,37724,(uint32)GetStringInfoLength(profile), + (void) TIFFSetField(tiff,37724,(uint32) GetStringInfoLength(profile), + GetStringInfoDatum(profile)); + if (LocaleCompare(name,"tiff:34118") == 0) + (void) TIFFSetField(tiff,34118,(uint32) GetStringInfoLength(profile), GetStringInfoDatum(profile)); name=GetNextImageProfile(image); } @@ -2442,7 +2611,7 @@ static void TIFFSetEXIFProperties(TIFF *tiff,Image *image, float rational; - rational=InterpretLocaleValue(value,(char **) NULL); + rational=StringToDouble(value,(char **) NULL); (void) TIFFSetField(tiff,exif_info[i].tag,rational); break; } @@ -2491,8 +2660,7 @@ static MagickBooleanType WriteTIFFImage(const ImageInfo *image_info, i; size_t - length, - lsb_first; + length; ssize_t y; @@ -2530,8 +2698,6 @@ static MagickBooleanType WriteTIFFImage(const ImageInfo *image_info, (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); assert(exception != (ExceptionInfo *) NULL); assert(exception->signature == MagickSignature); - assert(exception != (ExceptionInfo *) NULL); - assert(exception->signature == MagickSignature); status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); if (status == MagickFalse) return(status); @@ -2539,7 +2705,7 @@ static MagickBooleanType WriteTIFFImage(const ImageInfo *image_info, error_handler=TIFFSetErrorHandler((TIFFErrorHandler) TIFFErrors); warning_handler=TIFFSetWarningHandler((TIFFErrorHandler) TIFFWarnings); endian_type=UndefinedEndian; - option=GetImageOption(image_info,"tiff:endian"); + option=GetImageArtifact(image,"tiff:endian"); if (option != (const char *) NULL) { if (LocaleNCompare(option,"msb",3) == 0) @@ -2733,7 +2899,10 @@ static MagickBooleanType WriteTIFFImage(const ImageInfo *image_info, Full color TIFF raster. */ if (image->colorspace == LabColorspace) - photometric=PHOTOMETRIC_CIELAB; + { + photometric=PHOTOMETRIC_CIELAB; + EncodeLabImage(image,exception); + } else if (image->colorspace == YCbCrColorspace) { @@ -2743,11 +2912,7 @@ static MagickBooleanType WriteTIFFImage(const ImageInfo *image_info, (void) SetImageDepth(image,8,exception); } else - { - if (IsRGBColorspace(image->colorspace) == MagickFalse) - (void) TransformImageColorspace(image,RGBColorspace,exception); - photometric=PHOTOMETRIC_RGB; - } + photometric=PHOTOMETRIC_RGB; (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,3); if ((image_info->type != TrueColorType) && (image_info->type != TrueColorMatteType)) @@ -2759,7 +2924,8 @@ static MagickBooleanType WriteTIFFImage(const ImageInfo *image_info, MagickFalse ? PHOTOMETRIC_MINISWHITE : PHOTOMETRIC_MINISBLACK); (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,1); - if ((image_info->depth == 0) && (image->matte == MagickFalse) && + if ((image_info->depth == 0) && + (image->alpha_trait != BlendPixelTrait) && (IsImageMonochrome(image,exception) != MagickFalse)) { status=SetQuantumDepth(image,quantum_info,1); @@ -2789,6 +2955,9 @@ static MagickBooleanType WriteTIFFImage(const ImageInfo *image_info, } } } + if ((photometric == PHOTOMETRIC_RGB) && + (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)) + (void) TransformImageColorspace(image,sRGBColorspace,exception); switch (image->endian) { case LSBEndian: @@ -2808,10 +2977,6 @@ static MagickBooleanType WriteTIFFImage(const ImageInfo *image_info, break; } } - lsb_first=1; - image->endian=MSBEndian; - if ((int) (*(char *) &lsb_first) != 0) - image->endian=LSBEndian; if ((compress_tag == COMPRESSION_CCITTFAX3) && (photometric != PHOTOMETRIC_MINISWHITE)) { @@ -2825,7 +2990,7 @@ static MagickBooleanType WriteTIFFImage(const ImageInfo *image_info, compress_tag=COMPRESSION_NONE; endian=FILLORDER_MSB2LSB; } - option=GetImageProperty(image,"tiff:fill-order",exception); + option=GetImageArtifact(image,"tiff:fill-order"); if (option != (const char *) NULL) { if (LocaleNCompare(option,"msb",3) == 0) @@ -2836,7 +3001,7 @@ static MagickBooleanType WriteTIFFImage(const ImageInfo *image_info, (void) TIFFSetField(tiff,TIFFTAG_COMPRESSION,compress_tag); (void) TIFFSetField(tiff,TIFFTAG_FILLORDER,endian); (void) TIFFSetField(tiff,TIFFTAG_BITSPERSAMPLE,quantum_info->depth); - if (image->matte != MagickFalse) + if (image->alpha_trait == BlendPixelTrait) { uint16 extra_samples, @@ -2848,7 +3013,7 @@ static MagickBooleanType WriteTIFFImage(const ImageInfo *image_info, */ extra_samples=1; sample_info[0]=EXTRASAMPLE_UNASSALPHA; - option=GetImageProperty(image,"tiff:alpha",exception); + option=GetImageArtifact(image,"tiff:alpha"); if ((option != (const char *) NULL) && (LocaleCompare(option,"associated") == 0)) sample_info[0]=EXTRASAMPLE_ASSOCALPHA; @@ -2893,7 +3058,7 @@ static MagickBooleanType WriteTIFFImage(const ImageInfo *image_info, if (TIFFScanlineSize(tiff) != 0) rows_per_strip=(uint32) MagickMax((size_t) TIFFDefaultStripSize(tiff,0), 1); - option=GetImageOption(image_info,"tiff:rows-per-strip"); + option=GetImageArtifact(image,"tiff:rows-per-strip"); if (option != (const char *) NULL) rows_per_strip=(size_t) strtol(option,(char **) NULL,10); switch (compress_tag) @@ -2916,7 +3081,7 @@ static MagickBooleanType WriteTIFFImage(const ImageInfo *image_info, if (image_info->quality != UndefinedCompressionQuality) (void) TIFFSetField(tiff,TIFFTAG_JPEGQUALITY,image_info->quality); (void) TIFFSetField(tiff,TIFFTAG_JPEGCOLORMODE,JPEGCOLORMODE_RAW); - if (IsRGBColorspace(image->colorspace) == MagickTrue) + if (IssRGBCompatibleColorspace(image->colorspace) != MagickFalse) { const char *value; @@ -3002,10 +3167,10 @@ static MagickBooleanType WriteTIFFImage(const ImageInfo *image_info, default: break; } - option=GetImageOption(image_info,"tiff:tile-geometry"); + option=GetImageArtifact(image,"tiff:rows-per-strip"); if (option == (const char *) NULL) (void) TIFFSetField(tiff,TIFFTAG_ROWSPERSTRIP,rows_per_strip); - if ((image->x_resolution != 0.0) && (image->y_resolution != 0.0)) + if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0)) { unsigned short units; @@ -3019,17 +3184,17 @@ static MagickBooleanType WriteTIFFImage(const ImageInfo *image_info, if (image->units == PixelsPerCentimeterResolution) units=RESUNIT_CENTIMETER; (void) TIFFSetField(tiff,TIFFTAG_RESOLUTIONUNIT,(uint16) units); - (void) TIFFSetField(tiff,TIFFTAG_XRESOLUTION,image->x_resolution); - (void) TIFFSetField(tiff,TIFFTAG_YRESOLUTION,image->y_resolution); - if ((image->page.x != 0) || (image->page.y != 0)) + (void) TIFFSetField(tiff,TIFFTAG_XRESOLUTION,image->resolution.x); + (void) TIFFSetField(tiff,TIFFTAG_YRESOLUTION,image->resolution.y); + if ((image->page.x > 0) && (image->page.y > 0)) { /* Set image position. */ (void) TIFFSetField(tiff,TIFFTAG_XPOSITION,(float) image->page.x/ - image->x_resolution); + image->resolution.x); (void) TIFFSetField(tiff,TIFFTAG_YPOSITION,(float) image->page.y/ - image->y_resolution); + image->resolution.y); } } if (image->chromaticity.white_point.x != 0.0) @@ -3051,7 +3216,8 @@ static MagickBooleanType WriteTIFFImage(const ImageInfo *image_info, chromaticity[1]=(float) image->chromaticity.white_point.y; (void) TIFFSetField(tiff,TIFFTAG_WHITEPOINT,chromaticity); } - if ((image_info->adjoin != MagickFalse) && (GetImageListLength(image) > 1)) + if ((LocaleCompare(image_info->magick,"PTIF") != 0) && + (image_info->adjoin != MagickFalse) && (GetImageListLength(image) > 1)) { (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_PAGE); if (image->scene != 0) @@ -3068,7 +3234,8 @@ static MagickBooleanType WriteTIFFImage(const ImageInfo *image_info, page=(uint16) scene; pages=(uint16) GetImageListLength(image); - if ((image_info->adjoin != MagickFalse) && (pages > 1)) + if ((LocaleCompare(image_info->magick,"PTIF") != 0) && + (image_info->adjoin != MagickFalse) && (pages > 1)) (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_PAGE); (void) TIFFSetField(tiff,TIFFTAG_PAGENUMBER,page,pages); } @@ -3080,6 +3247,7 @@ static MagickBooleanType WriteTIFFImage(const ImageInfo *image_info, */ if (GetTIFFInfo(image_info,tiff,&tiff_info) == MagickFalse) ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); + quantum_info->endian=LSBEndian; pixels=GetQuantumPixels(quantum_info); tiff_info.scanline=GetQuantumPixels(quantum_info); switch (photometric) @@ -3097,7 +3265,7 @@ static MagickBooleanType WriteTIFFImage(const ImageInfo *image_info, default: { quantum_type=RGBQuantum; - if (image->matte != MagickFalse) + if (image->alpha_trait == BlendPixelTrait) quantum_type=RGBAQuantum; for (y=0; y < (ssize_t) image->rows; y++) { @@ -3185,7 +3353,7 @@ static MagickBooleanType WriteTIFFImage(const ImageInfo *image_info, if (status == MagickFalse) break; } - if (image->matte != MagickFalse) + if (image->alpha_trait == BlendPixelTrait) for (y=0; y < (ssize_t) image->rows; y++) { register const Quantum @@ -3216,7 +3384,7 @@ static MagickBooleanType WriteTIFFImage(const ImageInfo *image_info, CMYK TIFF image. */ quantum_type=CMYKQuantum; - if (image->matte != MagickFalse) + if (image->alpha_trait == BlendPixelTrait) quantum_type=CMYKAQuantum; if (image->colorspace != CMYKColorspace) (void) TransformImageColorspace(image,CMYKColorspace,exception); @@ -3281,7 +3449,7 @@ static MagickBooleanType WriteTIFFImage(const ImageInfo *image_info, Convert PseudoClass packets to contiguous grayscale scanlines. */ quantum_type=IndexQuantum; - if (image->matte != MagickFalse) + if (image->alpha_trait == BlendPixelTrait) { if (photometric != PHOTOMETRIC_PALETTE) quantum_type=GrayAlphaQuantum; @@ -3315,13 +3483,12 @@ static MagickBooleanType WriteTIFFImage(const ImageInfo *image_info, } } quantum_info=DestroyQuantumInfo(quantum_info); + if (image->colorspace == LabColorspace) + DecodeLabImage(image,exception); DestroyTIFFInfo(&tiff_info); if (0 && (image_info->verbose == MagickTrue)) TIFFPrintDirectory(tiff,stdout,MagickFalse); (void) TIFFWriteDirectory(tiff); - image->endian=MSBEndian; - if (endian == FILLORDER_LSB2MSB) - image->endian=LSBEndian; image=SyncNextImageInList(image); if (image == (Image *) NULL) break;