blob: 25c32a0daf972ed7fde0ca263c50db2feb15f8a4 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% SSSSS FFFFF W W %
7% SS F W W %
8% SSS FFF W W %
9% SS F W W W %
10% SSSSS F W W %
11% %
12% %
13% Read/Write ImageMagick Image Format %
14% %
15% Software Design %
16% John Cristy %
17% July 1992 %
18% %
19% %
cristy16af1cb2009-12-11 21:38:29 +000020% Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
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. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37*/
38
39/*
40 Include declarations.
41*/
42#include "magick/studio.h"
43#include "magick/blob.h"
44#include "magick/blob-private.h"
45#include "magick/constitute.h"
46#include "magick/exception.h"
47#include "magick/exception-private.h"
48#include "magick/image.h"
49#include "magick/image-private.h"
50#include "magick/list.h"
51#include "magick/magick.h"
52#include "magick/memory_.h"
53#include "magick/resource_.h"
54#include "magick/quantum-private.h"
55#include "magick/static.h"
56#include "magick/string_.h"
57#include "magick/module.h"
58#include "magick/transform.h"
59#include "magick/utility.h"
60
61/*
62%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
63% %
64% %
65% %
66% I s S F W %
67% %
68% %
69% %
70%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
71%
72% IsSFW() returns MagickTrue if the image format type, identified by the
73% magick string, is SFW.
74%
75% The format of the IsSFW method is:
76%
77% MagickBooleanType IsSFW(const unsigned char *magick,const size_t length)
78%
79% A description of each parameter follows:
80%
81% o magick: compare image format pattern against these bytes.
82%
83% o length: Specifies the length of the magick string.
84%
85*/
86static MagickBooleanType IsSFW(const unsigned char *magick,const size_t length)
87{
88 if (length < 5)
89 return(MagickFalse);
90 if (LocaleNCompare((const char *) magick,"SFW94",5) == 0)
91 return(MagickTrue);
92 return(MagickFalse);
93}
94
95/*
96%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
97% %
98% %
99% %
100% R e a d S F W I m a g e %
101% %
102% %
103% %
104%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
105%
106% ReadSFWImage() reads a Seattle Film Works image file and returns it.
107% It allocates the memory necessary for the new Image structure and returns a
108% pointer to the new image.
109%
110% The format of the ReadSFWImage method is:
111%
112% Image *ReadSFWImage(const ImageInfo *image_info,ExceptionInfo *exception)
113%
114% A description of each parameter follows:
115%
116% o image_info: the image info.
117%
118% o exception: return any errors or warnings in this structure.
119%
120*/
121
122static unsigned char *SFWScan(unsigned char *p,const unsigned char *q,
123 const unsigned char *target,const int length)
124{
125 register long
126 i;
127
128 for ( ; p < q; p++)
129 {
130 if (*p != *target)
131 continue;
132 if (length == 1)
133 return(p);
134 for (i=1; i < length; i++)
135 if (*(p+i) != *(target+i))
136 break;
137 if (i == length)
138 return(p);
139 }
140 return((unsigned char *) NULL);
141}
142
143static void TranslateSFWMarker(unsigned char *marker)
144{
145 switch (marker[1])
146 {
147 case 0xc8: marker[1]=0xd8; break; /* soi */
148 case 0xd0: marker[1]=0xe0; break; /* app */
149 case 0xcb: marker[1]=0xdb; break; /* dqt */
150 case 0xa0: marker[1]=0xc0; break; /* sof */
151 case 0xa4: marker[1]=0xc4; break; /* sof */
152 case 0xca: marker[1]=0xda; break; /* sos */
153 case 0xc9: marker[1]=0xd9; break; /* eoi */
154 default: break;
155 }
156}
157
158static Image *ReadSFWImage(const ImageInfo *image_info,ExceptionInfo *exception)
159{
160 static unsigned char
161 HuffmanTable[] =
162 {
163 0xFF, 0xC4, 0x01, 0xA2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01,
164 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
165 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
166 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
167 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04,
168 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x10, 0x00, 0x02, 0x01,
169 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00,
170 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21,
171 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32,
172 0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1,
173 0xF0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18,
174 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36,
175 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
176 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64,
177 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77,
178 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A,
179 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3,
180 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5,
181 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
182 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9,
183 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA,
184 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0x11,
185 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04,
186 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04,
187 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13,
188 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09,
189 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24,
190 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28,
191 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45,
192 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
193 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73,
194 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85,
195 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
196 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9,
197 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2,
198 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4,
199 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
200 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
201 0xF9, 0xFA
202 };
203
204 FILE
205 *file;
206
207 Image
208 *flipped_image,
209 *image;
210
211 ImageInfo
212 *read_info;
213
214 int
215 unique_file;
216
217 MagickBooleanType
218 status;
219
220 register unsigned char
221 *header,
222 *data;
223
224 ssize_t
225 count;
226
227 unsigned char
228 *buffer,
229 *offset;
230
231 /*
232 Open image file.
233 */
234 assert(image_info != (const ImageInfo *) NULL);
235 assert(image_info->signature == MagickSignature);
236 if (image_info->debug != MagickFalse)
237 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
238 image_info->filename);
239 assert(exception != (ExceptionInfo *) NULL);
240 assert(exception->signature == MagickSignature);
241 image=AcquireImage(image_info);
242 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
243 if (status == MagickFalse)
244 {
245 image=DestroyImageList(image);
246 return((Image *) NULL);
247 }
248 /*
249 Read image into a buffer.
250 */
251 buffer=(unsigned char *) AcquireQuantumMemory((size_t) GetBlobSize(image),
252 sizeof(*buffer));
253 if (buffer == (unsigned char *) NULL)
254 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
255 count=ReadBlob(image,(size_t) GetBlobSize(image),buffer);
256 if ((count == 0) || (LocaleNCompare((char *) buffer,"SFW",3) != 0))
257 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
258 (void) CloseBlob(image);
259 image=DestroyImage(image);
260 /*
261 Find the start of the JFIF data
262 */
263 header=SFWScan(buffer,buffer+count-1,(const unsigned char *)
264 "\377\310\377\320",4);
265 if (header == (unsigned char *) NULL)
266 {
267 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
268 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
269 }
270 TranslateSFWMarker(header); /* translate soi and app tags */
271 TranslateSFWMarker(header+2);
272 (void) CopyMagickMemory(header+6,"JFIF\0\001\0",7); /* JFIF magic */
273 /*
274 Translate remaining markers.
275 */
276 offset=header+2;
277 offset+=(offset[2] << 8)+offset[3]+2;
278 for ( ; ; )
279 {
280 TranslateSFWMarker(offset);
281 if (offset[1] == 0xda)
282 break;
283 offset+=(offset[2] << 8)+offset[3]+2;
284 }
285 offset--;
286 data=SFWScan(offset,buffer+count-1,(const unsigned char *) "\377\311",2);
287 if (data == (unsigned char *) NULL)
288 {
289 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
290 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
291 }
292 TranslateSFWMarker(data++); /* translate eoi marker */
293 /*
294 Write JFIF file.
295 */
296 read_info=CloneImageInfo(image_info);
297 read_info->blob=(void *) NULL;
298 read_info->length=0;
299 file=(FILE *) NULL;
300 unique_file=AcquireUniqueFileResource(read_info->filename);
301 if (unique_file != -1)
302 file=OpenMagickStream(read_info->filename,"wb");
303 if ((unique_file == -1) || (file == (FILE *) NULL))
304 {
305 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
306 read_info=DestroyImageInfo(read_info);
307 (void) CopyMagickString(image->filename,read_info->filename,
308 MaxTextExtent);
309 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
310 image->filename);
311 image=DestroyImageList(image);
312 return((Image *) NULL);
313 }
314 (void) fwrite(header,(size_t) (offset-header+1),1,file);
315 (void) fwrite(HuffmanTable,1,sizeof(HuffmanTable)/sizeof(*HuffmanTable),file);
316 (void) fwrite(offset+1,(size_t) (data-offset),1,file);
317 status=ferror(file) == -1 ? MagickFalse : MagickTrue;
318 (void) fclose(file);
319 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
320 if (status == MagickFalse)
321 {
322 char
323 *message;
324
325 (void) remove(read_info->filename);
326 read_info=DestroyImageInfo(read_info);
327 message=GetExceptionMessage(errno);
328 (void) ThrowMagickException(&image->exception,GetMagickModule(),
329 FileOpenError,"UnableToWriteFile","`%s': %s",image->filename,message);
330 message=DestroyString(message);
331 image=DestroyImageList(image);
332 return((Image *) NULL);
333 }
334 /*
335 Read JPEG image.
336 */
337 image=ReadImage(read_info,exception);
338 (void) RelinquishUniqueFileResource(read_info->filename);
339 read_info=DestroyImageInfo(read_info);
340 if (image == (Image *) NULL)
341 return(GetFirstImageInList(image));
342 /*
343 Correct image orientation.
344 */
345 flipped_image=FlipImage(image,exception);
346 if (flipped_image == (Image *) NULL)
347 return(GetFirstImageInList(image));
348 DuplicateBlob(flipped_image,image);
349 image=DestroyImage(image);
350 return(flipped_image);
351}
352
353/*
354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
355% %
356% %
357% %
358% R e g i s t e r S F W I m a g e %
359% %
360% %
361% %
362%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
363%
364% RegisterSFWImage() adds attributes for the SFW image format to
365% the list of supported formats. The attributes include the image format
366% tag, a method to read and/or write the format, whether the format
367% supports the saving of more than one frame to the same file or blob,
368% whether the format supports native in-memory I/O, and a brief
369% description of the format.
370%
371% The format of the RegisterSFWImage method is:
372%
373% unsigned long RegisterSFWImage(void)
374%
375*/
376ModuleExport unsigned long RegisterSFWImage(void)
377{
378 MagickInfo
379 *entry;
380
381 entry=SetMagickInfo("SFW");
382 entry->decoder=(DecodeImageHandler *) ReadSFWImage;
383 entry->magick=(IsImageFormatHandler *) IsSFW;
384 entry->adjoin=MagickFalse;
385 entry->description=ConstantString("Seattle Film Works");
386 entry->module=ConstantString("SFW");
387 (void) RegisterMagickInfo(entry);
388 return(MagickImageCoderSignature);
389}
390
391/*
392%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
393% %
394% %
395% %
396% U n r e g i s t e r S F W I m a g e %
397% %
398% %
399% %
400%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
401%
402% UnregisterSFWImage() removes format registrations made by the
403% SFW module from the list of supported formats.
404%
405% The format of the UnregisterSFWImage method is:
406%
407% UnregisterSFWImage(void)
408%
409*/
410ModuleExport void UnregisterSFWImage(void)
411{
412 (void) UnregisterMagickInfo("SFW");
413}