sgi.c revision 45ef08fd6a09813e4a8f5ddadf85ba9e0ec2cdc7
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-2013 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 inline size_t MagickMin(const size_t x,const size_t y) 168{ 169 if (x < y) 170 return(x); 171 return(y); 172} 173 174static MagickBooleanType SGIDecode(const size_t bytes_per_pixel, 175 ssize_t number_packets,unsigned char *packets,ssize_t number_pixels, 176 unsigned char *pixels) 177{ 178 register unsigned char 179 *p, 180 *q; 181 182 size_t 183 pixel; 184 185 ssize_t 186 count; 187 188 p=packets; 189 q=pixels; 190 if (bytes_per_pixel == 2) 191 { 192 for ( ; number_pixels > 0; ) 193 { 194 if (number_packets-- == 0) 195 return(MagickFalse); 196 pixel=(size_t) (*p++) << 8; 197 pixel|=(*p++); 198 count=(ssize_t) (pixel & 0x7f); 199 if (count == 0) 200 break; 201 if (count > (ssize_t) number_pixels) 202 return(MagickFalse); 203 number_pixels-=count; 204 if ((pixel & 0x80) != 0) 205 for ( ; count != 0; count--) 206 { 207 if (number_packets-- == 0) 208 return(MagickFalse); 209 *q=(*p++); 210 *(q+1)=(*p++); 211 q+=8; 212 } 213 else 214 { 215 pixel=(size_t) (*p++) << 8; 216 pixel|=(*p++); 217 for ( ; count != 0; count--) 218 { 219 if (number_packets-- == 0) 220 return(MagickFalse); 221 *q=(unsigned char) (pixel >> 8); 222 *(q+1)=(unsigned char) pixel; 223 q+=8; 224 } 225 } 226 } 227 return(MagickTrue); 228 } 229 for ( ; number_pixels > 0; ) 230 { 231 if (number_packets-- == 0) 232 return(MagickFalse); 233 pixel=(size_t) (*p++); 234 count=(ssize_t) (pixel & 0x7f); 235 if (count == 0) 236 break; 237 if (count > (ssize_t) number_pixels) 238 return(MagickFalse); 239 number_pixels-=count; 240 if ((pixel & 0x80) != 0) 241 for ( ; count != 0; count--) 242 { 243 if (number_packets-- == 0) 244 return(MagickFalse); 245 *q=(*p++); 246 q+=4; 247 } 248 else 249 { 250 if (number_packets-- == 0) 251 return(MagickFalse); 252 pixel=(size_t) (*p++); 253 for ( ; count != 0; count--) 254 { 255 *q=(unsigned char) pixel; 256 q+=4; 257 } 258 } 259 } 260 return(MagickTrue); 261} 262 263static Image *ReadSGIImage(const ImageInfo *image_info,ExceptionInfo *exception) 264{ 265 Image 266 *image; 267 268 MagickBooleanType 269 status; 270 271 MagickSizeType 272 number_pixels; 273 274 register Quantum 275 *q; 276 277 register ssize_t 278 i, 279 x; 280 281 register unsigned char 282 *p; 283 284 SGIInfo 285 iris_info; 286 287 size_t 288 bytes_per_pixel, 289 quantum; 290 291 ssize_t 292 count, 293 y, 294 z; 295 296 unsigned char 297 *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,exception); 310 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 311 if (status == MagickFalse) 312 { 313 image=DestroyImageList(image); 314 return((Image *) NULL); 315 } 316 /* 317 Read SGI raster header. 318 */ 319 iris_info.magic=ReadBlobMSBShort(image); 320 do 321 { 322 /* 323 Verify SGI identifier. 324 */ 325 if (iris_info.magic != 0x01DA) 326 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 327 iris_info.storage=(unsigned char) ReadBlobByte(image); 328 switch (iris_info.storage) 329 { 330 case 0x00: image->compression=NoCompression; break; 331 case 0x01: image->compression=RLECompression; break; 332 default: 333 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 334 } 335 iris_info.bytes_per_pixel=(unsigned char) ReadBlobByte(image); 336 if ((iris_info.bytes_per_pixel == 0) || (iris_info.bytes_per_pixel > 2)) 337 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 338 iris_info.dimension=ReadBlobMSBShort(image); 339 iris_info.columns=ReadBlobMSBShort(image); 340 iris_info.rows=ReadBlobMSBShort(image); 341 iris_info.depth=ReadBlobMSBShort(image); 342 if ((iris_info.depth == 0) || (iris_info.depth > 4)) 343 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 344 iris_info.minimum_value=ReadBlobMSBLong(image); 345 iris_info.maximum_value=ReadBlobMSBLong(image); 346 iris_info.sans=ReadBlobMSBLong(image); 347 (void) ReadBlob(image,sizeof(iris_info.name),(unsigned char *) 348 iris_info.name); 349 iris_info.name[sizeof(iris_info.name)-1]='\0'; 350 if (*iris_info.name != '\0') 351 (void) SetImageProperty(image,"label",iris_info.name,exception); 352 iris_info.pixel_format=ReadBlobMSBLong(image); 353 if (iris_info.pixel_format != 0) 354 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 355 count=ReadBlob(image,sizeof(iris_info.filler),iris_info.filler); 356 (void) count; 357 image->columns=iris_info.columns; 358 image->rows=iris_info.rows; 359 image->depth=(size_t) MagickMin(iris_info.depth,MAGICKCORE_QUANTUM_DEPTH); 360 if (iris_info.pixel_format == 0) 361 image->depth=(size_t) MagickMin((size_t) 8* 362 iris_info.bytes_per_pixel,MAGICKCORE_QUANTUM_DEPTH); 363 if (iris_info.depth < 3) 364 { 365 image->storage_class=PseudoClass; 366 image->colors=iris_info.bytes_per_pixel > 1 ? 65535 : 256; 367 } 368 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0)) 369 if (image->scene >= (image_info->scene+image_info->number_scenes-1)) 370 break; 371 /* 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->alpha_trait=iris_info.depth == 4 ? BlendPixelTrait : 534 UndefinedPixelTrait; 535 image->columns=iris_info.columns; 536 image->rows=iris_info.rows; 537 /* 538 Convert SGI raster image to pixel packets. 539 */ 540 if (image->storage_class == DirectClass) 541 { 542 /* 543 Convert SGI image to DirectClass pixel packets. 544 */ 545 if (bytes_per_pixel == 2) 546 { 547 for (y=0; y < (ssize_t) image->rows; y++) 548 { 549 p=iris_pixels+(image->rows-y-1)*8*image->columns; 550 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 551 if (q == (Quantum *) NULL) 552 break; 553 for (x=0; x < (ssize_t) image->columns; x++) 554 { 555 SetPixelRed(image,ScaleShortToQuantum((unsigned short) 556 ((*(p+0) << 8) | (*(p+1)))),q); 557 SetPixelGreen(image,ScaleShortToQuantum((unsigned short) 558 ((*(p+2) << 8) | (*(p+3)))),q); 559 SetPixelBlue(image,ScaleShortToQuantum((unsigned short) 560 ((*(p+4) << 8) | (*(p+5)))),q); 561 SetPixelAlpha(image,OpaqueAlpha,q); 562 if (image->alpha_trait == BlendPixelTrait) 563 SetPixelAlpha(image,ScaleShortToQuantum((unsigned short) 564 ((*(p+6) << 8) | (*(p+7)))),q); 565 p+=8; 566 q+=GetPixelChannels(image); 567 } 568 if (SyncAuthenticPixels(image,exception) == MagickFalse) 569 break; 570 if (image->previous == (Image *) NULL) 571 { 572 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) 573 y,image->rows); 574 if (status == MagickFalse) 575 break; 576 } 577 } 578 } 579 else 580 for (y=0; y < (ssize_t) image->rows; y++) 581 { 582 p=iris_pixels+(image->rows-y-1)*4*image->columns; 583 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 584 if (q == (Quantum *) NULL) 585 break; 586 for (x=0; x < (ssize_t) image->columns; x++) 587 { 588 SetPixelRed(image,ScaleCharToQuantum(*p),q); 589 SetPixelGreen(image,ScaleCharToQuantum(*(p+1)),q); 590 SetPixelBlue(image,ScaleCharToQuantum(*(p+2)),q); 591 SetPixelAlpha(image,OpaqueAlpha,q); 592 if (image->alpha_trait == BlendPixelTrait) 593 SetPixelAlpha(image,ScaleCharToQuantum(*(p+3)),q); 594 p+=4; 595 q+=GetPixelChannels(image); 596 } 597 if (SyncAuthenticPixels(image,exception) == MagickFalse) 598 break; 599 if (image->previous == (Image *) NULL) 600 { 601 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, 602 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,exception) == 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 < (ssize_t) 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 == (Quantum *) NULL) 625 break; 626 for (x=0; x < (ssize_t) image->columns; x++) 627 { 628 quantum=(*p << 8); 629 quantum|=(*(p+1)); 630 SetPixelIndex(image,quantum,q); 631 p+=8; 632 q+=GetPixelChannels(image); 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 == (Quantum *) NULL) 651 break; 652 for (x=0; x < (ssize_t) image->columns; x++) 653 { 654 SetPixelIndex(image,*p,q); 655 p+=4; 656 q+=GetPixelChannels(image); 657 } 658 if (SyncAuthenticPixels(image,exception) == MagickFalse) 659 break; 660 if (image->previous == (Image *) NULL) 661 { 662 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, 663 image->rows); 664 if (status == MagickFalse) 665 break; 666 } 667 } 668 (void) SyncImage(image,exception); 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,exception); 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% size_t RegisterSGIImage(void) 727% 728*/ 729ModuleExport size_t 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, 785% Image *image,ExceptionInfo *exception) 786% 787% A description of each parameter follows. 788% 789% o image_info: the image info. 790% 791% o image: The image. 792% 793% o exception: return any errors or warnings in this structure. 794% 795*/ 796 797static size_t SGIEncode(unsigned char *pixels,size_t length, 798 unsigned char *packets) 799{ 800 short 801 runlength; 802 803 register unsigned char 804 *p, 805 *q; 806 807 unsigned char 808 *limit, 809 *mark; 810 811 p=pixels; 812 limit=p+length*4; 813 q=packets; 814 while (p < limit) 815 { 816 mark=p; 817 p+=8; 818 while ((p < limit) && ((*(p-8) != *(p-4)) || (*(p-4) != *p))) 819 p+=4; 820 p-=8; 821 length=(size_t) (p-mark) >> 2; 822 while (length != 0) 823 { 824 runlength=(short) (length > 126 ? 126 : length); 825 length-=runlength; 826 *q++=(unsigned char) (0x80 | runlength); 827 for ( ; runlength > 0; runlength--) 828 { 829 *q++=(*mark); 830 mark+=4; 831 } 832 } 833 mark=p; 834 p+=4; 835 while ((p < limit) && (*p == *mark)) 836 p+=4; 837 length=(size_t) (p-mark) >> 2; 838 while (length != 0) 839 { 840 runlength=(short) (length > 126 ? 126 : length); 841 length-=runlength; 842 *q++=(unsigned char) runlength; 843 *q++=(*mark); 844 } 845 } 846 *q++='\0'; 847 return((size_t) (q-packets)); 848} 849 850static MagickBooleanType WriteSGIImage(const ImageInfo *image_info,Image *image, 851 ExceptionInfo *exception) 852{ 853 CompressionType 854 compression; 855 856 const char 857 *value; 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 Quantum 872 *p; 873 874 register ssize_t 875 i, 876 x; 877 878 register unsigned char 879 *q; 880 881 ssize_t 882 y, 883 z; 884 885 unsigned char 886 *iris_pixels, 887 *packets; 888 889 /* 890 Open output image file. 891 */ 892 assert(image_info != (const ImageInfo *) NULL); 893 assert(image_info->signature == MagickSignature); 894 assert(image != (Image *) NULL); 895 assert(image->signature == MagickSignature); 896 if (image->debug != MagickFalse) 897 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 898 if ((image->columns > 65535UL) || (image->rows > 65535UL)) 899 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit"); 900 assert(exception != (ExceptionInfo *) NULL); 901 assert(exception->signature == MagickSignature); 902 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 903 if (status == MagickFalse) 904 return(status); 905 scene=0; 906 do 907 { 908 /* 909 Initialize SGI raster file header. 910 */ 911 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) 912 (void) TransformImageColorspace(image,sRGBColorspace,exception); 913 (void) ResetMagickMemory(&iris_info,0,sizeof(iris_info)); 914 iris_info.magic=0x01DA; 915 compression=image->compression; 916 if (image_info->compression != UndefinedCompression) 917 compression=image_info->compression; 918 if (image->depth > 8) 919 compression=NoCompression; 920 if (compression == NoCompression) 921 iris_info.storage=(unsigned char) 0x00; 922 else 923 iris_info.storage=(unsigned char) 0x01; 924 iris_info.bytes_per_pixel=(unsigned char) (image->depth > 8 ? 2 : 1); 925 iris_info.dimension=3; 926 iris_info.columns=(unsigned short) image->columns; 927 iris_info.rows=(unsigned short) image->rows; 928 if (image->alpha_trait == BlendPixelTrait) 929 iris_info.depth=4; 930 else 931 { 932 if ((image_info->type != TrueColorType) && 933 (IsImageGray(image,exception) != MagickFalse)) 934 { 935 iris_info.dimension=2; 936 iris_info.depth=1; 937 } 938 else 939 iris_info.depth=3; 940 } 941 iris_info.minimum_value=0; 942 iris_info.maximum_value=(size_t) (image->depth <= 8 ? 943 1UL*ScaleQuantumToChar(QuantumRange) : 944 1UL*ScaleQuantumToShort(QuantumRange)); 945 /* 946 Write SGI header. 947 */ 948 (void) WriteBlobMSBShort(image,iris_info.magic); 949 (void) WriteBlobByte(image,iris_info.storage); 950 (void) WriteBlobByte(image,iris_info.bytes_per_pixel); 951 (void) WriteBlobMSBShort(image,iris_info.dimension); 952 (void) WriteBlobMSBShort(image,iris_info.columns); 953 (void) WriteBlobMSBShort(image,iris_info.rows); 954 (void) WriteBlobMSBShort(image,iris_info.depth); 955 (void) WriteBlobMSBLong(image,(unsigned int) iris_info.minimum_value); 956 (void) WriteBlobMSBLong(image,(unsigned int) iris_info.maximum_value); 957 (void) WriteBlobMSBLong(image,(unsigned int) iris_info.sans); 958 value=GetImageProperty(image,"label",exception); 959 if (value != (const char *) NULL) 960 (void) CopyMagickString(iris_info.name,value,sizeof(iris_info.name)); 961 (void) WriteBlob(image,sizeof(iris_info.name),(unsigned char *) 962 iris_info.name); 963 (void) WriteBlobMSBLong(image,(unsigned int) iris_info.pixel_format); 964 (void) WriteBlob(image,sizeof(iris_info.filler),iris_info.filler); 965 /* 966 Allocate SGI pixels. 967 */ 968 number_pixels=(MagickSizeType) image->columns*image->rows; 969 if ((4*iris_info.bytes_per_pixel*number_pixels) != 970 ((MagickSizeType) (size_t) (4*iris_info.bytes_per_pixel*number_pixels))) 971 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 972 iris_pixels=(unsigned char *) AcquireQuantumMemory((size_t) number_pixels, 973 4*iris_info.bytes_per_pixel*sizeof(*iris_pixels)); 974 if (iris_pixels == (unsigned char *) NULL) 975 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 976 /* 977 Convert image pixels to uncompressed SGI pixels. 978 */ 979 for (y=0; y < (ssize_t) image->rows; y++) 980 { 981 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 982 if (p == (const Quantum *) NULL) 983 break; 984 if (image->depth <= 8) 985 for (x=0; x < (ssize_t) image->columns; x++) 986 { 987 register unsigned char 988 *q; 989 990 q=(unsigned char *) iris_pixels; 991 q+=((iris_info.rows-1)-y)*(4*iris_info.columns)+4*x; 992 *q++=ScaleQuantumToChar(GetPixelRed(image,p)); 993 *q++=ScaleQuantumToChar(GetPixelGreen(image,p)); 994 *q++=ScaleQuantumToChar(GetPixelBlue(image,p)); 995 *q++=ScaleQuantumToChar(GetPixelAlpha(image,p)); 996 p+=GetPixelChannels(image); 997 } 998 else 999 for (x=0; x < (ssize_t) image->columns; x++) 1000 { 1001 register unsigned short 1002 *q; 1003 1004 q=(unsigned short *) iris_pixels; 1005 q+=((iris_info.rows-1)-y)*(4*iris_info.columns)+4*x; 1006 *q++=ScaleQuantumToShort(GetPixelRed(image,p)); 1007 *q++=ScaleQuantumToShort(GetPixelGreen(image,p)); 1008 *q++=ScaleQuantumToShort(GetPixelBlue(image,p)); 1009 *q++=ScaleQuantumToShort(GetPixelAlpha(image,p)); 1010 p+=GetPixelChannels(image); 1011 } 1012 if (image->previous == (Image *) NULL) 1013 { 1014 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 1015 image->rows); 1016 if (status == MagickFalse) 1017 break; 1018 } 1019 } 1020 switch (compression) 1021 { 1022 case NoCompression: 1023 { 1024 /* 1025 Write uncompressed SGI pixels. 1026 */ 1027 for (z=0; z < (ssize_t) iris_info.depth; z++) 1028 { 1029 for (y=0; y < (ssize_t) iris_info.rows; y++) 1030 { 1031 if (image->depth <= 8) 1032 for (x=0; x < (ssize_t) iris_info.columns; x++) 1033 { 1034 register unsigned char 1035 *q; 1036 1037 q=(unsigned char *) iris_pixels; 1038 q+=y*(4*iris_info.columns)+4*x+z; 1039 (void) WriteBlobByte(image,*q); 1040 } 1041 else 1042 for (x=0; x < (ssize_t) iris_info.columns; x++) 1043 { 1044 register unsigned short 1045 *q; 1046 1047 q=(unsigned short *) iris_pixels; 1048 q+=y*(4*iris_info.columns)+4*x+z; 1049 (void) WriteBlobMSBShort(image,*q); 1050 } 1051 } 1052 } 1053 break; 1054 } 1055 default: 1056 { 1057 size_t 1058 length, 1059 number_packets, 1060 *runlength; 1061 1062 ssize_t 1063 offset, 1064 *offsets; 1065 1066 /* 1067 Convert SGI uncompressed pixels. 1068 */ 1069 offsets=(ssize_t *) AcquireQuantumMemory(iris_info.rows*iris_info.depth, 1070 sizeof(*offsets)); 1071 packets=(unsigned char *) AcquireQuantumMemory((2*(size_t) 1072 iris_info.columns+10)*image->rows,4*sizeof(*packets)); 1073 runlength=(size_t *) AcquireQuantumMemory(iris_info.rows, 1074 iris_info.depth*sizeof(*runlength)); 1075 if ((offsets == (ssize_t *) NULL) || 1076 (packets == (unsigned char *) NULL) || 1077 (runlength == (size_t *) NULL)) 1078 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 1079 offset=512+4*2*((ssize_t) iris_info.rows*iris_info.depth); 1080 number_packets=0; 1081 q=iris_pixels; 1082 for (y=0; y < (ssize_t) iris_info.rows; y++) 1083 { 1084 for (z=0; z < (ssize_t) iris_info.depth; z++) 1085 { 1086 length=SGIEncode(q+z,(size_t) iris_info.columns,packets+ 1087 number_packets); 1088 number_packets+=length; 1089 offsets[y+z*iris_info.rows]=offset; 1090 runlength[y+z*iris_info.rows]=(size_t) length; 1091 offset+=(ssize_t) length; 1092 } 1093 q+=(iris_info.columns*4); 1094 } 1095 /* 1096 Write out line start and length tables and runlength-encoded pixels. 1097 */ 1098 for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++) 1099 (void) WriteBlobMSBLong(image,(unsigned int) offsets[i]); 1100 for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++) 1101 (void) WriteBlobMSBLong(image,(unsigned int) runlength[i]); 1102 (void) WriteBlob(image,number_packets,packets); 1103 /* 1104 Relinquish resources. 1105 */ 1106 runlength=(size_t *) RelinquishMagickMemory(runlength); 1107 packets=(unsigned char *) RelinquishMagickMemory(packets); 1108 offsets=(ssize_t *) RelinquishMagickMemory(offsets); 1109 break; 1110 } 1111 } 1112 iris_pixels=(unsigned char *) RelinquishMagickMemory(iris_pixels); 1113 if (GetNextImageInList(image) == (Image *) NULL) 1114 break; 1115 image=SyncNextImageInList(image); 1116 status=SetImageProgress(image,SaveImagesTag,scene++, 1117 GetImageListLength(image)); 1118 if (status == MagickFalse) 1119 break; 1120 } while (image_info->adjoin != MagickFalse); 1121 (void) CloseBlob(image); 1122 return(MagickTrue); 1123} 1124