2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write ImageMagick Image Format %
20 % Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
42 #include "MagickCore/studio.h"
43 #include "MagickCore/blob.h"
44 #include "MagickCore/blob-private.h"
45 #include "MagickCore/constitute.h"
46 #include "MagickCore/exception.h"
47 #include "MagickCore/exception-private.h"
48 #include "MagickCore/image.h"
49 #include "MagickCore/image-private.h"
50 #include "MagickCore/list.h"
51 #include "MagickCore/magick.h"
52 #include "MagickCore/memory_.h"
53 #include "MagickCore/resource_.h"
54 #include "MagickCore/quantum-private.h"
55 #include "MagickCore/static.h"
56 #include "MagickCore/string_.h"
57 #include "MagickCore/module.h"
58 #include "MagickCore/transform.h"
59 #include "MagickCore/utility.h"
60 #include "MagickCore/utility-private.h"
63 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
71 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
73 % IsSFW() returns MagickTrue if the image format type, identified by the
74 % magick string, is SFW.
76 % The format of the IsSFW method is:
78 % MagickBooleanType IsSFW(const unsigned char *magick,const size_t length)
80 % A description of each parameter follows:
82 % o magick: compare image format pattern against these bytes.
84 % o length: Specifies the length of the magick string.
87 static MagickBooleanType IsSFW(const unsigned char *magick,const size_t length)
91 if (LocaleNCompare((const char *) magick,"SFW94",5) == 0)
97 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
101 % R e a d S F W I m a g e %
105 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
107 % ReadSFWImage() reads a Seattle Film Works image file and returns it.
108 % It allocates the memory necessary for the new Image structure and returns a
109 % pointer to the new image.
111 % The format of the ReadSFWImage method is:
113 % Image *ReadSFWImage(const ImageInfo *image_info,ExceptionInfo *exception)
115 % A description of each parameter follows:
117 % o image_info: the image info.
119 % o exception: return any errors or warnings in this structure.
123 static unsigned char *SFWScan(unsigned char *p,const unsigned char *q,
124 const unsigned char *target,const int length)
135 for (i=1; i < length; i++)
136 if (*(p+i) != *(target+i))
141 return((unsigned char *) NULL);
144 static void TranslateSFWMarker(unsigned char *marker)
148 case 0xc8: marker[1]=0xd8; break; /* soi */
149 case 0xd0: marker[1]=0xe0; break; /* app */
150 case 0xcb: marker[1]=0xdb; break; /* dqt */
151 case 0xa0: marker[1]=0xc0; break; /* sof */
152 case 0xa4: marker[1]=0xc4; break; /* sof */
153 case 0xca: marker[1]=0xda; break; /* sos */
154 case 0xc9: marker[1]=0xd9; break; /* eoi */
159 static Image *ReadSFWImage(const ImageInfo *image_info,ExceptionInfo *exception)
164 0xFF, 0xC4, 0x01, 0xA2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01,
165 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
166 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
167 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
168 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04,
169 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x10, 0x00, 0x02, 0x01,
170 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00,
171 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21,
172 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32,
173 0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1,
174 0xF0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18,
175 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36,
176 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
177 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64,
178 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77,
179 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A,
180 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3,
181 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5,
182 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
183 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9,
184 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA,
185 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0x11,
186 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04,
187 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04,
188 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13,
189 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09,
190 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24,
191 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28,
192 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45,
193 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
194 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73,
195 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85,
196 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
197 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9,
198 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2,
199 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4,
200 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
201 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
221 register unsigned char
238 assert(image_info != (const ImageInfo *) NULL);
239 assert(image_info->signature == MagickSignature);
240 if (image_info->debug != MagickFalse)
241 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
242 image_info->filename);
243 assert(exception != (ExceptionInfo *) NULL);
244 assert(exception->signature == MagickSignature);
245 image=AcquireImage(image_info,exception);
246 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
247 if (status == MagickFalse)
249 image=DestroyImageList(image);
250 return((Image *) NULL);
253 Read image into a buffer.
255 buffer=(unsigned char *) AcquireQuantumMemory((size_t) GetBlobSize(image),
257 if (buffer == (unsigned char *) NULL)
258 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
259 count=ReadBlob(image,(size_t) GetBlobSize(image),buffer);
260 if ((count == 0) || (LocaleNCompare((char *) buffer,"SFW",3) != 0))
261 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
262 (void) CloseBlob(image);
263 image=DestroyImage(image);
265 Find the start of the JFIF data
267 header=SFWScan(buffer,buffer+count-1,(const unsigned char *)
268 "\377\310\377\320",4);
269 if (header == (unsigned char *) NULL)
271 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
272 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
274 TranslateSFWMarker(header); /* translate soi and app tags */
275 TranslateSFWMarker(header+2);
276 (void) CopyMagickMemory(header+6,"JFIF\0\001\0",7); /* JFIF magic */
278 Translate remaining markers.
281 offset+=(offset[2] << 8)+offset[3]+2;
284 TranslateSFWMarker(offset);
285 if (offset[1] == 0xda)
287 offset+=(offset[2] << 8)+offset[3]+2;
290 data=SFWScan(offset,buffer+count-1,(const unsigned char *) "\377\311",2);
291 if (data == (unsigned char *) NULL)
293 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
294 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
296 TranslateSFWMarker(data++); /* translate eoi marker */
300 read_info=CloneImageInfo(image_info);
301 SetImageInfoBlob(read_info,(void *) NULL,0);
303 unique_file=AcquireUniqueFileResource(read_info->filename);
304 if (unique_file != -1)
305 file=fopen_utf8(read_info->filename,"wb");
306 if ((unique_file == -1) || (file == (FILE *) NULL))
308 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
309 read_info=DestroyImageInfo(read_info);
310 (void) CopyMagickString(image->filename,read_info->filename,
312 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
314 image=DestroyImageList(image);
315 return((Image *) NULL);
317 extent=fwrite(header,(size_t) (offset-header+1),1,file);
319 extent=fwrite(HuffmanTable,1,sizeof(HuffmanTable)/sizeof(*HuffmanTable),file);
320 extent=fwrite(offset+1,(size_t) (data-offset),1,file);
321 status=ferror(file) == -1 ? MagickFalse : MagickTrue;
323 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
324 if (status == MagickFalse)
329 (void) remove_utf8(read_info->filename);
330 read_info=DestroyImageInfo(read_info);
331 message=GetExceptionMessage(errno);
332 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
333 "UnableToWriteFile","`%s': %s",image->filename,message);
334 message=DestroyString(message);
335 image=DestroyImageList(image);
336 return((Image *) NULL);
341 image=ReadImage(read_info,exception);
342 (void) RelinquishUniqueFileResource(read_info->filename);
343 read_info=DestroyImageInfo(read_info);
344 if (image == (Image *) NULL)
345 return(GetFirstImageInList(image));
347 Correct image orientation.
349 flipped_image=FlipImage(image,exception);
350 if (flipped_image != (Image *) NULL)
352 DuplicateBlob(flipped_image,image);
353 image=DestroyImage(image);
356 return(GetFirstImageInList(image));
360 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
364 % R e g i s t e r S F W I m a g e %
368 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
370 % RegisterSFWImage() adds attributes for the SFW image format to
371 % the list of supported formats. The attributes include the image format
372 % tag, a method to read and/or write the format, whether the format
373 % supports the saving of more than one frame to the same file or blob,
374 % whether the format supports native in-memory I/O, and a brief
375 % description of the format.
377 % The format of the RegisterSFWImage method is:
379 % size_t RegisterSFWImage(void)
382 ModuleExport size_t RegisterSFWImage(void)
387 entry=SetMagickInfo("SFW");
388 entry->decoder=(DecodeImageHandler *) ReadSFWImage;
389 entry->magick=(IsImageFormatHandler *) IsSFW;
390 entry->adjoin=MagickFalse;
391 entry->description=ConstantString("Seattle Film Works");
392 entry->module=ConstantString("SFW");
393 (void) RegisterMagickInfo(entry);
394 return(MagickImageCoderSignature);
398 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
402 % U n r e g i s t e r S F W I m a g e %
406 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
408 % UnregisterSFWImage() removes format registrations made by the
409 % SFW module from the list of supported formats.
411 % The format of the UnregisterSFWImage method is:
413 % UnregisterSFWImage(void)
416 ModuleExport void UnregisterSFWImage(void)
418 (void) UnregisterMagickInfo("SFW");