]> granicus.if.org Git - imagemagick/blob - coders/sfw.c
The PNG encoder sometimes would write indexed PNG when grayscale was reqested.
[imagemagick] / coders / sfw.c
1 /*
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 %                                                                             %
20 %  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
21 %  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 \f
39 /*
40   Include declarations.
41 */
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"
61 \f
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 */
87 static 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 \f
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
123 static unsigned char *SFWScan(const unsigned char *p,const unsigned char *q,
124   const unsigned char *target,const size_t length)
125 {
126   register ssize_t
127     i;
128
129   if ((p+length) < q)
130     while (p < q)
131     {
132       for (i=0; i < (ssize_t) length; i++)
133         if (p[i] != target[i])
134           break;
135       if (i == (ssize_t) length)
136         return((unsigned char *) p);
137       p++;
138     }
139   return((unsigned char *) NULL);
140 }
141
142 static void TranslateSFWMarker(unsigned char *marker)
143 {
144   switch (marker[1])
145   {
146     case 0xc8: marker[1]=0xd8; break;  /* soi */
147     case 0xd0: marker[1]=0xe0; break;  /* app */
148     case 0xcb: marker[1]=0xdb; break;  /* dqt */
149     case 0xa0: marker[1]=0xc0; break;  /* sof */
150     case 0xa4: marker[1]=0xc4; break;  /* sof */
151     case 0xca: marker[1]=0xda; break;  /* sos */
152     case 0xc9: marker[1]=0xd9; break;  /* eoi */
153     default: break;
154   }
155 }
156
157 static Image *ReadSFWImage(const ImageInfo *image_info,ExceptionInfo *exception)
158 {
159   static unsigned char
160     HuffmanTable[] =
161     {
162       0xFF, 0xC4, 0x01, 0xA2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01,
163       0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
164       0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
165       0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
166       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04,
167       0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x10, 0x00, 0x02, 0x01,
168       0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00,
169       0x01, 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21,
170       0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32,
171       0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1,
172       0xF0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18,
173       0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36,
174       0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
175       0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64,
176       0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77,
177       0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A,
178       0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3,
179       0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5,
180       0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
181       0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9,
182       0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA,
183       0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0x11,
184       0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04,
185       0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04,
186       0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13,
187       0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09,
188       0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24,
189       0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28,
190       0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45,
191       0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
192       0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73,
193       0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85,
194       0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
195       0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9,
196       0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2,
197       0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4,
198       0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
199       0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
200       0xF9, 0xFA
201     };
202
203   FILE
204     *file;
205
206   Image
207     *flipped_image,
208     *jpeg_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   size_t
225     extent;
226
227   ssize_t
228     count;
229
230   unsigned char
231     *buffer,
232     *offset;
233
234   /*
235     Open image file.
236   */
237   assert(image_info != (const ImageInfo *) NULL);
238   assert(image_info->signature == MagickSignature);
239   if (image_info->debug != MagickFalse)
240     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
241       image_info->filename);
242   assert(exception != (ExceptionInfo *) NULL);
243   assert(exception->signature == MagickSignature);
244   image=AcquireImage(image_info,exception);
245   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
246   if (status == MagickFalse)
247     {
248       image=DestroyImageList(image);
249       return((Image *) NULL);
250     }
251   /*
252     Read image into a buffer.
253   */
254   if (GetBlobSize(image) != (size_t) GetBlobSize(image))
255     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
256   buffer=(unsigned char *) AcquireQuantumMemory((size_t) GetBlobSize(image),
257     sizeof(*buffer));
258   if (buffer == (unsigned char *) NULL)
259     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
260   count=ReadBlob(image,(size_t) GetBlobSize(image),buffer);
261   if ((count != (ssize_t) GetBlobSize(image)) ||
262       (LocaleNCompare((char *) buffer,"SFW",3) != 0))
263     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
264   (void) CloseBlob(image);
265   /*
266     Find the start of the JFIF data
267   */
268   header=SFWScan(buffer,buffer+count-1,(const unsigned char *)
269     "\377\310\377\320",4);
270   if (header == (unsigned char *) NULL)
271     {
272       buffer=(unsigned char *) RelinquishMagickMemory(buffer);
273       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
274     }
275   TranslateSFWMarker(header);  /* translate soi and app tags */
276   TranslateSFWMarker(header+2);
277   (void) CopyMagickMemory(header+6,"JFIF\0\001\0",7);  /* JFIF magic */
278   /*
279     Translate remaining markers.
280   */
281   offset=header+2;
282   offset+=(((unsigned int) offset[2]) << 8)+offset[3]+2;
283   for ( ; ; )
284   {
285     if ((offset+4) > (buffer+count-1))
286       {
287         buffer=(unsigned char *) RelinquishMagickMemory(buffer);
288         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
289       }
290     TranslateSFWMarker(offset);
291     if (offset[1] == 0xda)
292       break;
293     offset+=(((unsigned int) offset[2]) << 8)+offset[3]+2;
294   }
295   offset--;
296   data=SFWScan(offset,buffer+count-1,(const unsigned char *) "\377\311",2);
297   if (data == (unsigned char *) NULL)
298     {
299       buffer=(unsigned char *) RelinquishMagickMemory(buffer);
300       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
301     }
302   TranslateSFWMarker(data++);  /* translate eoi marker */
303   /*
304     Write JFIF file.
305   */
306   read_info=CloneImageInfo(image_info);
307   SetImageInfoBlob(read_info,(void *) NULL,0);
308   file=(FILE *) NULL;
309   unique_file=AcquireUniqueFileResource(read_info->filename);
310   if (unique_file != -1)
311     file=fopen_utf8(read_info->filename,"wb");
312   if ((unique_file == -1) || (file == (FILE *) NULL))
313     {
314       buffer=(unsigned char *) RelinquishMagickMemory(buffer);
315       read_info=DestroyImageInfo(read_info);
316       (void) CopyMagickString(image->filename,read_info->filename,
317         MaxTextExtent);
318       ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
319         image->filename);
320       image=DestroyImageList(image);
321       return((Image *) NULL);
322     }
323   extent=fwrite(header,(size_t) (offset-header+1),1,file);
324   (void) extent;
325   extent=fwrite(HuffmanTable,1,sizeof(HuffmanTable)/sizeof(*HuffmanTable),file);
326   extent=fwrite(offset+1,(size_t) (data-offset),1,file);
327   status=ferror(file) == -1 ? MagickFalse : MagickTrue;
328   (void) fclose(file);
329   buffer=(unsigned char *) RelinquishMagickMemory(buffer);
330   if (status == MagickFalse)
331     {
332       char
333         *message;
334
335       (void) remove_utf8(read_info->filename);
336       read_info=DestroyImageInfo(read_info);
337       message=GetExceptionMessage(errno);
338       (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
339         "UnableToWriteFile","`%s': %s",image->filename,message);
340       message=DestroyString(message);
341       image=DestroyImageList(image);
342       return((Image *) NULL);
343     }
344   /*
345     Read JPEG image.
346   */
347   jpeg_image=ReadImage(read_info,exception);
348   (void) RelinquishUniqueFileResource(read_info->filename);
349   read_info=DestroyImageInfo(read_info);
350   if (jpeg_image == (Image *) NULL)
351     {
352       image=DestroyImageList(image);
353       return(jpeg_image);
354     }
355   (void) CopyMagickString(jpeg_image->filename,image->filename,MaxTextExtent);
356   (void) CopyMagickString(jpeg_image->magick,image->magick,MaxTextExtent);
357   image=DestroyImageList(image);
358   image=jpeg_image;
359   /*
360     Correct image orientation.
361   */
362   flipped_image=FlipImage(image,exception);
363   if (flipped_image != (Image *) NULL)
364     {
365       DuplicateBlob(flipped_image,image);
366       image=DestroyImage(image);
367       image=flipped_image;
368     }
369   return(GetFirstImageInList(image));
370 }
371 \f
372 /*
373 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
374 %                                                                             %
375 %                                                                             %
376 %                                                                             %
377 %   R e g i s t e r S F W I m a g e                                           %
378 %                                                                             %
379 %                                                                             %
380 %                                                                             %
381 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
382 %
383 %  RegisterSFWImage() adds attributes for the SFW image format to
384 %  the list of supported formats.  The attributes include the image format
385 %  tag, a method to read and/or write the format, whether the format
386 %  supports the saving of more than one frame to the same file or blob,
387 %  whether the format supports native in-memory I/O, and a brief
388 %  description of the format.
389 %
390 %  The format of the RegisterSFWImage method is:
391 %
392 %      size_t RegisterSFWImage(void)
393 %
394 */
395 ModuleExport size_t RegisterSFWImage(void)
396 {
397   MagickInfo
398     *entry;
399
400   entry=SetMagickInfo("SFW");
401   entry->decoder=(DecodeImageHandler *) ReadSFWImage;
402   entry->magick=(IsImageFormatHandler *) IsSFW;
403   entry->adjoin=MagickFalse;
404   entry->description=ConstantString("Seattle Film Works");
405   entry->module=ConstantString("SFW");
406   (void) RegisterMagickInfo(entry);
407   return(MagickImageCoderSignature);
408 }
409 \f
410 /*
411 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
412 %                                                                             %
413 %                                                                             %
414 %                                                                             %
415 %   U n r e g i s t e r S F W I m a g e                                       %
416 %                                                                             %
417 %                                                                             %
418 %                                                                             %
419 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
420 %
421 %  UnregisterSFWImage() removes format registrations made by the
422 %  SFW module from the list of supported formats.
423 %
424 %  The format of the UnregisterSFWImage method is:
425 %
426 %      UnregisterSFWImage(void)
427 %
428 */
429 ModuleExport void UnregisterSFWImage(void)
430 {
431   (void) UnregisterMagickInfo("SFW");
432 }