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