% July 1992 %
% %
% %
-% Copyright 1999-2012 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 %
Include declarations.
*/
#include "MagickCore/studio.h"
+#include "MagickCore/artifact.h"
#include "MagickCore/attribute.h"
#include "MagickCore/blob.h"
#include "MagickCore/blob-private.h"
#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"
#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)
%
*/
+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)
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)
/*
Read EXIF properties.
*/
+ offset=0;
if (TIFFGetField(tiff,TIFFTAG_EXIFIFD,&offset) == 0)
return;
directory=TIFFCurrentDirectory(tiff);
- offset=0;
if (TIFFReadEXIFDirectory(tiff,offset) == 0)
return;
sans=NULL;
ascii=(char *) NULL;
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:
longy;
if (TIFFGetField(tiff,exif_info[i].tag,&longy,&sans,&sans) != 0)
- (void) FormatLocaleString(value,MaxTextExtent,"%lld",longy);
+ (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
+ ((MagickOffsetType) longy));
break;
}
#endif
if (image->debug != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule(),"Image depth: %.20g",
(double) image->depth);
+ image->endian=MSBEndian;
+ if (endian == FILLORDER_LSB2MSB)
+ image->endian=LSBEndian;
if ((photometric == PHOTOMETRIC_MINISBLACK) ||
(photometric == PHOTOMETRIC_MINISWHITE))
- image->colorspace=GRAYColorspace;
+ 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);
+ 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);
(void) TIFFGetFieldDefaulted(tiff,TIFFTAG_SAMPLESPERPIXEL,
&samples_per_pixel);
(void) TIFFGetFieldDefaulted(tiff,TIFFTAG_RESOLUTIONUNIT,&units);
(void) TIFFGetFieldDefaulted(tiff,TIFFTAG_YRESOLUTION,&y_resolution);
image->resolution.x=x_resolution;
image->resolution.y=y_resolution;
- x_position=(float) image->page.x/x_resolution;
- y_position=(float) image->page.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);
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;
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 ((option == (const char *) NULL) ||
- (IsMagickTrue(option) != MagickFalse))
- TIFFGetEXIFProperties(tiff,image,exception);
/*
Allocate memory for the image and pixel buffer.
*/
TIFFClose(tiff);
ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
}
- quantum_info->endian=LSBEndian;
- if (endian == FILLORDER_LSB2MSB)
- quantum_info->endian=MSBEndian;
- image->endian=quantum_info->endian;
if (sample_format == SAMPLEFORMAT_UINT)
status=SetQuantumFormat(image,quantum_info,UnsignedQuantumFormat);
if (sample_format == SAMPLEFORMAT_INT)
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);
}
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);
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)
/*
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)
{
*/
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);
{
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);
}
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
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)
(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++;
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)
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--;
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))
}
if (image->storage_class == PseudoClass)
image->depth=GetImageDepth(image,exception);
- 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.
*/
static const TIFFFieldInfo
TIFFExtensions[] =
{
- {
- 37724, -3, -3, TIFF_UNDEFINED, FIELD_CUSTOM, 1, 1,
- (char *) "PhotoshopLayerData"
- }
+ { 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)/
rows/=2;
resolution.x/=2;
resolution.y/=2;
- pyramid_image=ResizeImage(next,columns,rows,image->filter,image->blur,
- exception);
+ pyramid_image=ResizeImage(next,columns,rows,image->filter,exception);
if (pyramid_image == (Image *) NULL)
break;
pyramid_image->resolution=resolution;
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)
{
if (LocaleCompare(name,"tiff:37724") == 0)
(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);
}
}
(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);
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)
Full color TIFF raster.
*/
if (image->colorspace == LabColorspace)
- photometric=PHOTOMETRIC_CIELAB;
+ {
+ photometric=PHOTOMETRIC_CIELAB;
+ EncodeLabImage(image,exception);
+ }
else
if (image->colorspace == YCbCrColorspace)
{
(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))
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);
}
}
}
+ if ((photometric == PHOTOMETRIC_RGB) &&
+ (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse))
+ (void) TransformImageColorspace(image,sRGBColorspace,exception);
switch (image->endian)
{
case LSBEndian:
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)
(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,
*/
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;
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)
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;
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->resolution.x != 0.0) && (image->resolution.y != 0.0))
(void) TIFFSetField(tiff,TIFFTAG_RESOLUTIONUNIT,(uint16) units);
(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))
+ if ((image->page.x > 0) && (image->page.y > 0))
{
/*
Set image position.
if (GetTIFFInfo(image_info,tiff,&tiff_info) == MagickFalse)
ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
quantum_info->endian=LSBEndian;
- if (endian == FILLORDER_LSB2MSB)
- quantum_info->endian=MSBEndian;
- image->endian=quantum_info->endian;
pixels=GetQuantumPixels(quantum_info);
tiff_info.scanline=GetQuantumPixels(quantum_info);
switch (photometric)
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++)
{
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
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);
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;
}
}
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);