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