From e30398436b12536bf0a155144176fc5f8a7ceb19 Mon Sep 17 00:00:00 2001 From: dirk Date: Sat, 26 Apr 2014 18:22:06 +0000 Subject: [PATCH] Added new coder for VIPS image format. --- MagickCore/methods.h | 4 + MagickCore/static.c | 2 + MagickCore/static.h | 2 + coders/vips.c | 657 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 665 insertions(+) create mode 100644 coders/vips.c diff --git a/MagickCore/methods.h b/MagickCore/methods.h index 1531cbe21..074b98714 100644 --- a/MagickCore/methods.h +++ b/MagickCore/methods.h @@ -945,6 +945,7 @@ extern "C" { #define RegisterRLAImage PrependMagickMethod(RegisterRLAImage) #define RegisterRLEImage PrependMagickMethod(RegisterRLEImage) #define RegisterSCRImage PrependMagickMethod(RegisterSCRImage) +#define RegisterSREENSHOTImage PrependMagickMethod(RegisterSCREENSHOTImage) #define RegisterSCTImage PrependMagickMethod(RegisterSCTImage) #define RegisterSFWImage PrependMagickMethod(RegisterSFWImage) #define RegisterSGIImage PrependMagickMethod(RegisterSGIImage) @@ -965,6 +966,7 @@ extern "C" { #define RegisterVICARImage PrependMagickMethod(RegisterVICARImage) #define RegisterVIDImage PrependMagickMethod(RegisterVIDImage) #define RegisterVIFFImage PrependMagickMethod(RegisterVIFFImage) +#define RegisterVIPSImage PrependMagickMethod(RegisterVIPSImage) #define RegisterWBMPImage PrependMagickMethod(RegisterWBMPImage) #define RegisterWMFImage PrependMagickMethod(RegisterWMFImage) #define RegisterWPGImage PrependMagickMethod(RegisterWPGImage) @@ -1276,6 +1278,7 @@ extern "C" { #define UnregisterRGBImage PrependMagickMethod(UnregisterRGBImage) #define UnregisterRLAImage PrependMagickMethod(UnregisterRLAImage) #define UnregisterRLEImage PrependMagickMethod(UnregisterRLEImage) +#define UnregisterSCREENSHOTImage PrependMagickMethod(UnregisterSCREENSHOTImage) #define UnregisterSCRImage PrependMagickMethod(UnregisterSCRImage) #define UnregisterSCTImage PrependMagickMethod(UnregisterSCTImage) #define UnregisterSFWImage PrependMagickMethod(UnregisterSFWImage) @@ -1297,6 +1300,7 @@ extern "C" { #define UnregisterVICARImage PrependMagickMethod(UnregisterVICARImage) #define UnregisterVIDImage PrependMagickMethod(UnregisterVIDImage) #define UnregisterVIFFImage PrependMagickMethod(UnregisterVIFFImage) +#define UnregisterVIPSImage PrependMagickMethod(UnregisterVIPSImage) #define UnregisterWBMPImage PrependMagickMethod(UnregisterWBMPImage) #define UnregisterWMFImage PrependMagickMethod(UnregisterWMFImage) #define UnregisterWPGImage PrependMagickMethod(UnregisterWPGImage) diff --git a/MagickCore/static.c b/MagickCore/static.c index 4cdf1fe0d..75370ea1f 100644 --- a/MagickCore/static.c +++ b/MagickCore/static.c @@ -299,6 +299,7 @@ MagickExport void RegisterStaticModules(void) (void) RegisterVICARImage(); (void) RegisterVIDImage(); (void) RegisterVIFFImage(); + (void) RegisterVIPSImage(); (void) RegisterWBMPImage(); #if defined(MAGICKCORE_WEBP_DELEGATE) (void) RegisterWEBPImage(); @@ -477,6 +478,7 @@ MagickExport void UnregisterStaticModules(void) UnregisterVICARImage(); UnregisterVIDImage(); UnregisterVIFFImage(); + UnregisterVIPSImage(); UnregisterWBMPImage(); #if defined(MAGICKCORE_WEBP_DELEGATE) UnregisterWEBPImage(); diff --git a/MagickCore/static.h b/MagickCore/static.h index 6a36529da..3d336cba5 100644 --- a/MagickCore/static.h +++ b/MagickCore/static.h @@ -168,6 +168,7 @@ extern ModuleExport size_t RegisterVICARImage(void), RegisterVIDImage(void), RegisterVIFFImage(void), + RegisterVIPSImage(void), RegisterVSTImage(void), RegisterWBMPImage(void), RegisterWEBPImage(void), @@ -327,6 +328,7 @@ extern ModuleExport void UnregisterVICARImage(void), UnregisterVIDImage(void), UnregisterVIFFImage(void), + UnregisterVIPSImage(void), UnregisterVSTImage(void), UnregisterWBMPImage(void), UnregisterWEBPImage(void), diff --git a/coders/vips.c b/coders/vips.c new file mode 100644 index 000000000..844cec539 --- /dev/null +++ b/coders/vips.c @@ -0,0 +1,657 @@ +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % +% V V IIIII PPPP SSSSS % +% V V I P P SS % +% V V I PPPP SSS % +% V V I P SS % +% V IIIII P SSSSS % +% % +% % +% Read/Write VIPS Image Format % +% % +% Software Design % +% Dirk Lemstra % +% April 2014 % +% % +% % +% Copyright 1999-2014 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 % +% obtain a copy of the License at % +% % +% http://www.imagemagick.org/script/license.php % +% % +% Unless required by applicable law or agreed to in writing, software % +% distributed under the License is distributed on an "AS IS" BASIS, % +% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % +% See the License for the specific language governing permissions and % +% limitations under the License. % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% +*/ + +/* + Include declarations. +*/ +#include "MagickCore/studio.h" +#include "MagickCore/attribute.h" +#include "MagickCore/blob.h" +#include "MagickCore/blob-private.h" +#include "MagickCore/cache.h" +#include "MagickCore/colorspace.h" +#include "MagickCore/colorspace-private.h" +#include "MagickCore/exception.h" +#include "MagickCore/exception-private.h" +#include "MagickCore/image.h" +#include "MagickCore/image-private.h" +#include "MagickCore/list.h" +#include "MagickCore/magick.h" +#include "MagickCore/memory_.h" +#include "MagickCore/monitor.h" +#include "MagickCore/monitor-private.h" +#include "MagickCore/pixel-accessor.h" +#include "MagickCore/property.h" +#include "MagickCore/quantum-private.h" +#include "MagickCore/static.h" +#include "MagickCore/string_.h" +#include "MagickCore/module.h" + +/* + Define declaractions. +*/ +#define VIPS_MAGIC_LSB 0x08f2a6b6U +#define VIPS_MAGIC_MSB 0xb6a6f208U + +typedef enum +{ + VIPSBandFormatNOTSET = -1, + VIPSBandFormatUCHAR = 0, /* Unsigned 8-bit int */ + VIPSBandFormatCHAR = 1, /* Signed 8-bit int */ + VIPSBandFormatUSHORT = 2, /* Unsigned 16-bit int */ + VIPSBandFormatSHORT = 3, /* Signed 16-bit int */ + VIPSBandFormatUINT = 4, /* Unsigned 32-bit int */ + VIPSBandFormatINT = 5, /* Signed 32-bit int */ + VIPSBandFormatFLOAT = 6, /* 32-bit IEEE float */ + VIPSBandFormatCOMPLEX = 7, /* Complex (2 floats) */ + VIPSBandFormatDOUBLE = 8, /* 64-bit IEEE double */ + VIPSBandFormatDPCOMPLEX = 9 /* Complex (2 doubles) */ +} VIPSBandFormat; + +typedef enum +{ + VIPSCodingNONE = 0, /* VIPS computation format */ + VIPSCodingLABQ = 2, /* LABQ storage format */ + VIPSCodingRAD = 6 /* Radiance storage format */ +} VIPSCoding; + +typedef enum +{ + VIPSTypeMULTIBAND = 0, /* Some multiband image */ + VIPSTypeB_W = 1, /* Some single band image */ + VIPSTypeHISTOGRAM = 10, /* Histogram or LUT */ + VIPSTypeFOURIER = 24, /* Image in Fourier space */ + VIPSTypeXYZ = 12, /* CIE XYZ colour space */ + VIPSTypeLAB = 13, /* CIE LAB colour space */ + VIPSTypeCMYK = 15, /* im_icc_export() */ + VIPSTypeLABQ = 16, /* 32-bit CIE LAB */ + VIPSTypeRGB = 17, /* Some RGB */ + VIPSTypeUCS = 18, /* UCS(1:1) colour space */ + VIPSTypeLCH = 19, /* CIE LCh colour space */ + VIPSTypeLABS = 21, /* 48-bit CIE LAB */ + VIPSTypesRGB = 22, /* sRGB colour space */ + VIPSTypeYXY = 23, /* CIE Yxy colour space */ + VIPSTypeRGB16 = 25, /* 16-bit RGB */ + VIPSTypeGREY16 = 26 /* 16-bit monochrome */ +} VIPSType; + +/* + Forward declarations. +*/ +static MagickBooleanType + WriteVIPSImage(const ImageInfo *,Image *,ExceptionInfo *); + +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % +% I s V I P S % +% % +% % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% IsVIPS() returns MagickTrue if the image format type, identified by the +% magick string, is VIPS. +% +% The format of the IsVIPS method is: +% +% MagickBooleanType IsVIPS(const unsigned char *magick,const size_t length) +% +% A description of each parameter follows: +% +% o magick: compare image format pattern against these bytes. +% +% o length: Specifies the length of the magick string. +% +*/ +static MagickBooleanType IsVIPS(const unsigned char *magick,const size_t length) +{ + if (length < 4) + return(MagickFalse); + + if (memcmp(magick,"\010\362\246\266",4) == 0) + return(MagickTrue); + + if (memcmp(magick,"\266\246\362\010",4) == 0) + return(MagickTrue); + + return(MagickFalse); +} + +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % +% R e a d V I P S I m a g e % +% % +% % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% ReadVIPSImage() reads a VIPS image file and returns it. It allocates the +% memory necessary for the new Image structure and returns a pointer to the +% new image. +% +% The format of the ReadVIPSImage method is: +% +% Image *ReadVIPSmage(const ImageInfo *image_info,ExceptionInfo *exception) +% +% A description of each parameter follows: +% +% o image_info: the image info. +% +% o exception: return any errors or warnings in this structure. +% +*/ + +static inline Quantum ReadVIPSPixelNONE(Image *image,const VIPSBandFormat format) +{ + switch(format) + { + case VIPSBandFormatUCHAR: + case VIPSBandFormatCHAR: + return(ScaleCharToQuantum((unsigned char) ReadBlobByte(image))); + case VIPSBandFormatUSHORT: + case VIPSBandFormatSHORT: + return(ScaleShortToQuantum(ReadBlobShort(image))); + case VIPSBandFormatUINT: + case VIPSBandFormatINT: + return(ScaleLongToQuantum(ReadBlobLong(image))); + case VIPSBandFormatFLOAT: + return(ScaleMapToQuantum((MagickRealType) ReadBlobFloat(image))); + case VIPSBandFormatDOUBLE: + return(ScaleMapToQuantum((MagickRealType) ReadBlobDouble(image))); + default: + return((Quantum) 0); + } +} + +static MagickBooleanType ReadVIPSPixelsNONE(Image *image, + const VIPSBandFormat format,const unsigned int channels, + ExceptionInfo *exception) +{ + Quantum + pixel; + + register Quantum + *q; + + register ssize_t + x; + + ssize_t + y; + + for (y = 0; y < (ssize_t) image->rows; y++) + { + q=GetAuthenticPixels(image,0,y,image->columns,1,exception); + if (q == (Quantum *) NULL) + return MagickFalse; + for (x=0; x < (ssize_t) image->columns; x++) + { + pixel=ReadVIPSPixelNONE(image,format); + SetPixelRed(image,pixel,q); + if (channels < 3) + { + SetPixelGreen(image,pixel,q); + SetPixelBlue(image,pixel,q); + if (channels == 2) + SetPixelAlpha(image,ReadVIPSPixelNONE(image,format),q); + } + else + { + SetPixelGreen(image,ReadVIPSPixelNONE(image,format),q); + SetPixelBlue(image,ReadVIPSPixelNONE(image,format),q); + if (channels == 4) + { + if (image->colorspace == CMYKColorspace) + SetPixelIndex(image,ReadVIPSPixelNONE(image,format),q); + else + SetPixelAlpha(image,ReadVIPSPixelNONE(image,format),q); + } + else if (channels == 5) + { + SetPixelIndex(image,ReadVIPSPixelNONE(image,format),q); + SetPixelAlpha(image,ReadVIPSPixelNONE(image,format),q); + } + } + q+=GetPixelChannels(image); + } + if (SyncAuthenticPixels(image,exception) == MagickFalse) + return MagickFalse; + } + return(MagickTrue); +} + +static Image *ReadVIPSImage(const ImageInfo *image_info, + ExceptionInfo *exception) +{ + char + buffer[MaxTextExtent], + *metadata; + + Image + *image; + + MagickBooleanType + status; + + ssize_t + n; + + unsigned int + channels, + marker; + + VIPSBandFormat + format; + + VIPSCoding + coding; + + VIPSType + type; + + assert(image_info != (const ImageInfo *) NULL); + assert(image_info->signature == MagickSignature); + if (image_info->debug != MagickFalse) + (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", + image_info->filename); + assert(exception != (ExceptionInfo *) NULL); + assert(exception->signature == MagickSignature); + + image=AcquireImage(image_info,exception); + status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); + if (status == MagickFalse) + { + image=DestroyImageList(image); + return((Image *) NULL); + } + marker=ReadBlobLSBLong(image); + if (marker == VIPS_MAGIC_LSB) + image->endian=LSBEndian; + else if (marker == VIPS_MAGIC_MSB) + image->endian=MSBEndian; + else + ThrowReaderException(CorruptImageError,"ImproperImageHeader"); + image->columns=(size_t) ReadBlobLong(image); + image->rows=(size_t) ReadBlobLong(image); + channels=ReadBlobLong(image); + (void) ReadBlobLong(image); /* Legacy */ + format=(VIPSBandFormat) ReadBlobLong(image); + switch(format) + { + case VIPSBandFormatUCHAR: + case VIPSBandFormatCHAR: + image->depth=8; + break; + case VIPSBandFormatUSHORT: + case VIPSBandFormatSHORT: + image->depth=16; + break; + case VIPSBandFormatUINT: + case VIPSBandFormatINT: + case VIPSBandFormatFLOAT: + image->depth=32; + break; + case VIPSBandFormatDOUBLE: + image->depth=64; + break; + case VIPSBandFormatCOMPLEX: + case VIPSBandFormatDPCOMPLEX: + case VIPSBandFormatNOTSET: + ThrowReaderException(CorruptImageError,"Unsupported VIPS band format"); + break; + } + coding=(VIPSCoding) ReadBlobLong(image); + type=(VIPSType) ReadBlobLong(image); + switch(type) + { + case VIPSTypeCMYK: + SetImageColorspace(image,CMYKColorspace,exception); + if (channels == 5) + image->alpha_trait=BlendPixelTrait; + break; + case VIPSTypeB_W: + case VIPSTypeGREY16: + SetImageColorspace(image,GRAYColorspace,exception); + if (channels == 2) + image->alpha_trait=BlendPixelTrait; + break; + case VIPSTypeLAB: + case VIPSTypeLABS: + case VIPSTypeLABQ: + SetImageColorspace(image,LabColorspace,exception); + break; + case VIPSTypeLCH: + SetImageColorspace(image,LCHColorspace,exception); + break; + case VIPSTypeRGB: + case VIPSTypeRGB16: + SetImageColorspace(image,RGBColorspace,exception); + if (channels == 4) + image->alpha_trait=BlendPixelTrait; + break; + case VIPSTypesRGB: + SetImageColorspace(image,sRGBColorspace,exception); + if (channels == 4) + image->alpha_trait=BlendPixelTrait; + break; + case VIPSTypeXYZ: + SetImageColorspace(image,XYZColorspace,exception); + break; + default: + case VIPSTypeFOURIER: + case VIPSTypeHISTOGRAM: + case VIPSTypeMULTIBAND: + case VIPSTypeUCS: + case VIPSTypeYXY: + ThrowReaderException(CorruptImageError,"Unsupported VIPS colorspace"); + break; + } + image->units=PixelsPerCentimeterResolution; + image->resolution.x=ReadBlobFloat(image)*10; + image->resolution.y=ReadBlobFloat(image)*10; + /* + Legacy, offsets, future + */ + (void) ReadBlobLongLong(image); + (void) ReadBlobLongLong(image); + (void) ReadBlobLongLong(image); + if (image_info->ping != MagickFalse) + return(image); + if (coding == VIPSCodingNONE) + status=ReadVIPSPixelsNONE(image,format,channels,exception); + else + ThrowReaderException(CorruptImageError,"Unsupported VIPS coding"); + metadata=(char *) NULL; + while ((n=ReadBlob(image,MaxTextExtent-1,(unsigned char *) buffer)) != 0) + { + buffer[n]='\0'; + if (metadata == (char *) NULL) + metadata=ConstantString(buffer); + else + (void) ConcatenateString(&metadata,buffer); + } + if (metadata != (char *) NULL) + SetImageProperty(image,"vips:metadata",metadata,exception); + (void) CloseBlob(image); + if (status == MagickFalse) + return((Image *) NULL); + return(image); +} + +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % +% R e g i s t e r V I P S I m a g e % +% % +% % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% RegisterVIPSmage() adds attributes for the VIPS image format to the list +% of supported formats. The attributes include the image format tag, a +% method to read and/or write the format, whether the format supports the +% saving of more than one frame to the same file or blob, whether the format +% supports native in-memory I/O, and a brief description of the format. +% +% The format of the RegisterVIPSImage method is: +% +% size_t RegisterVIPSImage(void) +% +*/ +ModuleExport size_t RegisterVIPSImage(void) +{ + MagickInfo + *entry; + + entry=SetMagickInfo("VIPS"); + entry->decoder=(DecodeImageHandler *) ReadVIPSImage; + entry->encoder=(EncodeImageHandler *) WriteVIPSImage; + entry->magick=(IsImageFormatHandler *) IsVIPS; + entry->description=ConstantString("VIPS image"); + entry->endian_support=MagickTrue; + entry->module=ConstantString("VIPS"); + (void) RegisterMagickInfo(entry); + return(MagickImageCoderSignature); +} + +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % +% U n r e g i s t e r V I P S I m a g e % +% % +% % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% UnregisterVIPSImage() removes format registrations made by the +% VIPS module from the list of supported formats. +% +% The format of the UnregisterVIPSImage method is: +% +% UnregisterVIPSImage(void) +% +*/ +ModuleExport void UnregisterVIPSImage(void) +{ + (void) UnregisterMagickInfo("VIPS"); +} + +/* +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % +% W r i t e V I P S I m a g e % +% % +% % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% WriteVIPSImage() writes an image to a file in VIPS image format. +% +% The format of the WriteVIPSImage method is: +% +% MagickBooleanType WriteVIPSImage(const ImageInfo *image_info,Image *image) +% +% A description of each parameter follows. +% +% o image_info: the image info. +% +% o image: The image. +% +*/ + +static inline void WriteVIPSPixel(Image *image, const Quantum value) +{ + if (image->depth == 16) + (void) WriteBlobShort(image,ScaleQuantumToShort(value)); + else + (void) WriteBlobByte(image,ScaleQuantumToChar(value)); +} + +static MagickBooleanType WriteVIPSImage(const ImageInfo *image_info, + Image *image,ExceptionInfo *exception) +{ + const char + *metadata; + + MagickBooleanType + status; + + register const Quantum + *p; + + register ssize_t + x; + + ssize_t + y; + + unsigned int + channels; + + assert(image_info != (const ImageInfo *) NULL); + assert(image_info->signature == MagickSignature); + assert(image != (Image *) NULL); + assert(image->signature == MagickSignature); + if (image->debug != MagickFalse) + (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); + + status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); + if (status == MagickFalse) + return(status); + if (image->endian == LSBEndian) + (void) WriteBlobLSBLong(image,VIPS_MAGIC_LSB); + else + (void) WriteBlobLSBLong(image,VIPS_MAGIC_MSB); + (void) WriteBlobLong(image,image->columns); + (void) WriteBlobLong(image,image->rows); + (void) SetImageStorageClass(image,DirectClass,exception); + channels=image->alpha_trait == BlendPixelTrait ? 4 : 3; + if (IsImageGray(image,exception) != MagickFalse) + channels=image->alpha_trait == BlendPixelTrait ? 2 : 1; + else if (image->colorspace == CMYKColorspace) + channels=image->alpha_trait == BlendPixelTrait ? 5 : 4; + (void) WriteBlobLong(image,channels); + (void) WriteBlobLong(image,0); + if (image->depth == 16) + (void) WriteBlobLong(image,(unsigned int) VIPSBandFormatUSHORT); + else + { + image->depth=8; + (void) WriteBlobLong(image,(unsigned int) VIPSBandFormatUCHAR); + } + (void) WriteBlobLong(image,VIPSCodingNONE); + switch(image->colorspace) + { + case CMYKColorspace: + (void) WriteBlobLong(image,VIPSTypeCMYK); + break; + case GRAYColorspace: + if (image->depth == 16) + (void) WriteBlobLong(image, VIPSTypeGREY16); + else + (void) WriteBlobLong(image, VIPSTypeB_W); + break; + case LabColorspace: + (void) WriteBlobLong(image,VIPSTypeLAB); + break; + case LCHColorspace: + (void) WriteBlobLong(image,VIPSTypeLCH); + break; + case RGBColorspace: + if (image->depth == 16) + (void) WriteBlobLong(image, VIPSTypeRGB16); + else + (void) WriteBlobLong(image, VIPSTypeRGB); + break; + case XYZColorspace: + (void) WriteBlobLong(image,VIPSTypeXYZ); + break; + default: + case sRGBColorspace: + (void) SetImageColorspace(image,sRGBColorspace,exception); + (void) WriteBlobLong(image,VIPSTypesRGB); + break; + } + if (image->units == PixelsPerCentimeterResolution) + { + (void) WriteBlobFloat(image,(image->resolution.x / 10)); + (void) WriteBlobFloat(image,(image->resolution.y / 10)); + } + else if (image->units == PixelsPerInchResolution) + { + (void) WriteBlobFloat(image,(image->resolution.x / 25.4)); + (void) WriteBlobFloat(image,(image->resolution.y / 25.4)); + } + else + { + (void) WriteBlobLong(image,0); + (void) WriteBlobLong(image,0); + } + /* + Legacy, Offsets, Future + */ + for (y=0; y < 24; y++) + (void) WriteBlobByte(image,0); + for (y=0; y < (ssize_t) image->rows; y++) + { + p=GetVirtualPixels(image,0,y,image->columns,1,exception); + if (p == (const Quantum *) NULL) + break; + for (x=0; x < (ssize_t) image->columns; x++) + { + WriteVIPSPixel(image,GetPixelRed(image,p)); + if (channels == 2) + WriteVIPSPixel(image,GetPixelAlpha(image,p)); + else + { + WriteVIPSPixel(image,GetPixelGreen(image,p)); + WriteVIPSPixel(image,GetPixelBlue(image,p)); + if (channels >= 4) + { + if (image->colorspace == CMYKColorspace) + WriteVIPSPixel(image,GetPixelIndex(image,p)); + else + WriteVIPSPixel(image,GetPixelAlpha(image,p)); + } + else if (channels == 5) + { + WriteVIPSPixel(image,GetPixelIndex(image,p)); + WriteVIPSPixel(image,GetPixelAlpha(image,p)); + } + } + p+=GetPixelChannels(image); + } + } + metadata=GetImageProperty(image,"vips:metadata",exception); + if (metadata != (const char*) NULL) + WriteBlobString(image,metadata); + (void) CloseBlob(image); + return(status); +} -- 2.40.0