blob: d23bf4727ee521a47a2c570c34b0e9a210a86995 [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% %
cristy1454be72011-12-19 01:52:48 +000020% Copyright 1999-2012 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*/
cristy4c08aed2011-07-01 19:47:50 +000042#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"
cristy18c6c272011-09-23 14:40:37 +000060#include "MagickCore/utility-private.h"
cristy3ed852e2009-09-05 21:47:34 +000061
62/*
63%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
64% %
65% %
66% %
67% I s S F W %
68% %
69% %
70% %
71%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
72%
73% IsSFW() returns MagickTrue if the image format type, identified by the
74% magick string, is SFW.
75%
76% The format of the IsSFW method is:
77%
78% MagickBooleanType IsSFW(const unsigned char *magick,const size_t length)
79%
80% A description of each parameter follows:
81%
82% o magick: compare image format pattern against these bytes.
83%
84% o length: Specifies the length of the magick string.
85%
86*/
87static MagickBooleanType IsSFW(const unsigned char *magick,const size_t length)
88{
89 if (length < 5)
90 return(MagickFalse);
91 if (LocaleNCompare((const char *) magick,"SFW94",5) == 0)
92 return(MagickTrue);
93 return(MagickFalse);
94}
95
96/*
97%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
98% %
99% %
100% %
101% R e a d S F W I m a g e %
102% %
103% %
104% %
105%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
106%
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.
110%
111% The format of the ReadSFWImage method is:
112%
113% Image *ReadSFWImage(const ImageInfo *image_info,ExceptionInfo *exception)
114%
115% A description of each parameter follows:
116%
117% o image_info: the image info.
118%
119% o exception: return any errors or warnings in this structure.
120%
121*/
122
123static unsigned char *SFWScan(unsigned char *p,const unsigned char *q,
124 const unsigned char *target,const int length)
125{
cristybb503372010-05-27 20:51:26 +0000126 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000127 i;
128
129 for ( ; p < q; p++)
130 {
131 if (*p != *target)
132 continue;
133 if (length == 1)
134 return(p);
135 for (i=1; i < length; i++)
136 if (*(p+i) != *(target+i))
137 break;
138 if (i == length)
139 return(p);
140 }
141 return((unsigned char *) NULL);
142}
143
144static void TranslateSFWMarker(unsigned char *marker)
145{
146 switch (marker[1])
147 {
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 */
155 default: break;
156 }
157}
158
159static Image *ReadSFWImage(const ImageInfo *image_info,ExceptionInfo *exception)
160{
161 static unsigned char
162 HuffmanTable[] =
163 {
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,
202 0xF9, 0xFA
203 };
204
205 FILE
206 *file;
207
208 Image
209 *flipped_image,
210 *image;
211
212 ImageInfo
213 *read_info;
214
215 int
216 unique_file;
217
218 MagickBooleanType
219 status;
220
221 register unsigned char
222 *header,
223 *data;
224
cristy95236b52009-12-30 21:56:45 +0000225 size_t
226 extent;
227
cristy3ed852e2009-09-05 21:47:34 +0000228 ssize_t
229 count;
230
231 unsigned char
232 *buffer,
233 *offset;
234
235 /*
236 Open image file.
237 */
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);
cristy9950d572011-10-01 18:22:35 +0000245 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000246 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
247 if (status == MagickFalse)
248 {
249 image=DestroyImageList(image);
250 return((Image *) NULL);
251 }
252 /*
253 Read image into a buffer.
254 */
255 buffer=(unsigned char *) AcquireQuantumMemory((size_t) GetBlobSize(image),
256 sizeof(*buffer));
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);
264 /*
265 Find the start of the JFIF data
266 */
267 header=SFWScan(buffer,buffer+count-1,(const unsigned char *)
268 "\377\310\377\320",4);
269 if (header == (unsigned char *) NULL)
270 {
271 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
272 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
273 }
274 TranslateSFWMarker(header); /* translate soi and app tags */
275 TranslateSFWMarker(header+2);
276 (void) CopyMagickMemory(header+6,"JFIF\0\001\0",7); /* JFIF magic */
277 /*
278 Translate remaining markers.
279 */
280 offset=header+2;
281 offset+=(offset[2] << 8)+offset[3]+2;
282 for ( ; ; )
283 {
284 TranslateSFWMarker(offset);
285 if (offset[1] == 0xda)
286 break;
287 offset+=(offset[2] << 8)+offset[3]+2;
288 }
289 offset--;
290 data=SFWScan(offset,buffer+count-1,(const unsigned char *) "\377\311",2);
291 if (data == (unsigned char *) NULL)
292 {
293 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
294 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
295 }
296 TranslateSFWMarker(data++); /* translate eoi marker */
297 /*
298 Write JFIF file.
299 */
300 read_info=CloneImageInfo(image_info);
cristy98f91ec2011-02-03 01:15:48 +0000301 SetImageInfoBlob(read_info,(void *) NULL,0);
cristy3ed852e2009-09-05 21:47:34 +0000302 file=(FILE *) NULL;
303 unique_file=AcquireUniqueFileResource(read_info->filename);
304 if (unique_file != -1)
cristy18c6c272011-09-23 14:40:37 +0000305 file=fopen_utf8(read_info->filename,"wb");
cristy3ed852e2009-09-05 21:47:34 +0000306 if ((unique_file == -1) || (file == (FILE *) NULL))
307 {
308 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
309 read_info=DestroyImageInfo(read_info);
310 (void) CopyMagickString(image->filename,read_info->filename,
311 MaxTextExtent);
312 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
313 image->filename);
314 image=DestroyImageList(image);
315 return((Image *) NULL);
316 }
cristy95236b52009-12-30 21:56:45 +0000317 extent=fwrite(header,(size_t) (offset-header+1),1,file);
cristyda16f162011-02-19 23:52:17 +0000318 (void) extent;
cristy95236b52009-12-30 21:56:45 +0000319 extent=fwrite(HuffmanTable,1,sizeof(HuffmanTable)/sizeof(*HuffmanTable),file);
320 extent=fwrite(offset+1,(size_t) (data-offset),1,file);
cristy3ed852e2009-09-05 21:47:34 +0000321 status=ferror(file) == -1 ? MagickFalse : MagickTrue;
322 (void) fclose(file);
323 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
324 if (status == MagickFalse)
325 {
326 char
327 *message;
328
cristy18c6c272011-09-23 14:40:37 +0000329 (void) remove_utf8(read_info->filename);
cristy3ed852e2009-09-05 21:47:34 +0000330 read_info=DestroyImageInfo(read_info);
331 message=GetExceptionMessage(errno);
cristyc82a27b2011-10-21 01:07:16 +0000332 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
333 "UnableToWriteFile","`%s': %s",image->filename,message);
cristy3ed852e2009-09-05 21:47:34 +0000334 message=DestroyString(message);
335 image=DestroyImageList(image);
336 return((Image *) NULL);
337 }
338 /*
339 Read JPEG image.
340 */
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));
346 /*
347 Correct image orientation.
348 */
349 flipped_image=FlipImage(image,exception);
cristybbfd4cd2010-04-13 21:54:39 +0000350 if (flipped_image != (Image *) NULL)
351 {
352 DuplicateBlob(flipped_image,image);
353 image=DestroyImage(image);
354 image=flipped_image;
355 }
356 return(GetFirstImageInList(image));
cristy3ed852e2009-09-05 21:47:34 +0000357}
358
359/*
360%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
361% %
362% %
363% %
364% R e g i s t e r S F W I m a g e %
365% %
366% %
367% %
368%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
369%
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.
376%
377% The format of the RegisterSFWImage method is:
378%
cristybb503372010-05-27 20:51:26 +0000379% size_t RegisterSFWImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000380%
381*/
cristybb503372010-05-27 20:51:26 +0000382ModuleExport size_t RegisterSFWImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000383{
384 MagickInfo
385 *entry;
386
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);
395}
396
397/*
398%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
399% %
400% %
401% %
402% U n r e g i s t e r S F W I m a g e %
403% %
404% %
405% %
406%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
407%
408% UnregisterSFWImage() removes format registrations made by the
409% SFW module from the list of supported formats.
410%
411% The format of the UnregisterSFWImage method is:
412%
413% UnregisterSFWImage(void)
414%
415*/
416ModuleExport void UnregisterSFWImage(void)
417{
418 (void) UnregisterMagickInfo("SFW");
419}