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