sfw.c revision 24ae22e90c1a7748b97a10e12572a9c27c713d32
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-2015 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/* 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 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(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 142static 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 157static 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 (void) close(unique_file); 330 buffer=(unsigned char *) RelinquishMagickMemory(buffer); 331 if (status == MagickFalse) 332 { 333 char 334 *message; 335 336 (void) remove_utf8(read_info->filename); 337 read_info=DestroyImageInfo(read_info); 338 message=GetExceptionMessage(errno); 339 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 340 "UnableToWriteFile","`%s': %s",image->filename,message); 341 message=DestroyString(message); 342 image=DestroyImageList(image); 343 return((Image *) NULL); 344 } 345 /* 346 Read JPEG image. 347 */ 348 jpeg_image=ReadImage(read_info,exception); 349 (void) RelinquishUniqueFileResource(read_info->filename); 350 read_info=DestroyImageInfo(read_info); 351 if (jpeg_image == (Image *) NULL) 352 { 353 image=DestroyImageList(image); 354 return(jpeg_image); 355 } 356 (void) CopyMagickString(jpeg_image->filename,image->filename,MaxTextExtent); 357 (void) CopyMagickString(jpeg_image->magick,image->magick,MaxTextExtent); 358 image=DestroyImageList(image); 359 image=jpeg_image; 360 /* 361 Correct image orientation. 362 */ 363 flipped_image=FlipImage(image,exception); 364 if (flipped_image != (Image *) NULL) 365 { 366 DuplicateBlob(flipped_image,image); 367 image=DestroyImage(image); 368 image=flipped_image; 369 } 370 return(GetFirstImageInList(image)); 371} 372 373/* 374%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 375% % 376% % 377% % 378% R e g i s t e r S F W I m a g e % 379% % 380% % 381% % 382%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 383% 384% RegisterSFWImage() adds attributes for the SFW image format to 385% the list of supported formats. The attributes include the image format 386% tag, a method to read and/or write the format, whether the format 387% supports the saving of more than one frame to the same file or blob, 388% whether the format supports native in-memory I/O, and a brief 389% description of the format. 390% 391% The format of the RegisterSFWImage method is: 392% 393% size_t RegisterSFWImage(void) 394% 395*/ 396ModuleExport size_t RegisterSFWImage(void) 397{ 398 MagickInfo 399 *entry; 400 401 entry=SetMagickInfo("SFW"); 402 entry->decoder=(DecodeImageHandler *) ReadSFWImage; 403 entry->magick=(IsImageFormatHandler *) IsSFW; 404 entry->flags^=Adjoin; 405 entry->description=ConstantString("Seattle Film Works"); 406 entry->module=ConstantString("SFW"); 407 (void) RegisterMagickInfo(entry); 408 return(MagickImageCoderSignature); 409} 410 411/* 412%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 413% % 414% % 415% % 416% U n r e g i s t e r S F W I m a g e % 417% % 418% % 419% % 420%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 421% 422% UnregisterSFWImage() removes format registrations made by the 423% SFW module from the list of supported formats. 424% 425% The format of the UnregisterSFWImage method is: 426% 427% UnregisterSFWImage(void) 428% 429*/ 430ModuleExport void UnregisterSFWImage(void) 431{ 432 (void) UnregisterMagickInfo("SFW"); 433} 434