blob: d9d0f8a2175abcb6b7ca197ecdfd7b593b1b5203 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
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 %
cristyde984cd2013-12-01 14:49:27 +000016% Cristy %
cristy3ed852e2009-09-05 21:47:34 +000017% July 1992 %
18% %
19% %
cristyb56bb242014-11-25 17:12:48 +000020% Copyright 1999-2015 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% 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*/
cristy4c08aed2011-07-01 19:47:50 +000042#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"
cristy510d06a2011-07-06 23:43:54 +000051#include "MagickCore/colorspace-private.h"
cristy4c08aed2011-07-01 19:47:50 +000052#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"
cristy3ed852e2009-09-05 21:47:34 +000067
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
cristybb503372010-05-27 20:51:26 +000086 size_t
cristy3ed852e2009-09-05 21:47:34 +000087 minimum_value,
88 maximum_value,
89 sans;
90
91 char
92 name[80];
93
cristybb503372010-05-27 20:51:26 +000094 size_t
cristy3ed852e2009-09-05 21:47:34 +000095 pixel_format;
96
97 unsigned char
98 filler[404];
99} SGIInfo;
100
101/*
102 Forward declarations.
103*/
104static MagickBooleanType
cristy3a37efd2011-08-28 20:31:03 +0000105 WriteSGIImage(const ImageInfo *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000106/*
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%
cristy3ed852e2009-09-05 21:47:34 +0000130*/
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,
cristybb503372010-05-27 20:51:26 +0000175 ssize_t number_packets,unsigned char *packets,ssize_t number_pixels,
cristy3ed852e2009-09-05 21:47:34 +0000176 unsigned char *pixels)
177{
178 register unsigned char
179 *p,
180 *q;
181
cristybb503372010-05-27 20:51:26 +0000182 size_t
cristy3ed852e2009-09-05 21:47:34 +0000183 pixel;
184
cristyc6da28e2011-04-28 01:41:35 +0000185 ssize_t
186 count;
187
cristy3ed852e2009-09-05 21:47:34 +0000188 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);
cristybb503372010-05-27 20:51:26 +0000196 pixel=(size_t) (*p++) << 8;
cristy3ed852e2009-09-05 21:47:34 +0000197 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 {
cristybb503372010-05-27 20:51:26 +0000215 pixel=(size_t) (*p++) << 8;
cristy3ed852e2009-09-05 21:47:34 +0000216 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);
cristybb503372010-05-27 20:51:26 +0000233 pixel=(size_t) (*p++);
cristy3ed852e2009-09-05 21:47:34 +0000234 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);
cristybb503372010-05-27 20:51:26 +0000252 pixel=(size_t) (*p++);
cristy3ed852e2009-09-05 21:47:34 +0000253 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
cristy3ed852e2009-09-05 21:47:34 +0000268 MagickBooleanType
269 status;
270
271 MagickSizeType
272 number_pixels;
273
cristyb64823d2013-06-30 20:58:24 +0000274 MemoryInfo
275 *pixel_info;
276
cristy4c08aed2011-07-01 19:47:50 +0000277 register Quantum
cristy667a8922010-12-29 13:43:35 +0000278 *q;
279
cristybb503372010-05-27 20:51:26 +0000280 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000281 i,
282 x;
283
cristy3ed852e2009-09-05 21:47:34 +0000284 register unsigned char
285 *p;
286
cristy3ed852e2009-09-05 21:47:34 +0000287 SGIInfo
288 iris_info;
289
290 size_t
cristy667a8922010-12-29 13:43:35 +0000291 bytes_per_pixel,
292 quantum;
293
294 ssize_t
295 count,
296 y,
297 z;
cristy3ed852e2009-09-05 21:47:34 +0000298
299 unsigned char
cristyb64823d2013-06-30 20:58:24 +0000300 *pixels;
cristy3ed852e2009-09-05 21:47:34 +0000301
cristy3ed852e2009-09-05 21:47:34 +0000302 /*
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);
cristy9950d572011-10-01 18:22:35 +0000312 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000313 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')
cristyd15e6592011-10-15 00:13:06 +0000354 (void) SetImageProperty(image,"label",iris_info.name,exception);
cristy3ed852e2009-09-05 21:47:34 +0000355 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);
cristyda16f162011-02-19 23:52:17 +0000359 (void) count;
cristy3ed852e2009-09-05 21:47:34 +0000360 image->columns=iris_info.columns;
361 image->rows=iris_info.rows;
cristybb503372010-05-27 20:51:26 +0000362 image->depth=(size_t) MagickMin(iris_info.depth,MAGICKCORE_QUANTUM_DEPTH);
cristy3ed852e2009-09-05 21:47:34 +0000363 if (iris_info.pixel_format == 0)
cristybb503372010-05-27 20:51:26 +0000364 image->depth=(size_t) MagickMin((size_t) 8*
cristy3ed852e2009-09-05 21:47:34 +0000365 iris_info.bytes_per_pixel,MAGICKCORE_QUANTUM_DEPTH);
366 if (iris_info.depth < 3)
367 {
368 image->storage_class=PseudoClass;
cristy667a8922010-12-29 13:43:35 +0000369 image->colors=iris_info.bytes_per_pixel > 1 ? 65535 : 256;
cristy3ed852e2009-09-05 21:47:34 +0000370 }
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;
cristyacabb842014-12-14 23:36:33 +0000374 status=SetImageExtent(image,image->columns,image->rows,exception);
375 if (status == MagickFalse)
376 return(DestroyImageList(image));
cristy3ed852e2009-09-05 21:47:34 +0000377 /*
378 Allocate SGI pixels.
379 */
380 bytes_per_pixel=(size_t) iris_info.bytes_per_pixel;
381 number_pixels=(MagickSizeType) iris_info.columns*iris_info.rows;
382 if ((4*bytes_per_pixel*number_pixels) != ((MagickSizeType) (size_t)
383 (4*bytes_per_pixel*number_pixels)))
384 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
cristyb64823d2013-06-30 20:58:24 +0000385 pixel_info=AcquireVirtualMemory(iris_info.columns,iris_info.rows*4*
386 bytes_per_pixel*sizeof(*pixels));
387 if (pixel_info == (MemoryInfo *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000388 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
cristyb64823d2013-06-30 20:58:24 +0000389 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +0000390 if ((int) iris_info.storage != 0x01)
391 {
392 unsigned char
393 *scanline;
394
395 /*
396 Read standard image format.
397 */
398 scanline=(unsigned char *) AcquireQuantumMemory(iris_info.columns,
399 bytes_per_pixel*sizeof(*scanline));
400 if (scanline == (unsigned char *) NULL)
401 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000402 for (z=0; z < (ssize_t) iris_info.depth; z++)
cristy3ed852e2009-09-05 21:47:34 +0000403 {
cristyb64823d2013-06-30 20:58:24 +0000404 p=pixels+bytes_per_pixel*z;
cristybb503372010-05-27 20:51:26 +0000405 for (y=0; y < (ssize_t) iris_info.rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000406 {
407 count=ReadBlob(image,bytes_per_pixel*iris_info.columns,scanline);
408 if (EOFBlob(image) != MagickFalse)
409 break;
410 if (bytes_per_pixel == 2)
cristybb503372010-05-27 20:51:26 +0000411 for (x=0; x < (ssize_t) iris_info.columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000412 {
413 *p=scanline[2*x];
414 *(p+1)=scanline[2*x+1];
415 p+=8;
416 }
417 else
cristybb503372010-05-27 20:51:26 +0000418 for (x=0; x < (ssize_t) iris_info.columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000419 {
420 *p=scanline[x];
421 p+=4;
422 }
423 }
424 }
425 scanline=(unsigned char *) RelinquishMagickMemory(scanline);
426 }
427 else
428 {
cristyb64823d2013-06-30 20:58:24 +0000429 MemoryInfo
430 *packet_info;
431
cristy667a8922010-12-29 13:43:35 +0000432 size_t
433 *runlength;
434
cristy3ed852e2009-09-05 21:47:34 +0000435 ssize_t
436 offset,
437 *offsets;
438
439 unsigned char
440 *packets;
441
442 unsigned int
443 data_order;
444
cristy3ed852e2009-09-05 21:47:34 +0000445 /*
446 Read runlength-encoded image format.
447 */
448 offsets=(ssize_t *) AcquireQuantumMemory((size_t) iris_info.rows,
449 iris_info.depth*sizeof(*offsets));
cristybb503372010-05-27 20:51:26 +0000450 runlength=(size_t *) AcquireQuantumMemory(iris_info.rows,
cristy3ed852e2009-09-05 21:47:34 +0000451 iris_info.depth*sizeof(*runlength));
cristyb64823d2013-06-30 20:58:24 +0000452 packet_info=AcquireVirtualMemory((size_t) iris_info.columns+10UL,4UL*
453 sizeof(*packets));
cristy3ed852e2009-09-05 21:47:34 +0000454 if ((offsets == (ssize_t *) NULL) ||
cristyb64823d2013-06-30 20:58:24 +0000455 (runlength == (size_t *) NULL) ||
456 (packet_info == (MemoryInfo *) NULL))
457 {
458 if (offsets == (ssize_t *) NULL)
459 offsets=(ssize_t *) RelinquishMagickMemory(offsets);
460 if (runlength == (size_t *) NULL)
461 runlength=(size_t *) RelinquishMagickMemory(runlength);
462 if (packet_info == (MemoryInfo *) NULL)
463 packet_info=RelinquishVirtualMemory(packet_info);
464 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
465 }
466 packets=(unsigned char *) GetVirtualMemoryBlob(packet_info);
cristybb503372010-05-27 20:51:26 +0000467 for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++)
cristy6cff05d2010-09-02 11:22:46 +0000468 offsets[i]=(int) ReadBlobMSBLong(image);
cristybb503372010-05-27 20:51:26 +0000469 for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++)
cristy3ed852e2009-09-05 21:47:34 +0000470 {
471 runlength[i]=ReadBlobMSBLong(image);
472 if (runlength[i] > (4*(size_t) iris_info.columns+10))
473 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
474 }
475 /*
476 Check data order.
477 */
478 offset=0;
479 data_order=0;
cristybb503372010-05-27 20:51:26 +0000480 for (y=0; ((y < (ssize_t) iris_info.rows) && (data_order == 0)); y++)
481 for (z=0; ((z < (ssize_t) iris_info.depth) && (data_order == 0)); z++)
cristy3ed852e2009-09-05 21:47:34 +0000482 {
483 if (offsets[y+z*iris_info.rows] < offset)
484 data_order=1;
485 offset=offsets[y+z*iris_info.rows];
486 }
487 offset=(ssize_t) TellBlob(image);
488 if (data_order == 1)
489 {
cristybb503372010-05-27 20:51:26 +0000490 for (z=0; z < (ssize_t) iris_info.depth; z++)
cristy3ed852e2009-09-05 21:47:34 +0000491 {
cristyb64823d2013-06-30 20:58:24 +0000492 p=pixels;
cristybb503372010-05-27 20:51:26 +0000493 for (y=0; y < (ssize_t) iris_info.rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000494 {
495 if (offset != offsets[y+z*iris_info.rows])
496 {
497 offset=offsets[y+z*iris_info.rows];
cristybb503372010-05-27 20:51:26 +0000498 offset=(ssize_t) SeekBlob(image,(ssize_t) offset,SEEK_SET);
cristy3ed852e2009-09-05 21:47:34 +0000499 }
500 count=ReadBlob(image,(size_t) runlength[y+z*iris_info.rows],
501 packets);
502 if (EOFBlob(image) != MagickFalse)
503 break;
cristyeaedf062010-05-29 22:36:02 +0000504 offset+=(ssize_t) runlength[y+z*iris_info.rows];
cristybb503372010-05-27 20:51:26 +0000505 status=SGIDecode(bytes_per_pixel,(ssize_t)
cristy3ed852e2009-09-05 21:47:34 +0000506 (runlength[y+z*iris_info.rows]/bytes_per_pixel),packets,
507 1L*iris_info.columns,p+bytes_per_pixel*z);
508 if (status == MagickFalse)
509 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
510 p+=(iris_info.columns*4*bytes_per_pixel);
511 }
512 }
513 }
514 else
515 {
516 MagickOffsetType
517 position;
518
519 position=TellBlob(image);
cristyb64823d2013-06-30 20:58:24 +0000520 p=pixels;
cristybb503372010-05-27 20:51:26 +0000521 for (y=0; y < (ssize_t) iris_info.rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000522 {
cristybb503372010-05-27 20:51:26 +0000523 for (z=0; z < (ssize_t) iris_info.depth; z++)
cristy3ed852e2009-09-05 21:47:34 +0000524 {
525 if (offset != offsets[y+z*iris_info.rows])
526 {
527 offset=offsets[y+z*iris_info.rows];
cristybb503372010-05-27 20:51:26 +0000528 offset=(ssize_t) SeekBlob(image,(ssize_t) offset,SEEK_SET);
cristy3ed852e2009-09-05 21:47:34 +0000529 }
530 count=ReadBlob(image,(size_t) runlength[y+z*iris_info.rows],
531 packets);
532 if (EOFBlob(image) != MagickFalse)
533 break;
cristyeaedf062010-05-29 22:36:02 +0000534 offset+=(ssize_t) runlength[y+z*iris_info.rows];
cristybb503372010-05-27 20:51:26 +0000535 status=SGIDecode(bytes_per_pixel,(ssize_t)
cristy3ed852e2009-09-05 21:47:34 +0000536 (runlength[y+z*iris_info.rows]/bytes_per_pixel),packets,
537 1L*iris_info.columns,p+bytes_per_pixel*z);
538 if (status == MagickFalse)
539 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
540 }
541 p+=(iris_info.columns*4*bytes_per_pixel);
542 }
543 offset=(ssize_t) SeekBlob(image,position,SEEK_SET);
544 }
cristyb64823d2013-06-30 20:58:24 +0000545 packet_info=RelinquishVirtualMemory(packet_info);
cristybb503372010-05-27 20:51:26 +0000546 runlength=(size_t *) RelinquishMagickMemory(runlength);
cristy3ed852e2009-09-05 21:47:34 +0000547 offsets=(ssize_t *) RelinquishMagickMemory(offsets);
548 }
549 /*
550 Initialize image structure.
551 */
cristyb0a657e2012-08-29 00:45:37 +0000552 image->alpha_trait=iris_info.depth == 4 ? BlendPixelTrait :
553 UndefinedPixelTrait;
cristy3ed852e2009-09-05 21:47:34 +0000554 image->columns=iris_info.columns;
555 image->rows=iris_info.rows;
556 /*
557 Convert SGI raster image to pixel packets.
558 */
559 if (image->storage_class == DirectClass)
560 {
561 /*
562 Convert SGI image to DirectClass pixel packets.
563 */
564 if (bytes_per_pixel == 2)
565 {
cristybb503372010-05-27 20:51:26 +0000566 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000567 {
cristyb64823d2013-06-30 20:58:24 +0000568 p=pixels+(image->rows-y-1)*8*image->columns;
cristy3ed852e2009-09-05 21:47:34 +0000569 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000570 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000571 break;
cristybb503372010-05-27 20:51:26 +0000572 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000573 {
cristy4c08aed2011-07-01 19:47:50 +0000574 SetPixelRed(image,ScaleShortToQuantum((unsigned short)
575 ((*(p+0) << 8) | (*(p+1)))),q);
576 SetPixelGreen(image,ScaleShortToQuantum((unsigned short)
577 ((*(p+2) << 8) | (*(p+3)))),q);
578 SetPixelBlue(image,ScaleShortToQuantum((unsigned short)
579 ((*(p+4) << 8) | (*(p+5)))),q);
580 SetPixelAlpha(image,OpaqueAlpha,q);
cristy17f11b02014-12-20 19:37:04 +0000581 if (image->alpha_trait != UndefinedPixelTrait)
cristy4c08aed2011-07-01 19:47:50 +0000582 SetPixelAlpha(image,ScaleShortToQuantum((unsigned short)
583 ((*(p+6) << 8) | (*(p+7)))),q);
cristy3ed852e2009-09-05 21:47:34 +0000584 p+=8;
cristyed231572011-07-14 02:18:59 +0000585 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000586 }
587 if (SyncAuthenticPixels(image,exception) == MagickFalse)
588 break;
589 if (image->previous == (Image *) NULL)
590 {
cristy667a8922010-12-29 13:43:35 +0000591 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
592 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000593 if (status == MagickFalse)
594 break;
595 }
596 }
597 }
598 else
cristybb503372010-05-27 20:51:26 +0000599 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000600 {
cristyb64823d2013-06-30 20:58:24 +0000601 p=pixels+(image->rows-y-1)*4*image->columns;
cristy3ed852e2009-09-05 21:47:34 +0000602 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000603 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000604 break;
cristybb503372010-05-27 20:51:26 +0000605 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000606 {
cristy4c08aed2011-07-01 19:47:50 +0000607 SetPixelRed(image,ScaleCharToQuantum(*p),q);
608 SetPixelGreen(image,ScaleCharToQuantum(*(p+1)),q);
609 SetPixelBlue(image,ScaleCharToQuantum(*(p+2)),q);
610 SetPixelAlpha(image,OpaqueAlpha,q);
cristy17f11b02014-12-20 19:37:04 +0000611 if (image->alpha_trait != UndefinedPixelTrait)
cristy4c08aed2011-07-01 19:47:50 +0000612 SetPixelAlpha(image,ScaleCharToQuantum(*(p+3)),q);
cristy3ed852e2009-09-05 21:47:34 +0000613 p+=4;
cristyed231572011-07-14 02:18:59 +0000614 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000615 }
616 if (SyncAuthenticPixels(image,exception) == MagickFalse)
617 break;
618 if (image->previous == (Image *) NULL)
619 {
cristycee97112010-05-28 00:44:52 +0000620 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
cristy4c08aed2011-07-01 19:47:50 +0000621 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000622 if (status == MagickFalse)
623 break;
624 }
625 }
626 }
627 else
628 {
629 /*
630 Create grayscale map.
631 */
cristy018f07f2011-09-04 21:15:19 +0000632 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000633 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
634 /*
635 Convert SGI image to PseudoClass pixel packets.
636 */
637 if (bytes_per_pixel == 2)
638 {
cristybb503372010-05-27 20:51:26 +0000639 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000640 {
cristyb64823d2013-06-30 20:58:24 +0000641 p=pixels+(image->rows-y-1)*8*image->columns;
cristy3ed852e2009-09-05 21:47:34 +0000642 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000643 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000644 break;
cristybb503372010-05-27 20:51:26 +0000645 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000646 {
647 quantum=(*p << 8);
648 quantum|=(*(p+1));
cristy4c08aed2011-07-01 19:47:50 +0000649 SetPixelIndex(image,quantum,q);
cristy3ed852e2009-09-05 21:47:34 +0000650 p+=8;
cristyed231572011-07-14 02:18:59 +0000651 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000652 }
653 if (SyncAuthenticPixels(image,exception) == MagickFalse)
654 break;
655 if (image->previous == (Image *) NULL)
656 {
cristy667a8922010-12-29 13:43:35 +0000657 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
658 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000659 if (status == MagickFalse)
660 break;
661 }
662 }
663 }
664 else
cristybb503372010-05-27 20:51:26 +0000665 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000666 {
cristyb64823d2013-06-30 20:58:24 +0000667 p=pixels+(image->rows-y-1)*4*image->columns;
cristy3ed852e2009-09-05 21:47:34 +0000668 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000669 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000670 break;
cristybb503372010-05-27 20:51:26 +0000671 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000672 {
cristy4c08aed2011-07-01 19:47:50 +0000673 SetPixelIndex(image,*p,q);
cristy3ed852e2009-09-05 21:47:34 +0000674 p+=4;
cristyed231572011-07-14 02:18:59 +0000675 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000676 }
677 if (SyncAuthenticPixels(image,exception) == MagickFalse)
678 break;
679 if (image->previous == (Image *) NULL)
680 {
cristycee97112010-05-28 00:44:52 +0000681 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
682 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000683 if (status == MagickFalse)
684 break;
685 }
686 }
cristyea1a8aa2011-10-20 13:24:06 +0000687 (void) SyncImage(image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000688 }
cristyb64823d2013-06-30 20:58:24 +0000689 pixel_info=RelinquishVirtualMemory(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +0000690 if (EOFBlob(image) != MagickFalse)
691 {
692 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
693 image->filename);
694 break;
695 }
696 /*
697 Proceed to next image.
698 */
699 if (image_info->number_scenes != 0)
700 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
701 break;
702 iris_info.magic=ReadBlobMSBShort(image);
703 if (iris_info.magic == 0x01DA)
704 {
705 /*
706 Allocate next image structure.
707 */
cristy9950d572011-10-01 18:22:35 +0000708 AcquireNextImage(image_info,image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000709 if (GetNextImageInList(image) == (Image *) NULL)
710 {
711 image=DestroyImageList(image);
712 return((Image *) NULL);
713 }
714 image=SyncNextImageInList(image);
715 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
716 GetBlobSize(image));
717 if (status == MagickFalse)
718 break;
719 }
720 } while (iris_info.magic == 0x01DA);
721 (void) CloseBlob(image);
722 return(GetFirstImageInList(image));
723}
724
725/*
726%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
727% %
728% %
729% %
730% R e g i s t e r S G I I m a g e %
731% %
732% %
733% %
734%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
735%
736% RegisterSGIImage() adds properties for the SGI image format to
737% the list of supported formats. The properties include the image format
738% tag, a method to read and/or write the format, whether the format
739% supports the saving of more than one frame to the same file or blob,
740% whether the format supports native in-memory I/O, and a brief
741% description of the format.
742%
743% The format of the RegisterSGIImage method is:
744%
cristybb503372010-05-27 20:51:26 +0000745% size_t RegisterSGIImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000746%
747*/
cristybb503372010-05-27 20:51:26 +0000748ModuleExport size_t RegisterSGIImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000749{
750 MagickInfo
751 *entry;
752
753 entry=SetMagickInfo("SGI");
754 entry->decoder=(DecodeImageHandler *) ReadSGIImage;
755 entry->encoder=(EncodeImageHandler *) WriteSGIImage;
756 entry->magick=(IsImageFormatHandler *) IsSGI;
757 entry->description=ConstantString("Irix RGB image");
758 entry->module=ConstantString("SGI");
759 entry->seekable_stream=MagickTrue;
760 (void) RegisterMagickInfo(entry);
761 return(MagickImageCoderSignature);
762}
763
764/*
765%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
766% %
767% %
768% %
769% U n r e g i s t e r S G I I m a g e %
770% %
771% %
772% %
773%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
774%
775% UnregisterSGIImage() removes format registrations made by the
776% SGI module from the list of supported formats.
777%
778% The format of the UnregisterSGIImage method is:
779%
780% UnregisterSGIImage(void)
781%
782*/
783ModuleExport void UnregisterSGIImage(void)
784{
785 (void) UnregisterMagickInfo("SGI");
786}
787
788/*
789%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
790% %
791% %
792% %
793% W r i t e S G I I m a g e %
794% %
795% %
796% %
797%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
798%
799% WriteSGIImage() writes an image in SGI RGB encoded image format.
800%
801% The format of the WriteSGIImage method is:
802%
cristy3a37efd2011-08-28 20:31:03 +0000803% MagickBooleanType WriteSGIImage(const ImageInfo *image_info,
804% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000805%
806% A description of each parameter follows.
807%
808% o image_info: the image info.
809%
810% o image: The image.
811%
cristy3a37efd2011-08-28 20:31:03 +0000812% o exception: return any errors or warnings in this structure.
813%
cristy3ed852e2009-09-05 21:47:34 +0000814*/
815
816static size_t SGIEncode(unsigned char *pixels,size_t length,
817 unsigned char *packets)
818{
819 short
820 runlength;
821
822 register unsigned char
823 *p,
824 *q;
825
826 unsigned char
827 *limit,
828 *mark;
829
830 p=pixels;
831 limit=p+length*4;
832 q=packets;
833 while (p < limit)
834 {
835 mark=p;
836 p+=8;
837 while ((p < limit) && ((*(p-8) != *(p-4)) || (*(p-4) != *p)))
838 p+=4;
839 p-=8;
840 length=(size_t) (p-mark) >> 2;
841 while (length != 0)
842 {
843 runlength=(short) (length > 126 ? 126 : length);
844 length-=runlength;
845 *q++=(unsigned char) (0x80 | runlength);
846 for ( ; runlength > 0; runlength--)
847 {
848 *q++=(*mark);
849 mark+=4;
850 }
851 }
852 mark=p;
853 p+=4;
854 while ((p < limit) && (*p == *mark))
855 p+=4;
856 length=(size_t) (p-mark) >> 2;
857 while (length != 0)
858 {
859 runlength=(short) (length > 126 ? 126 : length);
860 length-=runlength;
861 *q++=(unsigned char) runlength;
862 *q++=(*mark);
863 }
864 }
865 *q++='\0';
866 return((size_t) (q-packets));
867}
868
cristy3a37efd2011-08-28 20:31:03 +0000869static MagickBooleanType WriteSGIImage(const ImageInfo *image_info,Image *image,
870 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000871{
872 CompressionType
873 compression;
874
875 const char
876 *value;
877
cristy3ed852e2009-09-05 21:47:34 +0000878 MagickBooleanType
879 status;
880
881 MagickOffsetType
882 scene;
883
884 MagickSizeType
885 number_pixels;
886
cristyb64823d2013-06-30 20:58:24 +0000887 MemoryInfo
888 *pixel_info;
889
cristy3ed852e2009-09-05 21:47:34 +0000890 SGIInfo
891 iris_info;
892
cristy4c08aed2011-07-01 19:47:50 +0000893 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000894 *p;
895
cristybb503372010-05-27 20:51:26 +0000896 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000897 i,
898 x;
899
900 register unsigned char
901 *q;
902
cristyc6da28e2011-04-28 01:41:35 +0000903 ssize_t
904 y,
905 z;
906
cristy3ed852e2009-09-05 21:47:34 +0000907 unsigned char
cristyb64823d2013-06-30 20:58:24 +0000908 *pixels,
cristy3ed852e2009-09-05 21:47:34 +0000909 *packets;
910
911 /*
912 Open output image file.
913 */
914 assert(image_info != (const ImageInfo *) NULL);
915 assert(image_info->signature == MagickSignature);
916 assert(image != (Image *) NULL);
917 assert(image->signature == MagickSignature);
918 if (image->debug != MagickFalse)
919 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
920 if ((image->columns > 65535UL) || (image->rows > 65535UL))
921 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
cristy3a37efd2011-08-28 20:31:03 +0000922 assert(exception != (ExceptionInfo *) NULL);
923 assert(exception->signature == MagickSignature);
924 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000925 if (status == MagickFalse)
926 return(status);
927 scene=0;
928 do
929 {
930 /*
931 Initialize SGI raster file header.
932 */
cristyaf8d3912014-02-21 14:50:33 +0000933 (void) TransformImageColorspace(image,sRGBColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +0000934 (void) ResetMagickMemory(&iris_info,0,sizeof(iris_info));
935 iris_info.magic=0x01DA;
936 compression=image->compression;
937 if (image_info->compression != UndefinedCompression)
938 compression=image_info->compression;
939 if (image->depth > 8)
940 compression=NoCompression;
941 if (compression == NoCompression)
942 iris_info.storage=(unsigned char) 0x00;
943 else
944 iris_info.storage=(unsigned char) 0x01;
945 iris_info.bytes_per_pixel=(unsigned char) (image->depth > 8 ? 2 : 1);
946 iris_info.dimension=3;
947 iris_info.columns=(unsigned short) image->columns;
948 iris_info.rows=(unsigned short) image->rows;
cristy17f11b02014-12-20 19:37:04 +0000949 if (image->alpha_trait != UndefinedPixelTrait)
cristy3ed852e2009-09-05 21:47:34 +0000950 iris_info.depth=4;
951 else
952 {
953 if ((image_info->type != TrueColorType) &&
cristy3a37efd2011-08-28 20:31:03 +0000954 (IsImageGray(image,exception) != MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +0000955 {
956 iris_info.dimension=2;
957 iris_info.depth=1;
958 }
959 else
960 iris_info.depth=3;
961 }
962 iris_info.minimum_value=0;
cristybb503372010-05-27 20:51:26 +0000963 iris_info.maximum_value=(size_t) (image->depth <= 8 ?
cristy6e963d82012-06-19 15:23:24 +0000964 1UL*ScaleQuantumToChar(QuantumRange) :
965 1UL*ScaleQuantumToShort(QuantumRange));
cristy3ed852e2009-09-05 21:47:34 +0000966 /*
967 Write SGI header.
968 */
969 (void) WriteBlobMSBShort(image,iris_info.magic);
970 (void) WriteBlobByte(image,iris_info.storage);
971 (void) WriteBlobByte(image,iris_info.bytes_per_pixel);
972 (void) WriteBlobMSBShort(image,iris_info.dimension);
973 (void) WriteBlobMSBShort(image,iris_info.columns);
974 (void) WriteBlobMSBShort(image,iris_info.rows);
975 (void) WriteBlobMSBShort(image,iris_info.depth);
cristyeaedf062010-05-29 22:36:02 +0000976 (void) WriteBlobMSBLong(image,(unsigned int) iris_info.minimum_value);
977 (void) WriteBlobMSBLong(image,(unsigned int) iris_info.maximum_value);
978 (void) WriteBlobMSBLong(image,(unsigned int) iris_info.sans);
cristyd15e6592011-10-15 00:13:06 +0000979 value=GetImageProperty(image,"label",exception);
cristy3ed852e2009-09-05 21:47:34 +0000980 if (value != (const char *) NULL)
981 (void) CopyMagickString(iris_info.name,value,sizeof(iris_info.name));
982 (void) WriteBlob(image,sizeof(iris_info.name),(unsigned char *)
983 iris_info.name);
cristy0b29b252010-05-30 01:59:46 +0000984 (void) WriteBlobMSBLong(image,(unsigned int) iris_info.pixel_format);
cristy3ed852e2009-09-05 21:47:34 +0000985 (void) WriteBlob(image,sizeof(iris_info.filler),iris_info.filler);
986 /*
987 Allocate SGI pixels.
988 */
989 number_pixels=(MagickSizeType) image->columns*image->rows;
990 if ((4*iris_info.bytes_per_pixel*number_pixels) !=
991 ((MagickSizeType) (size_t) (4*iris_info.bytes_per_pixel*number_pixels)))
992 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
cristyb64823d2013-06-30 20:58:24 +0000993 pixel_info=AcquireVirtualMemory((size_t) number_pixels,4*
994 iris_info.bytes_per_pixel*sizeof(*pixels));
995 if (pixel_info == (MemoryInfo *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000996 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
cristyb64823d2013-06-30 20:58:24 +0000997 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +0000998 /*
999 Convert image pixels to uncompressed SGI pixels.
1000 */
cristybb503372010-05-27 20:51:26 +00001001 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001002 {
cristy3a37efd2011-08-28 20:31:03 +00001003 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001004 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001005 break;
1006 if (image->depth <= 8)
cristybb503372010-05-27 20:51:26 +00001007 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001008 {
1009 register unsigned char
1010 *q;
1011
cristyb64823d2013-06-30 20:58:24 +00001012 q=(unsigned char *) pixels;
cristy3ed852e2009-09-05 21:47:34 +00001013 q+=((iris_info.rows-1)-y)*(4*iris_info.columns)+4*x;
cristy4c08aed2011-07-01 19:47:50 +00001014 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
1015 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
1016 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
1017 *q++=ScaleQuantumToChar(GetPixelAlpha(image,p));
cristyed231572011-07-14 02:18:59 +00001018 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001019 }
1020 else
cristybb503372010-05-27 20:51:26 +00001021 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001022 {
1023 register unsigned short
1024 *q;
1025
cristyb64823d2013-06-30 20:58:24 +00001026 q=(unsigned short *) pixels;
cristy3ed852e2009-09-05 21:47:34 +00001027 q+=((iris_info.rows-1)-y)*(4*iris_info.columns)+4*x;
cristy4c08aed2011-07-01 19:47:50 +00001028 *q++=ScaleQuantumToShort(GetPixelRed(image,p));
1029 *q++=ScaleQuantumToShort(GetPixelGreen(image,p));
1030 *q++=ScaleQuantumToShort(GetPixelBlue(image,p));
1031 *q++=ScaleQuantumToShort(GetPixelAlpha(image,p));
cristyed231572011-07-14 02:18:59 +00001032 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001033 }
1034 if (image->previous == (Image *) NULL)
1035 {
cristycee97112010-05-28 00:44:52 +00001036 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristyc6da28e2011-04-28 01:41:35 +00001037 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001038 if (status == MagickFalse)
1039 break;
1040 }
1041 }
1042 switch (compression)
1043 {
1044 case NoCompression:
1045 {
1046 /*
1047 Write uncompressed SGI pixels.
1048 */
cristybb503372010-05-27 20:51:26 +00001049 for (z=0; z < (ssize_t) iris_info.depth; z++)
cristy3ed852e2009-09-05 21:47:34 +00001050 {
cristybb503372010-05-27 20:51:26 +00001051 for (y=0; y < (ssize_t) iris_info.rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001052 {
1053 if (image->depth <= 8)
cristybb503372010-05-27 20:51:26 +00001054 for (x=0; x < (ssize_t) iris_info.columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001055 {
1056 register unsigned char
1057 *q;
1058
cristyb64823d2013-06-30 20:58:24 +00001059 q=(unsigned char *) pixels;
cristy3ed852e2009-09-05 21:47:34 +00001060 q+=y*(4*iris_info.columns)+4*x+z;
1061 (void) WriteBlobByte(image,*q);
1062 }
1063 else
cristybb503372010-05-27 20:51:26 +00001064 for (x=0; x < (ssize_t) iris_info.columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001065 {
1066 register unsigned short
1067 *q;
1068
cristyb64823d2013-06-30 20:58:24 +00001069 q=(unsigned short *) pixels;
cristy3ed852e2009-09-05 21:47:34 +00001070 q+=y*(4*iris_info.columns)+4*x+z;
1071 (void) WriteBlobMSBShort(image,*q);
1072 }
1073 }
1074 }
1075 break;
1076 }
1077 default:
1078 {
cristyb64823d2013-06-30 20:58:24 +00001079 MemoryInfo
1080 *packet_info;
1081
cristyc6da28e2011-04-28 01:41:35 +00001082 size_t
1083 length,
1084 number_packets,
1085 *runlength;
1086
cristy3ed852e2009-09-05 21:47:34 +00001087 ssize_t
1088 offset,
1089 *offsets;
1090
cristy3ed852e2009-09-05 21:47:34 +00001091 /*
1092 Convert SGI uncompressed pixels.
1093 */
cristyfa6de8c2014-05-18 16:34:44 +00001094 offsets=(ssize_t *) AcquireQuantumMemory(iris_info.rows,
1095 iris_info.depth*sizeof(*offsets));
cristybb503372010-05-27 20:51:26 +00001096 runlength=(size_t *) AcquireQuantumMemory(iris_info.rows,
cristy3ed852e2009-09-05 21:47:34 +00001097 iris_info.depth*sizeof(*runlength));
cristyb64823d2013-06-30 20:58:24 +00001098 packet_info=AcquireVirtualMemory((2*(size_t) iris_info.columns+10)*
1099 image->rows,4*sizeof(*packets));
cristy3ed852e2009-09-05 21:47:34 +00001100 if ((offsets == (ssize_t *) NULL) ||
cristyb64823d2013-06-30 20:58:24 +00001101 (runlength == (size_t *) NULL) ||
1102 (packet_info == (MemoryInfo *) NULL))
1103 {
1104 if (offsets != (ssize_t *) NULL)
1105 offsets=(ssize_t *) RelinquishMagickMemory(offsets);
1106 if (runlength != (size_t *) NULL)
1107 runlength=(size_t *) RelinquishMagickMemory(runlength);
1108 if (packet_info != (MemoryInfo *) NULL)
1109 packet_info=RelinquishVirtualMemory(packet_info);
1110 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1111 }
1112 packets=(unsigned char *) GetVirtualMemoryBlob(packet_info);
cristy3ed852e2009-09-05 21:47:34 +00001113 offset=512+4*2*((ssize_t) iris_info.rows*iris_info.depth);
1114 number_packets=0;
cristyb64823d2013-06-30 20:58:24 +00001115 q=pixels;
cristybb503372010-05-27 20:51:26 +00001116 for (y=0; y < (ssize_t) iris_info.rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001117 {
cristybb503372010-05-27 20:51:26 +00001118 for (z=0; z < (ssize_t) iris_info.depth; z++)
cristy3ed852e2009-09-05 21:47:34 +00001119 {
1120 length=SGIEncode(q+z,(size_t) iris_info.columns,packets+
1121 number_packets);
1122 number_packets+=length;
1123 offsets[y+z*iris_info.rows]=offset;
cristybb503372010-05-27 20:51:26 +00001124 runlength[y+z*iris_info.rows]=(size_t) length;
cristy3ed852e2009-09-05 21:47:34 +00001125 offset+=(ssize_t) length;
1126 }
1127 q+=(iris_info.columns*4);
1128 }
1129 /*
1130 Write out line start and length tables and runlength-encoded pixels.
1131 */
cristybb503372010-05-27 20:51:26 +00001132 for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++)
cristyf9cca6a2010-06-04 23:49:28 +00001133 (void) WriteBlobMSBLong(image,(unsigned int) offsets[i]);
cristybb503372010-05-27 20:51:26 +00001134 for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++)
cristyeaedf062010-05-29 22:36:02 +00001135 (void) WriteBlobMSBLong(image,(unsigned int) runlength[i]);
cristy3ed852e2009-09-05 21:47:34 +00001136 (void) WriteBlob(image,number_packets,packets);
1137 /*
1138 Relinquish resources.
1139 */
cristy3ed852e2009-09-05 21:47:34 +00001140 offsets=(ssize_t *) RelinquishMagickMemory(offsets);
cristyb64823d2013-06-30 20:58:24 +00001141 runlength=(size_t *) RelinquishMagickMemory(runlength);
1142 packet_info=RelinquishVirtualMemory(packet_info);
cristy3ed852e2009-09-05 21:47:34 +00001143 break;
1144 }
1145 }
cristyb64823d2013-06-30 20:58:24 +00001146 pixel_info=RelinquishVirtualMemory(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +00001147 if (GetNextImageInList(image) == (Image *) NULL)
1148 break;
1149 image=SyncNextImageInList(image);
1150 status=SetImageProgress(image,SaveImagesTag,scene++,
1151 GetImageListLength(image));
1152 if (status == MagickFalse)
1153 break;
1154 } while (image_info->adjoin != MagickFalse);
1155 (void) CloseBlob(image);
1156 return(MagickTrue);
1157}