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