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