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-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/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 if (number_packets-- == 0) 213 return(MagickFalse); 214 pixel=(size_t) (*p++) << 8; 215 pixel|=(*p++); 216 for ( ; count != 0; count--) 217 { 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 n, 270 number_pixels; 271 272 MemoryInfo 273 *pixel_info; 274 275 register Quantum 276 *q; 277 278 register ssize_t 279 i, 280 x; 281 282 register unsigned char 283 *p; 284 285 SGIInfo 286 iris_info; 287 288 size_t 289 bytes_per_pixel, 290 quantum; 291 292 ssize_t 293 count, 294 y, 295 z; 296 297 unsigned char 298 *pixels; 299 300 /* 301 Open image file. 302 */ 303 assert(image_info != (const ImageInfo *) NULL); 304 assert(image_info->signature == MagickCoreSignature); 305 if (image_info->debug != MagickFalse) 306 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 307 image_info->filename); 308 assert(exception != (ExceptionInfo *) NULL); 309 assert(exception->signature == MagickCoreSignature); 310 image=AcquireImage(image_info,exception); 311 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 312 if (status == MagickFalse) 313 { 314 image=DestroyImageList(image); 315 return((Image *) NULL); 316 } 317 /* 318 Read SGI raster header. 319 */ 320 (void) memset(&iris_info,0,sizeof(iris_info)); 321 iris_info.magic=ReadBlobMSBShort(image); 322 do 323 { 324 /* 325 Verify SGI identifier. 326 */ 327 if (iris_info.magic != 0x01DA) 328 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 329 iris_info.storage=(unsigned char) ReadBlobByte(image); 330 switch (iris_info.storage) 331 { 332 case 0x00: image->compression=NoCompression; break; 333 case 0x01: image->compression=RLECompression; break; 334 default: 335 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 336 } 337 iris_info.bytes_per_pixel=(unsigned char) ReadBlobByte(image); 338 if ((iris_info.bytes_per_pixel == 0) || (iris_info.bytes_per_pixel > 2)) 339 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 340 iris_info.dimension=ReadBlobMSBShort(image); 341 if ((iris_info.dimension == 0) || (iris_info.dimension > 3)) 342 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 343 iris_info.columns=ReadBlobMSBShort(image); 344 iris_info.rows=ReadBlobMSBShort(image); 345 iris_info.depth=ReadBlobMSBShort(image); 346 if ((iris_info.depth == 0) || (iris_info.depth > 4)) 347 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 348 iris_info.minimum_value=ReadBlobMSBLong(image); 349 iris_info.maximum_value=ReadBlobMSBLong(image); 350 iris_info.sans=ReadBlobMSBLong(image); 351 count=ReadBlob(image,sizeof(iris_info.name),(unsigned char *) 352 iris_info.name); 353 if ((size_t) count != sizeof(iris_info.name)) 354 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 355 iris_info.name[sizeof(iris_info.name)-1]='\0'; 356 if (*iris_info.name != '\0') 357 (void) SetImageProperty(image,"label",iris_info.name,exception); 358 iris_info.pixel_format=ReadBlobMSBLong(image); 359 if (iris_info.pixel_format != 0) 360 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 361 count=ReadBlob(image,sizeof(iris_info.filler),iris_info.filler); 362 if ((size_t) count != sizeof(iris_info.filler)) 363 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 364 image->columns=iris_info.columns; 365 image->rows=iris_info.rows; 366 image->alpha_trait=iris_info.depth == 4 ? BlendPixelTrait : 367 UndefinedPixelTrait; 368 image->depth=(size_t) MagickMin(iris_info.depth,MAGICKCORE_QUANTUM_DEPTH); 369 if (iris_info.pixel_format == 0) 370 image->depth=(size_t) MagickMin((size_t) 8*iris_info.bytes_per_pixel, 371 MAGICKCORE_QUANTUM_DEPTH); 372 if (iris_info.depth < 3) 373 { 374 image->storage_class=PseudoClass; 375 image->colors=(size_t) (iris_info.bytes_per_pixel > 1 ? 65535 : 256); 376 } 377 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0)) 378 if (image->scene >= (image_info->scene+image_info->number_scenes-1)) 379 break; 380 if ((MagickSizeType) (image->columns*image->rows/255) > GetBlobSize(image)) 381 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile"); 382 status=SetImageExtent(image,image->columns,image->rows,exception); 383 if (status != MagickFalse) 384 status=ResetImagePixels(image,exception); 385 if (status == MagickFalse) 386 return(DestroyImageList(image)); 387 /* 388 Allocate SGI pixels. 389 */ 390 bytes_per_pixel=(size_t) iris_info.bytes_per_pixel; 391 number_pixels=(MagickSizeType) iris_info.columns*iris_info.rows; 392 if ((4*bytes_per_pixel*number_pixels) != ((MagickSizeType) (size_t) 393 (4*bytes_per_pixel*number_pixels))) 394 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 395 pixel_info=AcquireVirtualMemory(iris_info.columns,iris_info.rows*4* 396 bytes_per_pixel*sizeof(*pixels)); 397 if (pixel_info == (MemoryInfo *) NULL) 398 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 399 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info); 400 for (n=0; n < (4*bytes_per_pixel*number_pixels); n++) 401 pixels[n]=0; 402 if ((int) iris_info.storage != 0x01) 403 { 404 unsigned char 405 *scanline; 406 407 /* 408 Read standard image format. 409 */ 410 scanline=(unsigned char *) AcquireQuantumMemory(iris_info.columns, 411 bytes_per_pixel*sizeof(*scanline)); 412 if (scanline == (unsigned char *) NULL) 413 { 414 pixel_info=RelinquishVirtualMemory(pixel_info); 415 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 416 } 417 for (z=0; z < (ssize_t) iris_info.depth; z++) 418 { 419 p=pixels+bytes_per_pixel*z; 420 for (y=0; y < (ssize_t) iris_info.rows; y++) 421 { 422 count=ReadBlob(image,bytes_per_pixel*iris_info.columns,scanline); 423 if (count != (ssize_t) (bytes_per_pixel*iris_info.columns)) 424 break; 425 if (bytes_per_pixel == 2) 426 for (x=0; x < (ssize_t) iris_info.columns; x++) 427 { 428 *p=scanline[2*x]; 429 *(p+1)=scanline[2*x+1]; 430 p+=8; 431 } 432 else 433 for (x=0; x < (ssize_t) iris_info.columns; x++) 434 { 435 *p=scanline[x]; 436 p+=4; 437 } 438 } 439 if (y < (ssize_t) iris_info.rows) 440 break; 441 } 442 scanline=(unsigned char *) RelinquishMagickMemory(scanline); 443 } 444 else 445 { 446 MemoryInfo 447 *packet_info; 448 449 size_t 450 *runlength; 451 452 ssize_t 453 offset, 454 *offsets; 455 456 unsigned char 457 *packets; 458 459 unsigned int 460 data_order; 461 462 /* 463 Read runlength-encoded image format. 464 */ 465 offsets=(ssize_t *) AcquireQuantumMemory((size_t) iris_info.rows, 466 iris_info.depth*sizeof(*offsets)); 467 runlength=(size_t *) AcquireQuantumMemory(iris_info.rows, 468 iris_info.depth*sizeof(*runlength)); 469 packet_info=AcquireVirtualMemory((size_t) iris_info.columns+10UL,4UL* 470 sizeof(*packets)); 471 if ((offsets == (ssize_t *) NULL) || (runlength == (size_t *) NULL) || 472 (packet_info == (MemoryInfo *) NULL)) 473 { 474 offsets=(ssize_t *) RelinquishMagickMemory(offsets); 475 runlength=(size_t *) RelinquishMagickMemory(runlength); 476 if (packet_info != (MemoryInfo *) NULL) 477 packet_info=RelinquishVirtualMemory(packet_info); 478 pixel_info=RelinquishVirtualMemory(pixel_info); 479 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 480 } 481 packets=(unsigned char *) GetVirtualMemoryBlob(packet_info); 482 for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++) 483 offsets[i]=(ssize_t) ReadBlobMSBSignedLong(image); 484 for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++) 485 { 486 runlength[i]=ReadBlobMSBLong(image); 487 if (runlength[i] > (4*(size_t) iris_info.columns+10)) 488 { 489 packet_info=RelinquishVirtualMemory(packet_info); 490 runlength=(size_t *) RelinquishMagickMemory(runlength); 491 offsets=(ssize_t *) RelinquishMagickMemory(offsets); 492 pixel_info=RelinquishVirtualMemory(pixel_info); 493 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 494 } 495 } 496 /* 497 Check data order. 498 */ 499 offset=0; 500 data_order=0; 501 for (y=0; ((y < (ssize_t) iris_info.rows) && (data_order == 0)); y++) 502 for (z=0; ((z < (ssize_t) iris_info.depth) && (data_order == 0)); z++) 503 { 504 if (offsets[y+z*iris_info.rows] < offset) 505 data_order=1; 506 offset=offsets[y+z*iris_info.rows]; 507 } 508 offset=(ssize_t) TellBlob(image); 509 if (data_order == 1) 510 { 511 for (z=0; z < (ssize_t) iris_info.depth; z++) 512 { 513 p=pixels; 514 for (y=0; y < (ssize_t) iris_info.rows; y++) 515 { 516 if (offset != offsets[y+z*iris_info.rows]) 517 { 518 offset=offsets[y+z*iris_info.rows]; 519 offset=(ssize_t) SeekBlob(image,(MagickOffsetType) offset, 520 SEEK_SET); 521 } 522 count=ReadBlob(image,(size_t) runlength[y+z*iris_info.rows], 523 packets); 524 if (count != (ssize_t) runlength[y+z*iris_info.rows]) 525 break; 526 offset+=(ssize_t) runlength[y+z*iris_info.rows]; 527 status=SGIDecode(bytes_per_pixel,(ssize_t) 528 (runlength[y+z*iris_info.rows]/bytes_per_pixel),packets, 529 (ssize_t) iris_info.columns,p+bytes_per_pixel*z); 530 if (status == MagickFalse) 531 { 532 packet_info=RelinquishVirtualMemory(packet_info); 533 runlength=(size_t *) RelinquishMagickMemory(runlength); 534 offsets=(ssize_t *) RelinquishMagickMemory(offsets); 535 pixel_info=RelinquishVirtualMemory(pixel_info); 536 ThrowReaderException(CorruptImageError, 537 "ImproperImageHeader"); 538 } 539 p+=(iris_info.columns*4*bytes_per_pixel); 540 } 541 if (y < (ssize_t) iris_info.rows) 542 break; 543 } 544 } 545 else 546 { 547 MagickOffsetType 548 position; 549 550 position=TellBlob(image); 551 p=pixels; 552 for (y=0; y < (ssize_t) iris_info.rows; y++) 553 { 554 for (z=0; z < (ssize_t) iris_info.depth; z++) 555 { 556 if (offset != offsets[y+z*iris_info.rows]) 557 { 558 offset=offsets[y+z*iris_info.rows]; 559 offset=(ssize_t) SeekBlob(image,(MagickOffsetType) offset, 560 SEEK_SET); 561 } 562 count=ReadBlob(image,(size_t) runlength[y+z*iris_info.rows], 563 packets); 564 if (count != (ssize_t) runlength[y+z*iris_info.rows]) 565 break; 566 offset+=(ssize_t) runlength[y+z*iris_info.rows]; 567 status=SGIDecode(bytes_per_pixel,(ssize_t) 568 (runlength[y+z*iris_info.rows]/bytes_per_pixel),packets, 569 (ssize_t) iris_info.columns,p+bytes_per_pixel*z); 570 if (status == MagickFalse) 571 { 572 packet_info=RelinquishVirtualMemory(packet_info); 573 runlength=(size_t *) RelinquishMagickMemory(runlength); 574 offsets=(ssize_t *) RelinquishMagickMemory(offsets); 575 pixel_info=RelinquishVirtualMemory(pixel_info); 576 ThrowReaderException(CorruptImageError, 577 "ImproperImageHeader"); 578 } 579 } 580 if (z < (ssize_t) iris_info.depth) 581 break; 582 p+=(iris_info.columns*4*bytes_per_pixel); 583 } 584 offset=(ssize_t) SeekBlob(image,position,SEEK_SET); 585 } 586 packet_info=RelinquishVirtualMemory(packet_info); 587 runlength=(size_t *) RelinquishMagickMemory(runlength); 588 offsets=(ssize_t *) RelinquishMagickMemory(offsets); 589 } 590 /* 591 Convert SGI raster image to pixel packets. 592 */ 593 if (image->storage_class == DirectClass) 594 { 595 /* 596 Convert SGI image to DirectClass pixel packets. 597 */ 598 if (bytes_per_pixel == 2) 599 { 600 for (y=0; y < (ssize_t) image->rows; y++) 601 { 602 p=pixels+(image->rows-y-1)*8*image->columns; 603 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 604 if (q == (Quantum *) NULL) 605 break; 606 for (x=0; x < (ssize_t) image->columns; x++) 607 { 608 SetPixelRed(image,ScaleShortToQuantum((unsigned short) 609 ((*(p+0) << 8) | (*(p+1)))),q); 610 SetPixelGreen(image,ScaleShortToQuantum((unsigned short) 611 ((*(p+2) << 8) | (*(p+3)))),q); 612 SetPixelBlue(image,ScaleShortToQuantum((unsigned short) 613 ((*(p+4) << 8) | (*(p+5)))),q); 614 SetPixelAlpha(image,OpaqueAlpha,q); 615 if (image->alpha_trait != UndefinedPixelTrait) 616 SetPixelAlpha(image,ScaleShortToQuantum((unsigned short) 617 ((*(p+6) << 8) | (*(p+7)))),q); 618 p+=8; 619 q+=GetPixelChannels(image); 620 } 621 if (SyncAuthenticPixels(image,exception) == MagickFalse) 622 break; 623 if (image->previous == (Image *) NULL) 624 { 625 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) 626 y,image->rows); 627 if (status == MagickFalse) 628 break; 629 } 630 } 631 } 632 else 633 for (y=0; y < (ssize_t) image->rows; y++) 634 { 635 p=pixels+(image->rows-y-1)*4*image->columns; 636 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 637 if (q == (Quantum *) NULL) 638 break; 639 for (x=0; x < (ssize_t) image->columns; x++) 640 { 641 SetPixelRed(image,ScaleCharToQuantum(*p),q); 642 SetPixelGreen(image,ScaleCharToQuantum(*(p+1)),q); 643 SetPixelBlue(image,ScaleCharToQuantum(*(p+2)),q); 644 SetPixelAlpha(image,OpaqueAlpha,q); 645 if (image->alpha_trait != UndefinedPixelTrait) 646 SetPixelAlpha(image,ScaleCharToQuantum(*(p+3)),q); 647 p+=4; 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) y, 655 image->rows); 656 if (status == MagickFalse) 657 break; 658 } 659 } 660 } 661 else 662 { 663 /* 664 Create grayscale map. 665 */ 666 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse) 667 { 668 pixel_info=RelinquishVirtualMemory(pixel_info); 669 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 670 } 671 /* 672 Convert SGI image to PseudoClass pixel packets. 673 */ 674 if (bytes_per_pixel == 2) 675 { 676 for (y=0; y < (ssize_t) image->rows; y++) 677 { 678 p=pixels+(image->rows-y-1)*8*image->columns; 679 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 680 if (q == (Quantum *) NULL) 681 break; 682 for (x=0; x < (ssize_t) image->columns; x++) 683 { 684 quantum=(*p << 8); 685 quantum|=(*(p+1)); 686 SetPixelIndex(image,(Quantum) quantum,q); 687 p+=8; 688 q+=GetPixelChannels(image); 689 } 690 if (SyncAuthenticPixels(image,exception) == MagickFalse) 691 break; 692 if (image->previous == (Image *) NULL) 693 { 694 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) 695 y,image->rows); 696 if (status == MagickFalse) 697 break; 698 } 699 } 700 } 701 else 702 for (y=0; y < (ssize_t) image->rows; y++) 703 { 704 p=pixels+(image->rows-y-1)*4*image->columns; 705 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 706 if (q == (Quantum *) NULL) 707 break; 708 for (x=0; x < (ssize_t) image->columns; x++) 709 { 710 SetPixelIndex(image,*p,q); 711 p+=4; 712 q+=GetPixelChannels(image); 713 } 714 if (SyncAuthenticPixels(image,exception) == MagickFalse) 715 break; 716 if (image->previous == (Image *) NULL) 717 { 718 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, 719 image->rows); 720 if (status == MagickFalse) 721 break; 722 } 723 } 724 (void) SyncImage(image,exception); 725 } 726 pixel_info=RelinquishVirtualMemory(pixel_info); 727 if (EOFBlob(image) != MagickFalse) 728 { 729 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", 730 image->filename); 731 break; 732 } 733 /* 734 Proceed to next image. 735 */ 736 if (image_info->number_scenes != 0) 737 if (image->scene >= (image_info->scene+image_info->number_scenes-1)) 738 break; 739 iris_info.magic=ReadBlobMSBShort(image); 740 if (iris_info.magic == 0x01DA) 741 { 742 /* 743 Allocate next image structure. 744 */ 745 AcquireNextImage(image_info,image,exception); 746 if (GetNextImageInList(image) == (Image *) NULL) 747 { 748 status=MagickFalse; 749 break; 750 } 751 image=SyncNextImageInList(image); 752 status=SetImageProgress(image,LoadImagesTag,TellBlob(image), 753 GetBlobSize(image)); 754 if (status == MagickFalse) 755 break; 756 } 757 } while (iris_info.magic == 0x01DA); 758 (void) CloseBlob(image); 759 if (status == MagickFalse) 760 return(DestroyImageList(image)); 761 return(GetFirstImageInList(image)); 762 } 763 764 /* 766 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 767 % % 768 % % 769 % % 770 % R e g i s t e r S G I I m a g e % 771 % % 772 % % 773 % % 774 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 775 % 776 % RegisterSGIImage() adds properties for the SGI image format to 777 % the list of supported formats. The properties include the image format 778 % tag, a method to read and/or write the format, whether the format 779 % supports the saving of more than one frame to the same file or blob, 780 % whether the format supports native in-memory I/O, and a brief 781 % description of the format. 782 % 783 % The format of the RegisterSGIImage method is: 784 % 785 % size_t RegisterSGIImage(void) 786 % 787 */ 788 ModuleExport size_t RegisterSGIImage(void) 789 { 790 MagickInfo 791 *entry; 792 793 entry=AcquireMagickInfo("SGI","SGI","Irix RGB image"); 794 entry->decoder=(DecodeImageHandler *) ReadSGIImage; 795 entry->encoder=(EncodeImageHandler *) WriteSGIImage; 796 entry->magick=(IsImageFormatHandler *) IsSGI; 797 entry->flags|=CoderDecoderSeekableStreamFlag; 798 (void) RegisterMagickInfo(entry); 799 return(MagickImageCoderSignature); 800 } 801 802 /* 804 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 805 % % 806 % % 807 % % 808 % U n r e g i s t e r S G I I m a g e % 809 % % 810 % % 811 % % 812 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 813 % 814 % UnregisterSGIImage() removes format registrations made by the 815 % SGI module from the list of supported formats. 816 % 817 % The format of the UnregisterSGIImage method is: 818 % 819 % UnregisterSGIImage(void) 820 % 821 */ 822 ModuleExport void UnregisterSGIImage(void) 823 { 824 (void) UnregisterMagickInfo("SGI"); 825 } 826 827 /* 829 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 830 % % 831 % % 832 % % 833 % W r i t e S G I I m a g e % 834 % % 835 % % 836 % % 837 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 838 % 839 % WriteSGIImage() writes an image in SGI RGB encoded image format. 840 % 841 % The format of the WriteSGIImage method is: 842 % 843 % MagickBooleanType WriteSGIImage(const ImageInfo *image_info, 844 % Image *image,ExceptionInfo *exception) 845 % 846 % A description of each parameter follows. 847 % 848 % o image_info: the image info. 849 % 850 % o image: The image. 851 % 852 % o exception: return any errors or warnings in this structure. 853 % 854 */ 855 856 static size_t SGIEncode(unsigned char *pixels,size_t length, 857 unsigned char *packets) 858 { 859 short 860 runlength; 861 862 register unsigned char 863 *p, 864 *q; 865 866 unsigned char 867 *limit, 868 *mark; 869 870 p=pixels; 871 limit=p+length*4; 872 q=packets; 873 while (p < limit) 874 { 875 mark=p; 876 p+=8; 877 while ((p < limit) && ((*(p-8) != *(p-4)) || (*(p-4) != *p))) 878 p+=4; 879 p-=8; 880 length=(size_t) (p-mark) >> 2; 881 while (length != 0) 882 { 883 runlength=(short) (length > 126 ? 126 : length); 884 length-=runlength; 885 *q++=(unsigned char) (0x80 | runlength); 886 for ( ; runlength > 0; runlength--) 887 { 888 *q++=(*mark); 889 mark+=4; 890 } 891 } 892 mark=p; 893 p+=4; 894 while ((p < limit) && (*p == *mark)) 895 p+=4; 896 length=(size_t) (p-mark) >> 2; 897 while (length != 0) 898 { 899 runlength=(short) (length > 126 ? 126 : length); 900 length-=runlength; 901 *q++=(unsigned char) runlength; 902 *q++=(*mark); 903 } 904 } 905 *q++='\0'; 906 return((size_t) (q-packets)); 907 } 908 909 static MagickBooleanType WriteSGIImage(const ImageInfo *image_info,Image *image, 910 ExceptionInfo *exception) 911 { 912 CompressionType 913 compression; 914 915 const char 916 *value; 917 918 MagickBooleanType 919 status; 920 921 MagickOffsetType 922 scene; 923 924 MagickSizeType 925 number_pixels; 926 927 MemoryInfo 928 *pixel_info; 929 930 SGIInfo 931 iris_info; 932 933 register const Quantum 934 *p; 935 936 register ssize_t 937 i, 938 x; 939 940 register unsigned char 941 *q; 942 943 size_t 944 imageListLength; 945 946 ssize_t 947 y, 948 z; 949 950 unsigned char 951 *pixels, 952 *packets; 953 954 /* 955 Open output image file. 956 */ 957 assert(image_info != (const ImageInfo *) NULL); 958 assert(image_info->signature == MagickCoreSignature); 959 assert(image != (Image *) NULL); 960 assert(image->signature == MagickCoreSignature); 961 if (image->debug != MagickFalse) 962 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 963 if ((image->columns > 65535UL) || (image->rows > 65535UL)) 964 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit"); 965 assert(exception != (ExceptionInfo *) NULL); 966 assert(exception->signature == MagickCoreSignature); 967 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 968 if (status == MagickFalse) 969 return(status); 970 scene=0; 971 imageListLength=GetImageListLength(image); 972 do 973 { 974 /* 975 Initialize SGI raster file header. 976 */ 977 (void) TransformImageColorspace(image,sRGBColorspace,exception); 978 (void) memset(&iris_info,0,sizeof(iris_info)); 979 iris_info.magic=0x01DA; 980 compression=image->compression; 981 if (image_info->compression != UndefinedCompression) 982 compression=image_info->compression; 983 if (image->depth > 8) 984 compression=NoCompression; 985 if (compression == NoCompression) 986 iris_info.storage=(unsigned char) 0x00; 987 else 988 iris_info.storage=(unsigned char) 0x01; 989 iris_info.bytes_per_pixel=(unsigned char) (image->depth > 8 ? 2 : 1); 990 iris_info.dimension=3; 991 iris_info.columns=(unsigned short) image->columns; 992 iris_info.rows=(unsigned short) image->rows; 993 if (image->alpha_trait != UndefinedPixelTrait) 994 iris_info.depth=4; 995 else 996 { 997 if ((image_info->type != TrueColorType) && 998 (SetImageGray(image,exception) != MagickFalse)) 999 { 1000 iris_info.dimension=2; 1001 iris_info.depth=1; 1002 } 1003 else 1004 iris_info.depth=3; 1005 } 1006 iris_info.minimum_value=0; 1007 iris_info.maximum_value=(size_t) (image->depth <= 8 ? 1008 1UL*ScaleQuantumToChar(QuantumRange) : 1009 1UL*ScaleQuantumToShort(QuantumRange)); 1010 /* 1011 Write SGI header. 1012 */ 1013 (void) WriteBlobMSBShort(image,iris_info.magic); 1014 (void) WriteBlobByte(image,iris_info.storage); 1015 (void) WriteBlobByte(image,iris_info.bytes_per_pixel); 1016 (void) WriteBlobMSBShort(image,iris_info.dimension); 1017 (void) WriteBlobMSBShort(image,iris_info.columns); 1018 (void) WriteBlobMSBShort(image,iris_info.rows); 1019 (void) WriteBlobMSBShort(image,iris_info.depth); 1020 (void) WriteBlobMSBLong(image,(unsigned int) iris_info.minimum_value); 1021 (void) WriteBlobMSBLong(image,(unsigned int) iris_info.maximum_value); 1022 (void) WriteBlobMSBLong(image,(unsigned int) iris_info.sans); 1023 value=GetImageProperty(image,"label",exception); 1024 if (value != (const char *) NULL) 1025 (void) CopyMagickString(iris_info.name,value,sizeof(iris_info.name)); 1026 (void) WriteBlob(image,sizeof(iris_info.name),(unsigned char *) 1027 iris_info.name); 1028 (void) WriteBlobMSBLong(image,(unsigned int) iris_info.pixel_format); 1029 (void) WriteBlob(image,sizeof(iris_info.filler),iris_info.filler); 1030 /* 1031 Allocate SGI pixels. 1032 */ 1033 number_pixels=(MagickSizeType) image->columns*image->rows; 1034 if ((4*iris_info.bytes_per_pixel*number_pixels) != 1035 ((MagickSizeType) (size_t) (4*iris_info.bytes_per_pixel*number_pixels))) 1036 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 1037 pixel_info=AcquireVirtualMemory((size_t) number_pixels,4* 1038 iris_info.bytes_per_pixel*sizeof(*pixels)); 1039 if (pixel_info == (MemoryInfo *) NULL) 1040 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 1041 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info); 1042 /* 1043 Convert image pixels to uncompressed SGI pixels. 1044 */ 1045 for (y=0; y < (ssize_t) image->rows; y++) 1046 { 1047 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 1048 if (p == (const Quantum *) NULL) 1049 break; 1050 if (image->depth <= 8) 1051 for (x=0; x < (ssize_t) image->columns; x++) 1052 { 1053 register unsigned char 1054 *q; 1055 1056 q=(unsigned char *) pixels; 1057 q+=((iris_info.rows-1)-y)*(4*iris_info.columns)+4*x; 1058 *q++=ScaleQuantumToChar(GetPixelRed(image,p)); 1059 *q++=ScaleQuantumToChar(GetPixelGreen(image,p)); 1060 *q++=ScaleQuantumToChar(GetPixelBlue(image,p)); 1061 *q++=ScaleQuantumToChar(GetPixelAlpha(image,p)); 1062 p+=GetPixelChannels(image); 1063 } 1064 else 1065 for (x=0; x < (ssize_t) image->columns; x++) 1066 { 1067 register unsigned short 1068 *q; 1069 1070 q=(unsigned short *) pixels; 1071 q+=((iris_info.rows-1)-y)*(4*iris_info.columns)+4*x; 1072 *q++=ScaleQuantumToShort(GetPixelRed(image,p)); 1073 *q++=ScaleQuantumToShort(GetPixelGreen(image,p)); 1074 *q++=ScaleQuantumToShort(GetPixelBlue(image,p)); 1075 *q++=ScaleQuantumToShort(GetPixelAlpha(image,p)); 1076 p+=GetPixelChannels(image); 1077 } 1078 if (image->previous == (Image *) NULL) 1079 { 1080 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 1081 image->rows); 1082 if (status == MagickFalse) 1083 break; 1084 } 1085 } 1086 switch (compression) 1087 { 1088 case NoCompression: 1089 { 1090 /* 1091 Write uncompressed SGI pixels. 1092 */ 1093 for (z=0; z < (ssize_t) iris_info.depth; z++) 1094 { 1095 for (y=0; y < (ssize_t) iris_info.rows; y++) 1096 { 1097 if (image->depth <= 8) 1098 for (x=0; x < (ssize_t) iris_info.columns; x++) 1099 { 1100 register unsigned char 1101 *q; 1102 1103 q=(unsigned char *) pixels; 1104 q+=y*(4*iris_info.columns)+4*x+z; 1105 (void) WriteBlobByte(image,*q); 1106 } 1107 else 1108 for (x=0; x < (ssize_t) iris_info.columns; x++) 1109 { 1110 register unsigned short 1111 *q; 1112 1113 q=(unsigned short *) pixels; 1114 q+=y*(4*iris_info.columns)+4*x+z; 1115 (void) WriteBlobMSBShort(image,*q); 1116 } 1117 } 1118 } 1119 break; 1120 } 1121 default: 1122 { 1123 MemoryInfo 1124 *packet_info; 1125 1126 size_t 1127 length, 1128 number_packets, 1129 *runlength; 1130 1131 ssize_t 1132 offset, 1133 *offsets; 1134 1135 /* 1136 Convert SGI uncompressed pixels. 1137 */ 1138 offsets=(ssize_t *) AcquireQuantumMemory(iris_info.rows, 1139 iris_info.depth*sizeof(*offsets)); 1140 runlength=(size_t *) AcquireQuantumMemory(iris_info.rows, 1141 iris_info.depth*sizeof(*runlength)); 1142 packet_info=AcquireVirtualMemory((2*(size_t) iris_info.columns+10)* 1143 image->rows,4*sizeof(*packets)); 1144 if ((offsets == (ssize_t *) NULL) || 1145 (runlength == (size_t *) NULL) || 1146 (packet_info == (MemoryInfo *) NULL)) 1147 { 1148 if (offsets != (ssize_t *) NULL) 1149 offsets=(ssize_t *) RelinquishMagickMemory(offsets); 1150 if (runlength != (size_t *) NULL) 1151 runlength=(size_t *) RelinquishMagickMemory(runlength); 1152 if (packet_info != (MemoryInfo *) NULL) 1153 packet_info=RelinquishVirtualMemory(packet_info); 1154 pixel_info=RelinquishVirtualMemory(pixel_info); 1155 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 1156 } 1157 packets=(unsigned char *) GetVirtualMemoryBlob(packet_info); 1158 offset=512+4*2*((ssize_t) iris_info.rows*iris_info.depth); 1159 number_packets=0; 1160 q=pixels; 1161 for (y=0; y < (ssize_t) iris_info.rows; y++) 1162 { 1163 for (z=0; z < (ssize_t) iris_info.depth; z++) 1164 { 1165 length=SGIEncode(q+z,(size_t) iris_info.columns,packets+ 1166 number_packets); 1167 number_packets+=length; 1168 offsets[y+z*iris_info.rows]=offset; 1169 runlength[y+z*iris_info.rows]=(size_t) length; 1170 offset+=(ssize_t) length; 1171 } 1172 q+=(iris_info.columns*4); 1173 } 1174 /* 1175 Write out line start and length tables and runlength-encoded pixels. 1176 */ 1177 for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++) 1178 (void) WriteBlobMSBLong(image,(unsigned int) offsets[i]); 1179 for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++) 1180 (void) WriteBlobMSBLong(image,(unsigned int) runlength[i]); 1181 (void) WriteBlob(image,number_packets,packets); 1182 /* 1183 Relinquish resources. 1184 */ 1185 offsets=(ssize_t *) RelinquishMagickMemory(offsets); 1186 runlength=(size_t *) RelinquishMagickMemory(runlength); 1187 packet_info=RelinquishVirtualMemory(packet_info); 1188 break; 1189 } 1190 } 1191 pixel_info=RelinquishVirtualMemory(pixel_info); 1192 if (GetNextImageInList(image) == (Image *) NULL) 1193 break; 1194 image=SyncNextImageInList(image); 1195 status=SetImageProgress(image,SaveImagesTag,scene++,imageListLength); 1196 if (status == MagickFalse) 1197 break; 1198 } while (image_info->adjoin != MagickFalse); 1199 (void) CloseBlob(image); 1200 return(MagickTrue); 1201 } 1202