1 /* 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 % % 4 % % 5 % % 6 % SSSSS GGGG IIIII % 7 % SS G I % 8 % SSS G GG I % 9 % SS G G I % 10 % SSSSS GGG IIIII % 11 % % 12 % % 13 % Read/Write Irix RGB 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/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/colorspace.h" 52 #include "MagickCore/colorspace-private.h" 53 #include "MagickCore/exception.h" 54 #include "MagickCore/exception-private.h" 55 #include "MagickCore/image.h" 56 #include "MagickCore/image-private.h" 57 #include "MagickCore/list.h" 58 #include "MagickCore/magick.h" 59 #include "MagickCore/memory_.h" 60 #include "MagickCore/monitor.h" 61 #include "MagickCore/monitor-private.h" 62 #include "MagickCore/pixel-accessor.h" 63 #include "MagickCore/property.h" 64 #include "MagickCore/quantum-private.h" 65 #include "MagickCore/static.h" 66 #include "MagickCore/string_.h" 67 #include "MagickCore/module.h" 68 69 /* 71 Typedef declaractions. 72 */ 73 typedef struct _SGIInfo 74 { 75 unsigned short 76 magic; 77 78 unsigned char 79 storage, 80 bytes_per_pixel; 81 82 unsigned short 83 dimension, 84 columns, 85 rows, 86 depth; 87 88 size_t 89 minimum_value, 90 maximum_value, 91 sans; 92 93 char 94 name[80]; 95 96 size_t 97 pixel_format; 98 99 unsigned char 100 filler[404]; 101 } SGIInfo; 102 103 /* 105 Forward declarations. 106 */ 107 static MagickBooleanType 108 WriteSGIImage(const ImageInfo *,Image *,ExceptionInfo *); 109 /* 110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 111 % % 112 % % 113 % % 114 % I s S G I % 115 % % 116 % % 117 % % 118 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 119 % 120 % IsSGI() returns MagickTrue if the image format type, identified by the 121 % magick string, is SGI. 122 % 123 % The format of the IsSGI method is: 124 % 125 % MagickBooleanType IsSGI(const unsigned char *magick,const size_t length) 126 % 127 % A description of each parameter follows: 128 % 129 % o magick: compare image format pattern against these bytes. 130 % 131 % o length: Specifies the length of the magick string. 132 % 133 */ 134 static MagickBooleanType IsSGI(const unsigned char *magick,const size_t length) 135 { 136 if (length < 2) 137 return(MagickFalse); 138 if (memcmp(magick,"\001\332",2) == 0) 139 return(MagickTrue); 140 return(MagickFalse); 141 } 142 143 /* 145 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 146 % % 147 % % 148 % % 149 % R e a d S G I I m a g e % 150 % % 151 % % 152 % % 153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 154 % 155 % ReadSGIImage() reads a SGI RGB image file and returns it. It 156 % allocates the memory necessary for the new Image structure and returns a 157 % pointer to the new image. 158 % 159 % The format of the ReadSGIImage method is: 160 % 161 % Image *ReadSGIImage(const ImageInfo *image_info,ExceptionInfo *exception) 162 % 163 % A description of each parameter follows: 164 % 165 % o image_info: the image info. 166 % 167 % o exception: return any errors or warnings in this structure. 168 % 169 */ 170 171 static MagickBooleanType SGIDecode(const size_t bytes_per_pixel, 172 ssize_t number_packets,unsigned char *packets,ssize_t number_pixels, 173 unsigned char *pixels) 174 { 175 register unsigned char 176 *p, 177 *q; 178 179 size_t 180 pixel; 181 182 ssize_t 183 count; 184 185 p=packets; 186 q=pixels; 187 if (bytes_per_pixel == 2) 188 { 189 for ( ; number_pixels > 0; ) 190 { 191 if (number_packets-- == 0) 192 return(MagickFalse); 193 pixel=(size_t) (*p++) << 8; 194 pixel|=(*p++); 195 count=(ssize_t) (pixel & 0x7f); 196 if (count == 0) 197 break; 198 if (count > (ssize_t) number_pixels) 199 return(MagickFalse); 200 number_pixels-=count; 201 if ((pixel & 0x80) != 0) 202 for ( ; count != 0; count--) 203 { 204 if (number_packets-- == 0) 205 return(MagickFalse); 206 *q=(*p++); 207 *(q+1)=(*p++); 208 q+=8; 209 } 210 else 211 { 212 pixel=(size_t) (*p++) << 8; 213 pixel|=(*p++); 214 for ( ; count != 0; count--) 215 { 216 if (number_packets-- == 0) 217 return(MagickFalse); 218 *q=(unsigned char) (pixel >> 8); 219 *(q+1)=(unsigned char) pixel; 220 q+=8; 221 } 222 } 223 } 224 return(MagickTrue); 225 } 226 for ( ; number_pixels > 0; ) 227 { 228 if (number_packets-- == 0) 229 return(MagickFalse); 230 pixel=(size_t) (*p++); 231 count=(ssize_t) (pixel & 0x7f); 232 if (count == 0) 233 break; 234 if (count > (ssize_t) number_pixels) 235 return(MagickFalse); 236 number_pixels-=count; 237 if ((pixel & 0x80) != 0) 238 for ( ; count != 0; count--) 239 { 240 if (number_packets-- == 0) 241 return(MagickFalse); 242 *q=(*p++); 243 q+=4; 244 } 245 else 246 { 247 if (number_packets-- == 0) 248 return(MagickFalse); 249 pixel=(size_t) (*p++); 250 for ( ; count != 0; count--) 251 { 252 *q=(unsigned char) pixel; 253 q+=4; 254 } 255 } 256 } 257 return(MagickTrue); 258 } 259 260 static Image *ReadSGIImage(const ImageInfo *image_info,ExceptionInfo *exception) 261 { 262 Image 263 *image; 264 265 MagickBooleanType 266 status; 267 268 MagickSizeType 269 number_pixels; 270 271 MemoryInfo 272 *pixel_info; 273 274 register Quantum 275 *q; 276 277 register ssize_t 278 i, 279 x; 280 281 register unsigned char 282 *p; 283 284 SGIInfo 285 iris_info; 286 287 size_t 288 bytes_per_pixel, 289 quantum; 290 291 ssize_t 292 count, 293 y, 294 z; 295 296 unsigned char 297 *pixels; 298 299 /* 300 Open image file. 301 */ 302 assert(image_info != (const ImageInfo *) NULL); 303 assert(image_info->signature == MagickCoreSignature); 304 if (image_info->debug != MagickFalse) 305 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 306 image_info->filename); 307 assert(exception != (ExceptionInfo *) NULL); 308 assert(exception->signature == MagickCoreSignature); 309 image=AcquireImage(image_info,exception); 310 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 311 if (status == MagickFalse) 312 { 313 image=DestroyImageList(image); 314 return((Image *) NULL); 315 } 316 /* 317 Read SGI raster header. 318 */ 319 iris_info.magic=ReadBlobMSBShort(image); 320 do 321 { 322 /* 323 Verify SGI identifier. 324 */ 325 if (iris_info.magic != 0x01DA) 326 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 327 iris_info.storage=(unsigned char) ReadBlobByte(image); 328 switch (iris_info.storage) 329 { 330 case 0x00: image->compression=NoCompression; break; 331 case 0x01: image->compression=RLECompression; break; 332 default: 333 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 334 } 335 iris_info.bytes_per_pixel=(unsigned char) ReadBlobByte(image); 336 if ((iris_info.bytes_per_pixel == 0) || (iris_info.bytes_per_pixel > 2)) 337 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 338 iris_info.dimension=ReadBlobMSBShort(image); 339 iris_info.columns=ReadBlobMSBShort(image); 340 iris_info.rows=ReadBlobMSBShort(image); 341 iris_info.depth=ReadBlobMSBShort(image); 342 if ((iris_info.depth == 0) || (iris_info.depth > 4)) 343 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 344 iris_info.minimum_value=ReadBlobMSBLong(image); 345 iris_info.maximum_value=ReadBlobMSBLong(image); 346 iris_info.sans=ReadBlobMSBLong(image); 347 (void) ReadBlob(image,sizeof(iris_info.name),(unsigned char *) 348 iris_info.name); 349 iris_info.name[sizeof(iris_info.name)-1]='\0'; 350 if (*iris_info.name != '\0') 351 (void) SetImageProperty(image,"label",iris_info.name,exception); 352 iris_info.pixel_format=ReadBlobMSBLong(image); 353 if (iris_info.pixel_format != 0) 354 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 355 count=ReadBlob(image,sizeof(iris_info.filler),iris_info.filler); 356 (void) count; 357 image->columns=iris_info.columns; 358 image->rows=iris_info.rows; 359 image->depth=(size_t) MagickMin(iris_info.depth,MAGICKCORE_QUANTUM_DEPTH); 360 if (iris_info.pixel_format == 0) 361 image->depth=(size_t) MagickMin((size_t) 8* 362 iris_info.bytes_per_pixel,MAGICKCORE_QUANTUM_DEPTH); 363 if (iris_info.depth < 3) 364 { 365 image->storage_class=PseudoClass; 366 image->colors=iris_info.bytes_per_pixel > 1 ? 65535 : 256; 367 } 368 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0)) 369 if (image->scene >= (image_info->scene+image_info->number_scenes-1)) 370 break; 371 status=SetImageExtent(image,image->columns,image->rows,exception); 372 if (status == MagickFalse) 373 return(DestroyImageList(image)); 374 /* 375 Allocate SGI pixels. 376 */ 377 bytes_per_pixel=(size_t) iris_info.bytes_per_pixel; 378 number_pixels=(MagickSizeType) iris_info.columns*iris_info.rows; 379 if ((4*bytes_per_pixel*number_pixels) != ((MagickSizeType) (size_t) 380 (4*bytes_per_pixel*number_pixels))) 381 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 382 pixel_info=AcquireVirtualMemory(iris_info.columns,iris_info.rows*4* 383 bytes_per_pixel*sizeof(*pixels)); 384 if (pixel_info == (MemoryInfo *) NULL) 385 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 386 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info); 387 if ((int) iris_info.storage != 0x01) 388 { 389 unsigned char 390 *scanline; 391 392 /* 393 Read standard image format. 394 */ 395 scanline=(unsigned char *) AcquireQuantumMemory(iris_info.columns, 396 bytes_per_pixel*sizeof(*scanline)); 397 if (scanline == (unsigned char *) NULL) 398 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 399 for (z=0; z < (ssize_t) iris_info.depth; z++) 400 { 401 p=pixels+bytes_per_pixel*z; 402 for (y=0; y < (ssize_t) iris_info.rows; y++) 403 { 404 count=ReadBlob(image,bytes_per_pixel*iris_info.columns,scanline); 405 if (EOFBlob(image) != MagickFalse) 406 break; 407 if (bytes_per_pixel == 2) 408 for (x=0; x < (ssize_t) iris_info.columns; x++) 409 { 410 *p=scanline[2*x]; 411 *(p+1)=scanline[2*x+1]; 412 p+=8; 413 } 414 else 415 for (x=0; x < (ssize_t) iris_info.columns; x++) 416 { 417 *p=scanline[x]; 418 p+=4; 419 } 420 } 421 } 422 scanline=(unsigned char *) RelinquishMagickMemory(scanline); 423 } 424 else 425 { 426 MemoryInfo 427 *packet_info; 428 429 size_t 430 *runlength; 431 432 ssize_t 433 offset, 434 *offsets; 435 436 unsigned char 437 *packets; 438 439 unsigned int 440 data_order; 441 442 /* 443 Read runlength-encoded image format. 444 */ 445 offsets=(ssize_t *) AcquireQuantumMemory((size_t) iris_info.rows, 446 iris_info.depth*sizeof(*offsets)); 447 runlength=(size_t *) AcquireQuantumMemory(iris_info.rows, 448 iris_info.depth*sizeof(*runlength)); 449 packet_info=AcquireVirtualMemory((size_t) iris_info.columns+10UL,4UL* 450 sizeof(*packets)); 451 if ((offsets == (ssize_t *) NULL) || 452 (runlength == (size_t *) NULL) || 453 (packet_info == (MemoryInfo *) NULL)) 454 { 455 if (offsets == (ssize_t *) NULL) 456 offsets=(ssize_t *) RelinquishMagickMemory(offsets); 457 if (runlength == (size_t *) NULL) 458 runlength=(size_t *) RelinquishMagickMemory(runlength); 459 if (packet_info == (MemoryInfo *) NULL) 460 packet_info=RelinquishVirtualMemory(packet_info); 461 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 462 } 463 packets=(unsigned char *) GetVirtualMemoryBlob(packet_info); 464 for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++) 465 offsets[i]=ReadBlobMSBSignedLong(image); 466 for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++) 467 { 468 runlength[i]=ReadBlobMSBLong(image); 469 if (runlength[i] > (4*(size_t) iris_info.columns+10)) 470 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 471 } 472 /* 473 Check data order. 474 */ 475 offset=0; 476 data_order=0; 477 for (y=0; ((y < (ssize_t) iris_info.rows) && (data_order == 0)); y++) 478 for (z=0; ((z < (ssize_t) iris_info.depth) && (data_order == 0)); z++) 479 { 480 if (offsets[y+z*iris_info.rows] < offset) 481 data_order=1; 482 offset=offsets[y+z*iris_info.rows]; 483 } 484 offset=(ssize_t) TellBlob(image); 485 if (data_order == 1) 486 { 487 for (z=0; z < (ssize_t) iris_info.depth; z++) 488 { 489 p=pixels; 490 for (y=0; y < (ssize_t) iris_info.rows; y++) 491 { 492 if (offset != offsets[y+z*iris_info.rows]) 493 { 494 offset=offsets[y+z*iris_info.rows]; 495 offset=(ssize_t) SeekBlob(image,(ssize_t) offset,SEEK_SET); 496 } 497 count=ReadBlob(image,(size_t) runlength[y+z*iris_info.rows], 498 packets); 499 if (EOFBlob(image) != MagickFalse) 500 break; 501 offset+=(ssize_t) runlength[y+z*iris_info.rows]; 502 status=SGIDecode(bytes_per_pixel,(ssize_t) 503 (runlength[y+z*iris_info.rows]/bytes_per_pixel),packets, 504 1L*iris_info.columns,p+bytes_per_pixel*z); 505 if (status == MagickFalse) 506 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 507 p+=(iris_info.columns*4*bytes_per_pixel); 508 } 509 } 510 } 511 else 512 { 513 MagickOffsetType 514 position; 515 516 position=TellBlob(image); 517 p=pixels; 518 for (y=0; y < (ssize_t) iris_info.rows; y++) 519 { 520 for (z=0; z < (ssize_t) iris_info.depth; z++) 521 { 522 if (offset != offsets[y+z*iris_info.rows]) 523 { 524 offset=offsets[y+z*iris_info.rows]; 525 offset=(ssize_t) SeekBlob(image,(ssize_t) offset,SEEK_SET); 526 } 527 count=ReadBlob(image,(size_t) runlength[y+z*iris_info.rows], 528 packets); 529 if (EOFBlob(image) != MagickFalse) 530 break; 531 offset+=(ssize_t) runlength[y+z*iris_info.rows]; 532 status=SGIDecode(bytes_per_pixel,(ssize_t) 533 (runlength[y+z*iris_info.rows]/bytes_per_pixel),packets, 534 1L*iris_info.columns,p+bytes_per_pixel*z); 535 if (status == MagickFalse) 536 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 537 } 538 p+=(iris_info.columns*4*bytes_per_pixel); 539 } 540 offset=(ssize_t) SeekBlob(image,position,SEEK_SET); 541 } 542 packet_info=RelinquishVirtualMemory(packet_info); 543 runlength=(size_t *) RelinquishMagickMemory(runlength); 544 offsets=(ssize_t *) RelinquishMagickMemory(offsets); 545 } 546 /* 547 Initialize image structure. 548 */ 549 image->alpha_trait=iris_info.depth == 4 ? BlendPixelTrait : 550 UndefinedPixelTrait; 551 image->columns=iris_info.columns; 552 image->rows=iris_info.rows; 553 /* 554 Convert SGI raster image to pixel packets. 555 */ 556 if (image->storage_class == DirectClass) 557 { 558 /* 559 Convert SGI image to DirectClass pixel packets. 560 */ 561 if (bytes_per_pixel == 2) 562 { 563 for (y=0; y < (ssize_t) image->rows; y++) 564 { 565 p=pixels+(image->rows-y-1)*8*image->columns; 566 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 567 if (q == (Quantum *) NULL) 568 break; 569 for (x=0; x < (ssize_t) image->columns; x++) 570 { 571 SetPixelRed(image,ScaleShortToQuantum((unsigned short) 572 ((*(p+0) << 8) | (*(p+1)))),q); 573 SetPixelGreen(image,ScaleShortToQuantum((unsigned short) 574 ((*(p+2) << 8) | (*(p+3)))),q); 575 SetPixelBlue(image,ScaleShortToQuantum((unsigned short) 576 ((*(p+4) << 8) | (*(p+5)))),q); 577 SetPixelAlpha(image,OpaqueAlpha,q); 578 if (image->alpha_trait != UndefinedPixelTrait) 579 SetPixelAlpha(image,ScaleShortToQuantum((unsigned short) 580 ((*(p+6) << 8) | (*(p+7)))),q); 581 p+=8; 582 q+=GetPixelChannels(image); 583 } 584 if (SyncAuthenticPixels(image,exception) == MagickFalse) 585 break; 586 if (image->previous == (Image *) NULL) 587 { 588 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) 589 y,image->rows); 590 if (status == MagickFalse) 591 break; 592 } 593 } 594 } 595 else 596 for (y=0; y < (ssize_t) image->rows; y++) 597 { 598 p=pixels+(image->rows-y-1)*4*image->columns; 599 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 600 if (q == (Quantum *) NULL) 601 break; 602 for (x=0; x < (ssize_t) image->columns; x++) 603 { 604 SetPixelRed(image,ScaleCharToQuantum(*p),q); 605 SetPixelGreen(image,ScaleCharToQuantum(*(p+1)),q); 606 SetPixelBlue(image,ScaleCharToQuantum(*(p+2)),q); 607 SetPixelAlpha(image,OpaqueAlpha,q); 608 if (image->alpha_trait != UndefinedPixelTrait) 609 SetPixelAlpha(image,ScaleCharToQuantum(*(p+3)),q); 610 p+=4; 611 q+=GetPixelChannels(image); 612 } 613 if (SyncAuthenticPixels(image,exception) == MagickFalse) 614 break; 615 if (image->previous == (Image *) NULL) 616 { 617 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, 618 image->rows); 619 if (status == MagickFalse) 620 break; 621 } 622 } 623 } 624 else 625 { 626 /* 627 Create grayscale map. 628 */ 629 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse) 630 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 631 /* 632 Convert SGI image to PseudoClass pixel packets. 633 */ 634 if (bytes_per_pixel == 2) 635 { 636 for (y=0; y < (ssize_t) image->rows; y++) 637 { 638 p=pixels+(image->rows-y-1)*8*image->columns; 639 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 640 if (q == (Quantum *) NULL) 641 break; 642 for (x=0; x < (ssize_t) image->columns; x++) 643 { 644 quantum=(*p << 8); 645 quantum|=(*(p+1)); 646 SetPixelIndex(image,(Quantum) quantum,q); 647 p+=8; 648 q+=GetPixelChannels(image); 649 } 650 if (SyncAuthenticPixels(image,exception) == MagickFalse) 651 break; 652 if (image->previous == (Image *) NULL) 653 { 654 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) 655 y,image->rows); 656 if (status == MagickFalse) 657 break; 658 } 659 } 660 } 661 else 662 for (y=0; y < (ssize_t) image->rows; y++) 663 { 664 p=pixels+(image->rows-y-1)*4*image->columns; 665 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 666 if (q == (Quantum *) NULL) 667 break; 668 for (x=0; x < (ssize_t) image->columns; x++) 669 { 670 SetPixelIndex(image,*p,q); 671 p+=4; 672 q+=GetPixelChannels(image); 673 } 674 if (SyncAuthenticPixels(image,exception) == MagickFalse) 675 break; 676 if (image->previous == (Image *) NULL) 677 { 678 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, 679 image->rows); 680 if (status == MagickFalse) 681 break; 682 } 683 } 684 (void) SyncImage(image,exception); 685 } 686 pixel_info=RelinquishVirtualMemory(pixel_info); 687 if (EOFBlob(image) != MagickFalse) 688 { 689 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", 690 image->filename); 691 break; 692 } 693 /* 694 Proceed to next image. 695 */ 696 if (image_info->number_scenes != 0) 697 if (image->scene >= (image_info->scene+image_info->number_scenes-1)) 698 break; 699 iris_info.magic=ReadBlobMSBShort(image); 700 if (iris_info.magic == 0x01DA) 701 { 702 /* 703 Allocate next image structure. 704 */ 705 AcquireNextImage(image_info,image,exception); 706 if (GetNextImageInList(image) == (Image *) NULL) 707 { 708 image=DestroyImageList(image); 709 return((Image *) NULL); 710 } 711 image=SyncNextImageInList(image); 712 status=SetImageProgress(image,LoadImagesTag,TellBlob(image), 713 GetBlobSize(image)); 714 if (status == MagickFalse) 715 break; 716 } 717 } while (iris_info.magic == 0x01DA); 718 (void) CloseBlob(image); 719 return(GetFirstImageInList(image)); 720 } 721 722 /* 724 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 725 % % 726 % % 727 % % 728 % R e g i s t e r S G I I m a g e % 729 % % 730 % % 731 % % 732 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 733 % 734 % RegisterSGIImage() adds properties for the SGI image format to 735 % the list of supported formats. The properties include the image format 736 % tag, a method to read and/or write the format, whether the format 737 % supports the saving of more than one frame to the same file or blob, 738 % whether the format supports native in-memory I/O, and a brief 739 % description of the format. 740 % 741 % The format of the RegisterSGIImage method is: 742 % 743 % size_t RegisterSGIImage(void) 744 % 745 */ 746 ModuleExport size_t RegisterSGIImage(void) 747 { 748 MagickInfo 749 *entry; 750 751 entry=AcquireMagickInfo("SGI","SGI","Irix RGB image"); 752 entry->decoder=(DecodeImageHandler *) ReadSGIImage; 753 entry->encoder=(EncodeImageHandler *) WriteSGIImage; 754 entry->magick=(IsImageFormatHandler *) IsSGI; 755 entry->flags|=CoderSeekableStreamFlag; 756 (void) RegisterMagickInfo(entry); 757 return(MagickImageCoderSignature); 758 } 759 760 /* 762 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 763 % % 764 % % 765 % % 766 % U n r e g i s t e r S G I I m a g e % 767 % % 768 % % 769 % % 770 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 771 % 772 % UnregisterSGIImage() removes format registrations made by the 773 % SGI module from the list of supported formats. 774 % 775 % The format of the UnregisterSGIImage method is: 776 % 777 % UnregisterSGIImage(void) 778 % 779 */ 780 ModuleExport void UnregisterSGIImage(void) 781 { 782 (void) UnregisterMagickInfo("SGI"); 783 } 784 785 /* 787 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 788 % % 789 % % 790 % % 791 % W r i t e S G I I m a g e % 792 % % 793 % % 794 % % 795 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 796 % 797 % WriteSGIImage() writes an image in SGI RGB encoded image format. 798 % 799 % The format of the WriteSGIImage method is: 800 % 801 % MagickBooleanType WriteSGIImage(const ImageInfo *image_info, 802 % Image *image,ExceptionInfo *exception) 803 % 804 % A description of each parameter follows. 805 % 806 % o image_info: the image info. 807 % 808 % o image: The image. 809 % 810 % o exception: return any errors or warnings in this structure. 811 % 812 */ 813 814 static size_t SGIEncode(unsigned char *pixels,size_t length, 815 unsigned char *packets) 816 { 817 short 818 runlength; 819 820 register unsigned char 821 *p, 822 *q; 823 824 unsigned char 825 *limit, 826 *mark; 827 828 p=pixels; 829 limit=p+length*4; 830 q=packets; 831 while (p < limit) 832 { 833 mark=p; 834 p+=8; 835 while ((p < limit) && ((*(p-8) != *(p-4)) || (*(p-4) != *p))) 836 p+=4; 837 p-=8; 838 length=(size_t) (p-mark) >> 2; 839 while (length != 0) 840 { 841 runlength=(short) (length > 126 ? 126 : length); 842 length-=runlength; 843 *q++=(unsigned char) (0x80 | runlength); 844 for ( ; runlength > 0; runlength--) 845 { 846 *q++=(*mark); 847 mark+=4; 848 } 849 } 850 mark=p; 851 p+=4; 852 while ((p < limit) && (*p == *mark)) 853 p+=4; 854 length=(size_t) (p-mark) >> 2; 855 while (length != 0) 856 { 857 runlength=(short) (length > 126 ? 126 : length); 858 length-=runlength; 859 *q++=(unsigned char) runlength; 860 *q++=(*mark); 861 } 862 } 863 *q++='\0'; 864 return((size_t) (q-packets)); 865 } 866 867 static MagickBooleanType WriteSGIImage(const ImageInfo *image_info,Image *image, 868 ExceptionInfo *exception) 869 { 870 CompressionType 871 compression; 872 873 const char 874 *value; 875 876 MagickBooleanType 877 status; 878 879 MagickOffsetType 880 scene; 881 882 MagickSizeType 883 number_pixels; 884 885 MemoryInfo 886 *pixel_info; 887 888 SGIInfo 889 iris_info; 890 891 register const Quantum 892 *p; 893 894 register ssize_t 895 i, 896 x; 897 898 register unsigned char 899 *q; 900 901 ssize_t 902 y, 903 z; 904 905 unsigned char 906 *pixels, 907 *packets; 908 909 /* 910 Open output image file. 911 */ 912 assert(image_info != (const ImageInfo *) NULL); 913 assert(image_info->signature == MagickCoreSignature); 914 assert(image != (Image *) NULL); 915 assert(image->signature == MagickCoreSignature); 916 if (image->debug != MagickFalse) 917 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 918 if ((image->columns > 65535UL) || (image->rows > 65535UL)) 919 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit"); 920 assert(exception != (ExceptionInfo *) NULL); 921 assert(exception->signature == MagickCoreSignature); 922 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 923 if (status == MagickFalse) 924 return(status); 925 scene=0; 926 do 927 { 928 /* 929 Initialize SGI raster file header. 930 */ 931 (void) TransformImageColorspace(image,sRGBColorspace,exception); 932 (void) ResetMagickMemory(&iris_info,0,sizeof(iris_info)); 933 iris_info.magic=0x01DA; 934 compression=image->compression; 935 if (image_info->compression != UndefinedCompression) 936 compression=image_info->compression; 937 if (image->depth > 8) 938 compression=NoCompression; 939 if (compression == NoCompression) 940 iris_info.storage=(unsigned char) 0x00; 941 else 942 iris_info.storage=(unsigned char) 0x01; 943 iris_info.bytes_per_pixel=(unsigned char) (image->depth > 8 ? 2 : 1); 944 iris_info.dimension=3; 945 iris_info.columns=(unsigned short) image->columns; 946 iris_info.rows=(unsigned short) image->rows; 947 if (image->alpha_trait != UndefinedPixelTrait) 948 iris_info.depth=4; 949 else 950 { 951 if ((image_info->type != TrueColorType) && 952 (SetImageGray(image,exception) != MagickFalse)) 953 { 954 iris_info.dimension=2; 955 iris_info.depth=1; 956 } 957 else 958 iris_info.depth=3; 959 } 960 iris_info.minimum_value=0; 961 iris_info.maximum_value=(size_t) (image->depth <= 8 ? 962 1UL*ScaleQuantumToChar(QuantumRange) : 963 1UL*ScaleQuantumToShort(QuantumRange)); 964 /* 965 Write SGI header. 966 */ 967 (void) WriteBlobMSBShort(image,iris_info.magic); 968 (void) WriteBlobByte(image,iris_info.storage); 969 (void) WriteBlobByte(image,iris_info.bytes_per_pixel); 970 (void) WriteBlobMSBShort(image,iris_info.dimension); 971 (void) WriteBlobMSBShort(image,iris_info.columns); 972 (void) WriteBlobMSBShort(image,iris_info.rows); 973 (void) WriteBlobMSBShort(image,iris_info.depth); 974 (void) WriteBlobMSBLong(image,(unsigned int) iris_info.minimum_value); 975 (void) WriteBlobMSBLong(image,(unsigned int) iris_info.maximum_value); 976 (void) WriteBlobMSBLong(image,(unsigned int) iris_info.sans); 977 value=GetImageProperty(image,"label",exception); 978 if (value != (const char *) NULL) 979 (void) CopyMagickString(iris_info.name,value,sizeof(iris_info.name)); 980 (void) WriteBlob(image,sizeof(iris_info.name),(unsigned char *) 981 iris_info.name); 982 (void) WriteBlobMSBLong(image,(unsigned int) iris_info.pixel_format); 983 (void) WriteBlob(image,sizeof(iris_info.filler),iris_info.filler); 984 /* 985 Allocate SGI pixels. 986 */ 987 number_pixels=(MagickSizeType) image->columns*image->rows; 988 if ((4*iris_info.bytes_per_pixel*number_pixels) != 989 ((MagickSizeType) (size_t) (4*iris_info.bytes_per_pixel*number_pixels))) 990 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 991 pixel_info=AcquireVirtualMemory((size_t) number_pixels,4* 992 iris_info.bytes_per_pixel*sizeof(*pixels)); 993 if (pixel_info == (MemoryInfo *) NULL) 994 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 995 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info); 996 /* 997 Convert image pixels to uncompressed SGI pixels. 998 */ 999 for (y=0; y < (ssize_t) image->rows; y++) 1000 { 1001 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 1002 if (p == (const Quantum *) NULL) 1003 break; 1004 if (image->depth <= 8) 1005 for (x=0; x < (ssize_t) image->columns; x++) 1006 { 1007 register unsigned char 1008 *q; 1009 1010 q=(unsigned char *) pixels; 1011 q+=((iris_info.rows-1)-y)*(4*iris_info.columns)+4*x; 1012 *q++=ScaleQuantumToChar(GetPixelRed(image,p)); 1013 *q++=ScaleQuantumToChar(GetPixelGreen(image,p)); 1014 *q++=ScaleQuantumToChar(GetPixelBlue(image,p)); 1015 *q++=ScaleQuantumToChar(GetPixelAlpha(image,p)); 1016 p+=GetPixelChannels(image); 1017 } 1018 else 1019 for (x=0; x < (ssize_t) image->columns; x++) 1020 { 1021 register unsigned short 1022 *q; 1023 1024 q=(unsigned short *) pixels; 1025 q+=((iris_info.rows-1)-y)*(4*iris_info.columns)+4*x; 1026 *q++=ScaleQuantumToShort(GetPixelRed(image,p)); 1027 *q++=ScaleQuantumToShort(GetPixelGreen(image,p)); 1028 *q++=ScaleQuantumToShort(GetPixelBlue(image,p)); 1029 *q++=ScaleQuantumToShort(GetPixelAlpha(image,p)); 1030 p+=GetPixelChannels(image); 1031 } 1032 if (image->previous == (Image *) NULL) 1033 { 1034 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 1035 image->rows); 1036 if (status == MagickFalse) 1037 break; 1038 } 1039 } 1040 switch (compression) 1041 { 1042 case NoCompression: 1043 { 1044 /* 1045 Write uncompressed SGI pixels. 1046 */ 1047 for (z=0; z < (ssize_t) iris_info.depth; z++) 1048 { 1049 for (y=0; y < (ssize_t) iris_info.rows; y++) 1050 { 1051 if (image->depth <= 8) 1052 for (x=0; x < (ssize_t) iris_info.columns; x++) 1053 { 1054 register unsigned char 1055 *q; 1056 1057 q=(unsigned char *) pixels; 1058 q+=y*(4*iris_info.columns)+4*x+z; 1059 (void) WriteBlobByte(image,*q); 1060 } 1061 else 1062 for (x=0; x < (ssize_t) iris_info.columns; x++) 1063 { 1064 register unsigned short 1065 *q; 1066 1067 q=(unsigned short *) pixels; 1068 q+=y*(4*iris_info.columns)+4*x+z; 1069 (void) WriteBlobMSBShort(image,*q); 1070 } 1071 } 1072 } 1073 break; 1074 } 1075 default: 1076 { 1077 MemoryInfo 1078 *packet_info; 1079 1080 size_t 1081 length, 1082 number_packets, 1083 *runlength; 1084 1085 ssize_t 1086 offset, 1087 *offsets; 1088 1089 /* 1090 Convert SGI uncompressed pixels. 1091 */ 1092 offsets=(ssize_t *) AcquireQuantumMemory(iris_info.rows, 1093 iris_info.depth*sizeof(*offsets)); 1094 runlength=(size_t *) AcquireQuantumMemory(iris_info.rows, 1095 iris_info.depth*sizeof(*runlength)); 1096 packet_info=AcquireVirtualMemory((2*(size_t) iris_info.columns+10)* 1097 image->rows,4*sizeof(*packets)); 1098 if ((offsets == (ssize_t *) NULL) || 1099 (runlength == (size_t *) NULL) || 1100 (packet_info == (MemoryInfo *) NULL)) 1101 { 1102 if (offsets != (ssize_t *) NULL) 1103 offsets=(ssize_t *) RelinquishMagickMemory(offsets); 1104 if (runlength != (size_t *) NULL) 1105 runlength=(size_t *) RelinquishMagickMemory(runlength); 1106 if (packet_info != (MemoryInfo *) NULL) 1107 packet_info=RelinquishVirtualMemory(packet_info); 1108 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 1109 } 1110 packets=(unsigned char *) GetVirtualMemoryBlob(packet_info); 1111 offset=512+4*2*((ssize_t) iris_info.rows*iris_info.depth); 1112 number_packets=0; 1113 q=pixels; 1114 for (y=0; y < (ssize_t) iris_info.rows; y++) 1115 { 1116 for (z=0; z < (ssize_t) iris_info.depth; z++) 1117 { 1118 length=SGIEncode(q+z,(size_t) iris_info.columns,packets+ 1119 number_packets); 1120 number_packets+=length; 1121 offsets[y+z*iris_info.rows]=offset; 1122 runlength[y+z*iris_info.rows]=(size_t) length; 1123 offset+=(ssize_t) length; 1124 } 1125 q+=(iris_info.columns*4); 1126 } 1127 /* 1128 Write out line start and length tables and runlength-encoded pixels. 1129 */ 1130 for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++) 1131 (void) WriteBlobMSBLong(image,(unsigned int) offsets[i]); 1132 for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++) 1133 (void) WriteBlobMSBLong(image,(unsigned int) runlength[i]); 1134 (void) WriteBlob(image,number_packets,packets); 1135 /* 1136 Relinquish resources. 1137 */ 1138 offsets=(ssize_t *) RelinquishMagickMemory(offsets); 1139 runlength=(size_t *) RelinquishMagickMemory(runlength); 1140 packet_info=RelinquishVirtualMemory(packet_info); 1141 break; 1142 } 1143 } 1144 pixel_info=RelinquishVirtualMemory(pixel_info); 1145 if (GetNextImageInList(image) == (Image *) NULL) 1146 break; 1147 image=SyncNextImageInList(image); 1148 status=SetImageProgress(image,SaveImagesTag,scene++, 1149 GetImageListLength(image)); 1150 if (status == MagickFalse) 1151 break; 1152 } while (image_info->adjoin != MagickFalse); 1153 (void) CloseBlob(image); 1154 return(MagickTrue); 1155 } 1156