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