1 /* 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 % % 4 % % 5 % % 6 % SSSSS U U N N % 7 % SS U U NN N % 8 % SSS U U N N N % 9 % SS U U N NN % 10 % SSSSS UUU N N % 11 % % 12 % % 13 % Read/Write Sun Rasterfile Image Format % 14 % % 15 % Software Design % 16 % Cristy % 17 % July 1992 % 18 % % 19 % % 20 % Copyright 1999-2019 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 % https://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/attribute.h" 45 #include "MagickCore/blob.h" 46 #include "MagickCore/blob-private.h" 47 #include "MagickCore/cache.h" 48 #include "MagickCore/color.h" 49 #include "MagickCore/color-private.h" 50 #include "MagickCore/colormap.h" 51 #include "MagickCore/colormap-private.h" 52 #include "MagickCore/colorspace.h" 53 #include "MagickCore/colorspace-private.h" 54 #include "MagickCore/exception.h" 55 #include "MagickCore/exception-private.h" 56 #include "MagickCore/image.h" 57 #include "MagickCore/image-private.h" 58 #include "MagickCore/list.h" 59 #include "MagickCore/magick.h" 60 #include "MagickCore/memory_.h" 61 #include "MagickCore/memory-private.h" 62 #include "MagickCore/monitor.h" 63 #include "MagickCore/monitor-private.h" 64 #include "MagickCore/pixel-accessor.h" 65 #include "MagickCore/quantum-private.h" 66 #include "MagickCore/static.h" 67 #include "MagickCore/string_.h" 68 #include "MagickCore/module.h" 69 70 /* 72 Forward declarations. 73 */ 74 static MagickBooleanType 75 WriteSUNImage(const ImageInfo *,Image *,ExceptionInfo *); 76 77 /* 79 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 80 % % 81 % % 82 % % 83 % I s S U N % 84 % % 85 % % 86 % % 87 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 88 % 89 % IsSUN() returns MagickTrue if the image format type, identified by the 90 % magick string, is SUN. 91 % 92 % The format of the IsSUN method is: 93 % 94 % MagickBooleanType IsSUN(const unsigned char *magick,const size_t length) 95 % 96 % A description of each parameter follows: 97 % 98 % o magick: compare image format pattern against these bytes. 99 % 100 % o length: Specifies the length of the magick string. 101 % 102 */ 103 static MagickBooleanType IsSUN(const unsigned char *magick,const size_t length) 104 { 105 if (length < 4) 106 return(MagickFalse); 107 if (memcmp(magick,"\131\246\152\225",4) == 0) 108 return(MagickTrue); 109 return(MagickFalse); 110 } 111 112 /* 114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 115 % % 116 % % 117 % % 118 % D e c o d e I m a g e % 119 % % 120 % % 121 % % 122 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 123 % 124 % DecodeImage unpacks the packed image pixels into runlength-encoded pixel 125 % packets. 126 % 127 % The format of the DecodeImage method is: 128 % 129 % MagickBooleanType DecodeImage(const unsigned char *compressed_pixels, 130 % const size_t length,unsigned char *pixels) 131 % 132 % A description of each parameter follows: 133 % 134 % o compressed_pixels: The address of a byte (8 bits) array of compressed 135 % pixel data. 136 % 137 % o length: An integer value that is the total number of bytes of the 138 % source image (as just read by ReadBlob) 139 % 140 % o pixels: The address of a byte (8 bits) array of pixel data created by 141 % the uncompression process. The number of bytes in this array 142 % must be at least equal to the number columns times the number of rows 143 % of the source pixels. 144 % 145 */ 146 static MagickBooleanType DecodeImage(const unsigned char *compressed_pixels, 147 const size_t length,unsigned char *pixels,size_t extent) 148 { 149 register const unsigned char 150 *p; 151 152 register unsigned char 153 *q; 154 155 ssize_t 156 count; 157 158 unsigned char 159 byte; 160 161 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 162 assert(compressed_pixels != (unsigned char *) NULL); 163 assert(pixels != (unsigned char *) NULL); 164 p=compressed_pixels; 165 q=pixels; 166 while (((size_t) (p-compressed_pixels) < length) && 167 ((size_t) (q-pixels) < extent)) 168 { 169 byte=(*p++); 170 if (byte != 128U) 171 *q++=byte; 172 else 173 { 174 /* 175 Runlength-encoded packet: <count><byte>. 176 */ 177 if (((size_t) (p-compressed_pixels) >= length)) 178 break; 179 count=(*p++); 180 if (count > 0) 181 { 182 if (((size_t) (p-compressed_pixels) >= length)) 183 break; 184 byte=(*p++); 185 } 186 while ((count >= 0) && ((size_t) (q-pixels) < extent)) 187 { 188 *q++=byte; 189 count--; 190 } 191 } 192 } 193 return(((size_t) (q-pixels) == extent) ? MagickTrue : MagickFalse); 194 } 195 196 /* 198 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 199 % % 200 % % 201 % % 202 % R e a d S U N I m a g e % 203 % % 204 % % 205 % % 206 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 207 % 208 % ReadSUNImage() reads a SUN image file and returns it. It allocates 209 % the memory necessary for the new Image structure and returns a pointer to 210 % the new image. 211 % 212 % The format of the ReadSUNImage method is: 213 % 214 % Image *ReadSUNImage(const ImageInfo *image_info,ExceptionInfo *exception) 215 % 216 % A description of each parameter follows: 217 % 218 % o image_info: the image info. 219 % 220 % o exception: return any errors or warnings in this structure. 221 % 222 */ 223 static Image *ReadSUNImage(const ImageInfo *image_info,ExceptionInfo *exception) 224 { 225 #define RMT_EQUAL_RGB 1 226 #define RMT_NONE 0 227 #define RMT_RAW 2 228 #define RT_STANDARD 1 229 #define RT_ENCODED 2 230 #define RT_FORMAT_RGB 3 231 232 typedef struct _SUNInfo 233 { 234 unsigned int 235 magic, 236 width, 237 height, 238 depth, 239 length, 240 type, 241 maptype, 242 maplength; 243 } SUNInfo; 244 245 Image 246 *image; 247 248 int 249 bit; 250 251 MagickBooleanType 252 status; 253 254 MagickSizeType 255 number_pixels; 256 257 register Quantum 258 *q; 259 260 register ssize_t 261 i, 262 x; 263 264 register unsigned char 265 *p; 266 267 size_t 268 bytes_per_line, 269 extent, 270 height, 271 pixels_length, 272 quantum; 273 274 ssize_t 275 count, 276 y; 277 278 SUNInfo 279 sun_info; 280 281 unsigned char 282 *sun_data, 283 *sun_pixels; 284 285 /* 286 Open image file. 287 */ 288 assert(image_info != (const ImageInfo *) NULL); 289 assert(image_info->signature == MagickCoreSignature); 290 if (image_info->debug != MagickFalse) 291 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 292 image_info->filename); 293 assert(exception != (ExceptionInfo *) NULL); 294 assert(exception->signature == MagickCoreSignature); 295 image=AcquireImage(image_info,exception); 296 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 297 if (status == MagickFalse) 298 { 299 image=DestroyImageList(image); 300 return((Image *) NULL); 301 } 302 /* 303 Read SUN raster header. 304 */ 305 (void) memset(&sun_info,0,sizeof(sun_info)); 306 sun_info.magic=ReadBlobMSBLong(image); 307 do 308 { 309 /* 310 Verify SUN identifier. 311 */ 312 if (sun_info.magic != 0x59a66a95) 313 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 314 sun_info.width=ReadBlobMSBLong(image); 315 sun_info.height=ReadBlobMSBLong(image); 316 sun_info.depth=ReadBlobMSBLong(image); 317 sun_info.length=ReadBlobMSBLong(image); 318 sun_info.type=ReadBlobMSBLong(image); 319 sun_info.maptype=ReadBlobMSBLong(image); 320 sun_info.maplength=ReadBlobMSBLong(image); 321 if (sun_info.maplength > GetBlobSize(image)) 322 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile"); 323 extent=sun_info.height*sun_info.width; 324 if ((sun_info.height != 0) && (sun_info.width != extent/sun_info.height)) 325 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 326 if ((sun_info.type != RT_STANDARD) && (sun_info.type != RT_ENCODED) && 327 (sun_info.type != RT_FORMAT_RGB)) 328 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 329 if ((sun_info.maptype == RMT_NONE) && (sun_info.maplength != 0)) 330 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 331 if ((sun_info.depth != 1) && (sun_info.depth != 8) && 332 (sun_info.depth != 24) && (sun_info.depth != 32)) 333 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 334 if ((sun_info.maptype != RMT_NONE) && (sun_info.maptype != RMT_EQUAL_RGB) && 335 (sun_info.maptype != RMT_RAW)) 336 ThrowReaderException(CoderError,"ColormapTypeNotSupported"); 337 image->columns=sun_info.width; 338 image->rows=sun_info.height; 339 image->depth=sun_info.depth <= 8 ? sun_info.depth : 340 MAGICKCORE_QUANTUM_DEPTH; 341 if (sun_info.depth < 24) 342 { 343 size_t 344 one; 345 346 image->colors=sun_info.maplength; 347 one=1; 348 if (sun_info.maptype == RMT_NONE) 349 image->colors=one << sun_info.depth; 350 if (sun_info.maptype == RMT_EQUAL_RGB) 351 image->colors=sun_info.maplength/3; 352 if (image->colors == 0) 353 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 354 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse) 355 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 356 } 357 switch (sun_info.maptype) 358 { 359 case RMT_NONE: 360 break; 361 case RMT_EQUAL_RGB: 362 { 363 unsigned char 364 *sun_colormap; 365 366 /* 367 Read SUN raster colormap. 368 */ 369 sun_colormap=(unsigned char *) AcquireQuantumMemory(image->colors, 370 sizeof(*sun_colormap)); 371 if (sun_colormap == (unsigned char *) NULL) 372 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 373 count=ReadBlob(image,image->colors,sun_colormap); 374 if (count != (ssize_t) image->colors) 375 { 376 sun_colormap=(unsigned char *) RelinquishMagickMemory(sun_colormap); 377 ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile"); 378 } 379 for (i=0; i < (ssize_t) image->colors; i++) 380 image->colormap[i].red=(MagickRealType) ScaleCharToQuantum( 381 sun_colormap[i]); 382 count=ReadBlob(image,image->colors,sun_colormap); 383 if (count != (ssize_t) image->colors) 384 { 385 sun_colormap=(unsigned char *) RelinquishMagickMemory(sun_colormap); 386 ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile"); 387 } 388 for (i=0; i < (ssize_t) image->colors; i++) 389 image->colormap[i].green=(MagickRealType) ScaleCharToQuantum( 390 sun_colormap[i]); 391 count=ReadBlob(image,image->colors,sun_colormap); 392 if (count != (ssize_t) image->colors) 393 { 394 sun_colormap=(unsigned char *) RelinquishMagickMemory(sun_colormap); 395 ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile"); 396 } 397 for (i=0; i < (ssize_t) image->colors; i++) 398 image->colormap[i].blue=(MagickRealType) ScaleCharToQuantum( 399 sun_colormap[i]); 400 sun_colormap=(unsigned char *) RelinquishMagickMemory(sun_colormap); 401 break; 402 } 403 case RMT_RAW: 404 { 405 unsigned char 406 *sun_colormap; 407 408 /* 409 Read SUN raster colormap. 410 */ 411 sun_colormap=(unsigned char *) AcquireQuantumMemory(sun_info.maplength, 412 sizeof(*sun_colormap)); 413 if (sun_colormap == (unsigned char *) NULL) 414 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 415 count=ReadBlob(image,sun_info.maplength,sun_colormap); 416 sun_colormap=(unsigned char *) RelinquishMagickMemory(sun_colormap); 417 if (count != (ssize_t) sun_info.maplength) 418 ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile"); 419 break; 420 } 421 default: 422 ThrowReaderException(CoderError,"ColormapTypeNotSupported"); 423 } 424 image->alpha_trait=sun_info.depth == 32 ? BlendPixelTrait : 425 UndefinedPixelTrait; 426 image->columns=sun_info.width; 427 image->rows=sun_info.height; 428 if (image_info->ping != MagickFalse) 429 { 430 (void) CloseBlob(image); 431 return(GetFirstImageInList(image)); 432 } 433 status=SetImageExtent(image,image->columns,image->rows,exception); 434 if (status == MagickFalse) 435 return(DestroyImageList(image)); 436 if (sun_info.length == 0) 437 ThrowReaderException(ResourceLimitError,"ImproperImageHeader"); 438 number_pixels=(MagickSizeType) (image->columns*image->rows); 439 if ((sun_info.type != RT_ENCODED) && 440 ((number_pixels*sun_info.depth) > (8UL*sun_info.length))) 441 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 442 if (HeapOverflowSanityCheck(sun_info.width,sun_info.depth) != MagickFalse) 443 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 444 bytes_per_line=sun_info.width*sun_info.depth; 445 if (sun_info.length > GetBlobSize(image)) 446 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile"); 447 sun_data=(unsigned char *) AcquireQuantumMemory(sun_info.length, 448 sizeof(*sun_data)); 449 if (sun_data == (unsigned char *) NULL) 450 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 451 count=(ssize_t) ReadBlob(image,sun_info.length,sun_data); 452 if (count != (ssize_t) sun_info.length) 453 { 454 sun_data=(unsigned char *) RelinquishMagickMemory(sun_data); 455 ThrowReaderException(CorruptImageError,"UnableToReadImageData"); 456 } 457 height=sun_info.height; 458 if ((height == 0) || (sun_info.width == 0) || (sun_info.depth == 0) || 459 ((bytes_per_line/sun_info.depth) != sun_info.width)) 460 { 461 sun_data=(unsigned char *) RelinquishMagickMemory(sun_data); 462 ThrowReaderException(ResourceLimitError,"ImproperImageHeader"); 463 } 464 quantum=sun_info.depth == 1 ? 15 : 7; 465 bytes_per_line+=quantum; 466 bytes_per_line<<=1; 467 if ((bytes_per_line >> 1) != (sun_info.width*sun_info.depth+quantum)) 468 { 469 sun_data=(unsigned char *) RelinquishMagickMemory(sun_data); 470 ThrowReaderException(ResourceLimitError,"ImproperImageHeader"); 471 } 472 bytes_per_line>>=4; 473 if (HeapOverflowSanityCheck(height,bytes_per_line) != MagickFalse) 474 { 475 sun_data=(unsigned char *) RelinquishMagickMemory(sun_data); 476 ThrowReaderException(ResourceLimitError,"ImproperImageHeader"); 477 } 478 pixels_length=height*bytes_per_line; 479 sun_pixels=(unsigned char *) AcquireQuantumMemory(pixels_length+image->rows, 480 sizeof(*sun_pixels)); 481 if (sun_pixels == (unsigned char *) NULL) 482 { 483 sun_data=(unsigned char *) RelinquishMagickMemory(sun_data); 484 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 485 } 486 (void) memset(sun_pixels,0,(pixels_length+image->rows)* 487 sizeof(*sun_pixels)); 488 if (sun_info.type == RT_ENCODED) 489 { 490 status=DecodeImage(sun_data,sun_info.length,sun_pixels,pixels_length); 491 if (status == MagickFalse) 492 { 493 sun_data=(unsigned char *) RelinquishMagickMemory(sun_data); 494 sun_pixels=(unsigned char *) RelinquishMagickMemory(sun_pixels); 495 ThrowReaderException(CorruptImageError,"UnableToReadImageData"); 496 } 497 } 498 else 499 { 500 if (sun_info.length > pixels_length) 501 { 502 sun_data=(unsigned char *) RelinquishMagickMemory(sun_data); 503 sun_pixels=(unsigned char *) RelinquishMagickMemory(sun_pixels); 504 ThrowReaderException(ResourceLimitError,"ImproperImageHeader"); 505 } 506 (void) memcpy(sun_pixels,sun_data,sun_info.length); 507 } 508 sun_data=(unsigned char *) RelinquishMagickMemory(sun_data); 509 /* 510 Convert SUN raster image to pixel packets. 511 */ 512 p=sun_pixels; 513 if (sun_info.depth == 1) 514 for (y=0; y < (ssize_t) image->rows; y++) 515 { 516 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 517 if (q == (Quantum *) NULL) 518 break; 519 for (x=0; x < ((ssize_t) image->columns-7); x+=8) 520 { 521 for (bit=7; bit >= 0; bit--) 522 { 523 SetPixelIndex(image,(Quantum) ((*p) & (0x01 << bit) ? 0x00 : 0x01), 524 q); 525 q+=GetPixelChannels(image); 526 } 527 p++; 528 } 529 if ((image->columns % 8) != 0) 530 { 531 for (bit=7; bit >= (int) (8-(image->columns % 8)); bit--) 532 { 533 SetPixelIndex(image,(Quantum) ((*p) & (0x01 << bit) ? 0x00 : 534 0x01),q); 535 q+=GetPixelChannels(image); 536 } 537 p++; 538 } 539 if ((((image->columns/8)+(image->columns % 8 ? 1 : 0)) % 2) != 0) 540 p++; 541 if (SyncAuthenticPixels(image,exception) == MagickFalse) 542 break; 543 if (image->previous == (Image *) NULL) 544 { 545 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, 546 image->rows); 547 if (status == MagickFalse) 548 break; 549 } 550 } 551 else 552 if (image->storage_class == PseudoClass) 553 { 554 for (y=0; y < (ssize_t) image->rows; y++) 555 { 556 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 557 if (q == (Quantum *) NULL) 558 break; 559 for (x=0; x < (ssize_t) image->columns; x++) 560 { 561 SetPixelIndex(image,ConstrainColormapIndex(image,*p,exception),q); 562 p++; 563 q+=GetPixelChannels(image); 564 } 565 if ((image->columns % 2) != 0) 566 p++; 567 if (SyncAuthenticPixels(image,exception) == MagickFalse) 568 break; 569 if (image->previous == (Image *) NULL) 570 { 571 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, 572 image->rows); 573 if (status == MagickFalse) 574 break; 575 } 576 } 577 } 578 else 579 { 580 size_t 581 bytes_per_pixel; 582 583 bytes_per_pixel=3; 584 if (image->alpha_trait != UndefinedPixelTrait) 585 bytes_per_pixel++; 586 if (bytes_per_line == 0) 587 bytes_per_line=bytes_per_pixel*image->columns; 588 for (y=0; y < (ssize_t) image->rows; y++) 589 { 590 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 591 if (q == (Quantum *) NULL) 592 break; 593 for (x=0; x < (ssize_t) image->columns; x++) 594 { 595 if (image->alpha_trait != UndefinedPixelTrait) 596 SetPixelAlpha(image,ScaleCharToQuantum(*p++),q); 597 if (sun_info.type == RT_STANDARD) 598 { 599 SetPixelBlue(image,ScaleCharToQuantum(*p++),q); 600 SetPixelGreen(image,ScaleCharToQuantum(*p++),q); 601 SetPixelRed(image,ScaleCharToQuantum(*p++),q); 602 } 603 else 604 { 605 SetPixelRed(image,ScaleCharToQuantum(*p++),q); 606 SetPixelGreen(image,ScaleCharToQuantum(*p++),q); 607 SetPixelBlue(image,ScaleCharToQuantum(*p++),q); 608 } 609 if (image->colors != 0) 610 { 611 SetPixelRed(image,ClampToQuantum(image->colormap[(ssize_t) 612 GetPixelRed(image,q)].red),q); 613 SetPixelGreen(image,ClampToQuantum(image->colormap[(ssize_t) 614 GetPixelGreen(image,q)].green),q); 615 SetPixelBlue(image,ClampToQuantum(image->colormap[(ssize_t) 616 GetPixelBlue(image,q)].blue),q); 617 } 618 q+=GetPixelChannels(image); 619 } 620 if (((bytes_per_pixel*image->columns) % 2) != 0) 621 p++; 622 if (SyncAuthenticPixels(image,exception) == MagickFalse) 623 break; 624 if (image->previous == (Image *) NULL) 625 { 626 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, 627 image->rows); 628 if (status == MagickFalse) 629 break; 630 } 631 } 632 } 633 if (image->storage_class == PseudoClass) 634 (void) SyncImage(image,exception); 635 sun_pixels=(unsigned char *) RelinquishMagickMemory(sun_pixels); 636 if (EOFBlob(image) != MagickFalse) 637 { 638 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", 639 image->filename); 640 break; 641 } 642 /* 643 Proceed to next image. 644 */ 645 if (image_info->number_scenes != 0) 646 if (image->scene >= (image_info->scene+image_info->number_scenes-1)) 647 break; 648 sun_info.magic=ReadBlobMSBLong(image); 649 if (sun_info.magic == 0x59a66a95) 650 { 651 /* 652 Allocate next image structure. 653 */ 654 AcquireNextImage(image_info,image,exception); 655 if (GetNextImageInList(image) == (Image *) NULL) 656 { 657 status=MagickFalse; 658 break; 659 } 660 image=SyncNextImageInList(image); 661 status=SetImageProgress(image,LoadImagesTag,TellBlob(image), 662 GetBlobSize(image)); 663 if (status == MagickFalse) 664 break; 665 } 666 } while (sun_info.magic == 0x59a66a95); 667 (void) CloseBlob(image); 668 if (status == MagickFalse) 669 return(DestroyImageList(image)); 670 return(GetFirstImageInList(image)); 671 } 672 673 /* 675 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 676 % % 677 % % 678 % % 679 % R e g i s t e r S U N I m a g e % 680 % % 681 % % 682 % % 683 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 684 % 685 % RegisterSUNImage() adds attributes for the SUN image format to 686 % the list of supported formats. The attributes include the image format 687 % tag, a method to read and/or write the format, whether the format 688 % supports the saving of more than one frame to the same file or blob, 689 % whether the format supports native in-memory I/O, and a brief 690 % description of the format. 691 % 692 % The format of the RegisterSUNImage method is: 693 % 694 % size_t RegisterSUNImage(void) 695 % 696 */ 697 ModuleExport size_t RegisterSUNImage(void) 698 { 699 MagickInfo 700 *entry; 701 702 entry=AcquireMagickInfo("SUN","RAS","SUN Rasterfile"); 703 entry->decoder=(DecodeImageHandler *) ReadSUNImage; 704 entry->encoder=(EncodeImageHandler *) WriteSUNImage; 705 entry->magick=(IsImageFormatHandler *) IsSUN; 706 entry->flags|=CoderDecoderSeekableStreamFlag; 707 (void) RegisterMagickInfo(entry); 708 entry=AcquireMagickInfo("SUN","SUN","SUN Rasterfile"); 709 entry->decoder=(DecodeImageHandler *) ReadSUNImage; 710 entry->encoder=(EncodeImageHandler *) WriteSUNImage; 711 entry->flags|=CoderDecoderSeekableStreamFlag; 712 (void) RegisterMagickInfo(entry); 713 return(MagickImageCoderSignature); 714 } 715 716 /* 718 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 719 % % 720 % % 721 % % 722 % U n r e g i s t e r S U N I m a g e % 723 % % 724 % % 725 % % 726 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 727 % 728 % UnregisterSUNImage() removes format registrations made by the 729 % SUN module from the list of supported formats. 730 % 731 % The format of the UnregisterSUNImage method is: 732 % 733 % UnregisterSUNImage(void) 734 % 735 */ 736 ModuleExport void UnregisterSUNImage(void) 737 { 738 (void) UnregisterMagickInfo("RAS"); 739 (void) UnregisterMagickInfo("SUN"); 740 } 741 742 /* 744 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 745 % % 746 % % 747 % % 748 % W r i t e S U N I m a g e % 749 % % 750 % % 751 % % 752 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 753 % 754 % WriteSUNImage() writes an image in the SUN rasterfile format. 755 % 756 % The format of the WriteSUNImage method is: 757 % 758 % MagickBooleanType WriteSUNImage(const ImageInfo *image_info, 759 % Image *image,ExceptionInfo *exception) 760 % 761 % A description of each parameter follows. 762 % 763 % o image_info: the image info. 764 % 765 % o image: The image. 766 % 767 % o exception: return any errors or warnings in this structure. 768 % 769 */ 770 static MagickBooleanType WriteSUNImage(const ImageInfo *image_info,Image *image, 771 ExceptionInfo *exception) 772 { 773 #define RMT_EQUAL_RGB 1 774 #define RMT_NONE 0 775 #define RMT_RAW 2 776 #define RT_STANDARD 1 777 #define RT_FORMAT_RGB 3 778 779 typedef struct _SUNInfo 780 { 781 unsigned int 782 magic, 783 width, 784 height, 785 depth, 786 length, 787 type, 788 maptype, 789 maplength; 790 } SUNInfo; 791 792 MagickBooleanType 793 status; 794 795 MagickOffsetType 796 scene; 797 798 MagickSizeType 799 number_pixels; 800 801 register const Quantum 802 *p; 803 804 register ssize_t 805 i, 806 x; 807 808 size_t 809 imageListLength; 810 811 ssize_t 812 y; 813 814 SUNInfo 815 sun_info; 816 817 /* 818 Open output image file. 819 */ 820 assert(image_info != (const ImageInfo *) NULL); 821 assert(image_info->signature == MagickCoreSignature); 822 assert(image != (Image *) NULL); 823 assert(image->signature == MagickCoreSignature); 824 if (image->debug != MagickFalse) 825 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 826 assert(exception != (ExceptionInfo *) NULL); 827 assert(exception->signature == MagickCoreSignature); 828 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 829 if (status == MagickFalse) 830 return(status); 831 scene=0; 832 imageListLength=GetImageListLength(image); 833 do 834 { 835 /* 836 Initialize SUN raster file header. 837 */ 838 (void) TransformImageColorspace(image,sRGBColorspace,exception); 839 sun_info.magic=0x59a66a95; 840 if ((image->columns != (unsigned int) image->columns) || 841 (image->rows != (unsigned int) image->rows)) 842 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit"); 843 sun_info.width=(unsigned int) image->columns; 844 sun_info.height=(unsigned int) image->rows; 845 sun_info.type=(unsigned int) 846 (image->storage_class == DirectClass ? RT_FORMAT_RGB : RT_STANDARD); 847 sun_info.maptype=RMT_NONE; 848 sun_info.maplength=0; 849 number_pixels=(MagickSizeType) image->columns*image->rows; 850 if ((4*number_pixels) != (size_t) (4*number_pixels)) 851 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 852 if (image->storage_class == DirectClass) 853 { 854 /* 855 Full color SUN raster. 856 */ 857 sun_info.depth=(unsigned int) image->alpha_trait != 858 UndefinedPixelTrait ? 32U : 24U; 859 sun_info.length=(unsigned int) ((image->alpha_trait != 860 UndefinedPixelTrait ? 4 : 3)*number_pixels); 861 sun_info.length+=sun_info.length & 0x01 ? (unsigned int) image->rows : 862 0; 863 } 864 else 865 if (SetImageMonochrome(image,exception) != MagickFalse) 866 { 867 /* 868 Monochrome SUN raster. 869 */ 870 sun_info.depth=1; 871 sun_info.length=(unsigned int) (((image->columns+7) >> 3)* 872 image->rows); 873 sun_info.length+=(unsigned int) (((image->columns/8)+(image->columns % 874 8 ? 1 : 0)) % 2 ? image->rows : 0); 875 } 876 else 877 { 878 /* 879 Colormapped SUN raster. 880 */ 881 sun_info.depth=8; 882 sun_info.length=(unsigned int) number_pixels; 883 sun_info.length+=(unsigned int) (image->columns & 0x01 ? image->rows : 884 0); 885 sun_info.maptype=RMT_EQUAL_RGB; 886 sun_info.maplength=(unsigned int) (3*image->colors); 887 } 888 /* 889 Write SUN header. 890 */ 891 (void) WriteBlobMSBLong(image,sun_info.magic); 892 (void) WriteBlobMSBLong(image,sun_info.width); 893 (void) WriteBlobMSBLong(image,sun_info.height); 894 (void) WriteBlobMSBLong(image,sun_info.depth); 895 (void) WriteBlobMSBLong(image,sun_info.length); 896 (void) WriteBlobMSBLong(image,sun_info.type); 897 (void) WriteBlobMSBLong(image,sun_info.maptype); 898 (void) WriteBlobMSBLong(image,sun_info.maplength); 899 /* 900 Convert MIFF to SUN raster pixels. 901 */ 902 x=0; 903 y=0; 904 if (image->storage_class == DirectClass) 905 { 906 register unsigned char 907 *q; 908 909 size_t 910 bytes_per_pixel, 911 length; 912 913 unsigned char 914 *pixels; 915 916 /* 917 Allocate memory for pixels. 918 */ 919 bytes_per_pixel=3; 920 if (image->alpha_trait != UndefinedPixelTrait) 921 bytes_per_pixel++; 922 length=image->columns; 923 pixels=(unsigned char *) AcquireQuantumMemory(length,4*sizeof(*pixels)); 924 if (pixels == (unsigned char *) NULL) 925 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 926 /* 927 Convert DirectClass packet to SUN RGB pixel. 928 */ 929 for (y=0; y < (ssize_t) image->rows; y++) 930 { 931 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 932 if (p == (const Quantum *) NULL) 933 break; 934 q=pixels; 935 for (x=0; x < (ssize_t) image->columns; x++) 936 { 937 if (image->alpha_trait != UndefinedPixelTrait) 938 *q++=ScaleQuantumToChar(GetPixelAlpha(image,p)); 939 *q++=ScaleQuantumToChar(GetPixelRed(image,p)); 940 *q++=ScaleQuantumToChar(GetPixelGreen(image,p)); 941 *q++=ScaleQuantumToChar(GetPixelBlue(image,p)); 942 p+=GetPixelChannels(image); 943 } 944 if (((bytes_per_pixel*image->columns) & 0x01) != 0) 945 *q++='\0'; /* pad scanline */ 946 (void) WriteBlob(image,(size_t) (q-pixels),pixels); 947 if (image->previous == (Image *) NULL) 948 { 949 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 950 image->rows); 951 if (status == MagickFalse) 952 break; 953 } 954 } 955 pixels=(unsigned char *) RelinquishMagickMemory(pixels); 956 } 957 else 958 if (SetImageMonochrome(image,exception) != MagickFalse) 959 { 960 register unsigned char 961 bit, 962 byte; 963 964 /* 965 Convert PseudoClass image to a SUN monochrome image. 966 */ 967 (void) SetImageType(image,BilevelType,exception); 968 for (y=0; y < (ssize_t) image->rows; y++) 969 { 970 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 971 if (p == (const Quantum *) NULL) 972 break; 973 bit=0; 974 byte=0; 975 for (x=0; x < (ssize_t) image->columns; x++) 976 { 977 byte<<=1; 978 if (GetPixelLuma(image,p) < (QuantumRange/2.0)) 979 byte|=0x01; 980 bit++; 981 if (bit == 8) 982 { 983 (void) WriteBlobByte(image,byte); 984 bit=0; 985 byte=0; 986 } 987 p+=GetPixelChannels(image); 988 } 989 if (bit != 0) 990 (void) WriteBlobByte(image,(unsigned char) (byte << (8-bit))); 991 if ((((image->columns/8)+ 992 (image->columns % 8 ? 1 : 0)) % 2) != 0) 993 (void) WriteBlobByte(image,0); /* pad scanline */ 994 if (image->previous == (Image *) NULL) 995 { 996 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 997 image->rows); 998 if (status == MagickFalse) 999 break; 1000 } 1001 } 1002 } 1003 else 1004 { 1005 /* 1006 Dump colormap to file. 1007 */ 1008 for (i=0; i < (ssize_t) image->colors; i++) 1009 (void) WriteBlobByte(image,ScaleQuantumToChar( 1010 ClampToQuantum(image->colormap[i].red))); 1011 for (i=0; i < (ssize_t) image->colors; i++) 1012 (void) WriteBlobByte(image,ScaleQuantumToChar( 1013 ClampToQuantum(image->colormap[i].green))); 1014 for (i=0; i < (ssize_t) image->colors; i++) 1015 (void) WriteBlobByte(image,ScaleQuantumToChar( 1016 ClampToQuantum(image->colormap[i].blue))); 1017 /* 1018 Convert PseudoClass packet to SUN colormapped pixel. 1019 */ 1020 for (y=0; y < (ssize_t) image->rows; y++) 1021 { 1022 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 1023 if (p == (const Quantum *) NULL) 1024 break; 1025 for (x=0; x < (ssize_t) image->columns; x++) 1026 { 1027 (void) WriteBlobByte(image,(unsigned char) 1028 GetPixelIndex(image,p)); 1029 p+=GetPixelChannels(image); 1030 } 1031 if (image->columns & 0x01) 1032 (void) WriteBlobByte(image,0); /* pad scanline */ 1033 if (image->previous == (Image *) NULL) 1034 { 1035 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 1036 image->rows); 1037 if (status == MagickFalse) 1038 break; 1039 } 1040 } 1041 } 1042 if (GetNextImageInList(image) == (Image *) NULL) 1043 break; 1044 image=SyncNextImageInList(image); 1045 status=SetImageProgress(image,SaveImagesTag,scene++,imageListLength); 1046 if (status == MagickFalse) 1047 break; 1048 } while (image_info->adjoin != MagickFalse); 1049 (void) CloseBlob(image); 1050 return(MagickTrue); 1051 } 1052