blob: 100ce7c95b81c107f3a2a3a3d2f7f3528d043a31 [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
cristy3ed852e2009-09-05 21:47:34 +0000167static MagickBooleanType SGIDecode(const size_t bytes_per_pixel,
cristybb503372010-05-27 20:51:26 +0000168 ssize_t number_packets,unsigned char *packets,ssize_t number_pixels,
cristy3ed852e2009-09-05 21:47:34 +0000169 unsigned char *pixels)
170{
171 register unsigned char
172 *p,
173 *q;
174
cristybb503372010-05-27 20:51:26 +0000175 size_t
cristy3ed852e2009-09-05 21:47:34 +0000176 pixel;
177
cristyc6da28e2011-04-28 01:41:35 +0000178 ssize_t
179 count;
180
cristy3ed852e2009-09-05 21:47:34 +0000181 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);
cristybb503372010-05-27 20:51:26 +0000189 pixel=(size_t) (*p++) << 8;
cristy3ed852e2009-09-05 21:47:34 +0000190 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 {
cristybb503372010-05-27 20:51:26 +0000208 pixel=(size_t) (*p++) << 8;
cristy3ed852e2009-09-05 21:47:34 +0000209 pixel|=(*p++);
210 for ( ; count != 0; count--)
211 {
212 if (number_packets-- == 0)
213 return(MagickFalse);
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);
cristybb503372010-05-27 20:51:26 +0000226 pixel=(size_t) (*p++);
cristy3ed852e2009-09-05 21:47:34 +0000227 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);
cristybb503372010-05-27 20:51:26 +0000245 pixel=(size_t) (*p++);
cristy3ed852e2009-09-05 21:47:34 +0000246 for ( ; count != 0; count--)
247 {
248 *q=(unsigned char) pixel;
249 q+=4;
250 }
251 }
252 }
253 return(MagickTrue);
254}
255
256static Image *ReadSGIImage(const ImageInfo *image_info,ExceptionInfo *exception)
257{
258 Image
259 *image;
260
cristy3ed852e2009-09-05 21:47:34 +0000261 MagickBooleanType
262 status;
263
264 MagickSizeType
265 number_pixels;
266
cristyb64823d2013-06-30 20:58:24 +0000267 MemoryInfo
268 *pixel_info;
269
cristy4c08aed2011-07-01 19:47:50 +0000270 register Quantum
cristy667a8922010-12-29 13:43:35 +0000271 *q;
272
cristybb503372010-05-27 20:51:26 +0000273 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000274 i,
275 x;
276
cristy3ed852e2009-09-05 21:47:34 +0000277 register unsigned char
278 *p;
279
cristy3ed852e2009-09-05 21:47:34 +0000280 SGIInfo
281 iris_info;
282
283 size_t
cristy667a8922010-12-29 13:43:35 +0000284 bytes_per_pixel,
285 quantum;
286
287 ssize_t
288 count,
289 y,
290 z;
cristy3ed852e2009-09-05 21:47:34 +0000291
292 unsigned char
cristyb64823d2013-06-30 20:58:24 +0000293 *pixels;
cristy3ed852e2009-09-05 21:47:34 +0000294
cristy3ed852e2009-09-05 21:47:34 +0000295 /*
296 Open image file.
297 */
298 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000299 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000300 if (image_info->debug != MagickFalse)
301 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
302 image_info->filename);
303 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000304 assert(exception->signature == MagickCoreSignature);
cristy9950d572011-10-01 18:22:35 +0000305 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000306 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
307 if (status == MagickFalse)
308 {
309 image=DestroyImageList(image);
310 return((Image *) NULL);
311 }
312 /*
313 Read SGI raster header.
314 */
315 iris_info.magic=ReadBlobMSBShort(image);
316 do
317 {
318 /*
319 Verify SGI identifier.
320 */
321 if (iris_info.magic != 0x01DA)
322 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
323 iris_info.storage=(unsigned char) ReadBlobByte(image);
324 switch (iris_info.storage)
325 {
326 case 0x00: image->compression=NoCompression; break;
327 case 0x01: image->compression=RLECompression; break;
328 default:
329 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
330 }
331 iris_info.bytes_per_pixel=(unsigned char) ReadBlobByte(image);
332 if ((iris_info.bytes_per_pixel == 0) || (iris_info.bytes_per_pixel > 2))
333 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
334 iris_info.dimension=ReadBlobMSBShort(image);
335 iris_info.columns=ReadBlobMSBShort(image);
336 iris_info.rows=ReadBlobMSBShort(image);
337 iris_info.depth=ReadBlobMSBShort(image);
338 if ((iris_info.depth == 0) || (iris_info.depth > 4))
339 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
340 iris_info.minimum_value=ReadBlobMSBLong(image);
341 iris_info.maximum_value=ReadBlobMSBLong(image);
342 iris_info.sans=ReadBlobMSBLong(image);
343 (void) ReadBlob(image,sizeof(iris_info.name),(unsigned char *)
344 iris_info.name);
345 iris_info.name[sizeof(iris_info.name)-1]='\0';
346 if (*iris_info.name != '\0')
cristyd15e6592011-10-15 00:13:06 +0000347 (void) SetImageProperty(image,"label",iris_info.name,exception);
cristy3ed852e2009-09-05 21:47:34 +0000348 iris_info.pixel_format=ReadBlobMSBLong(image);
349 if (iris_info.pixel_format != 0)
350 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
351 count=ReadBlob(image,sizeof(iris_info.filler),iris_info.filler);
cristyda16f162011-02-19 23:52:17 +0000352 (void) count;
cristy3ed852e2009-09-05 21:47:34 +0000353 image->columns=iris_info.columns;
354 image->rows=iris_info.rows;
cristybb503372010-05-27 20:51:26 +0000355 image->depth=(size_t) MagickMin(iris_info.depth,MAGICKCORE_QUANTUM_DEPTH);
cristy3ed852e2009-09-05 21:47:34 +0000356 if (iris_info.pixel_format == 0)
cristybb503372010-05-27 20:51:26 +0000357 image->depth=(size_t) MagickMin((size_t) 8*
cristy3ed852e2009-09-05 21:47:34 +0000358 iris_info.bytes_per_pixel,MAGICKCORE_QUANTUM_DEPTH);
359 if (iris_info.depth < 3)
360 {
361 image->storage_class=PseudoClass;
cristy667a8922010-12-29 13:43:35 +0000362 image->colors=iris_info.bytes_per_pixel > 1 ? 65535 : 256;
cristy3ed852e2009-09-05 21:47:34 +0000363 }
364 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
365 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
366 break;
cristyacabb842014-12-14 23:36:33 +0000367 status=SetImageExtent(image,image->columns,image->rows,exception);
368 if (status == MagickFalse)
369 return(DestroyImageList(image));
cristy3ed852e2009-09-05 21:47:34 +0000370 /*
371 Allocate SGI pixels.
372 */
373 bytes_per_pixel=(size_t) iris_info.bytes_per_pixel;
374 number_pixels=(MagickSizeType) iris_info.columns*iris_info.rows;
375 if ((4*bytes_per_pixel*number_pixels) != ((MagickSizeType) (size_t)
376 (4*bytes_per_pixel*number_pixels)))
377 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
cristyb64823d2013-06-30 20:58:24 +0000378 pixel_info=AcquireVirtualMemory(iris_info.columns,iris_info.rows*4*
379 bytes_per_pixel*sizeof(*pixels));
380 if (pixel_info == (MemoryInfo *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000381 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
cristyb64823d2013-06-30 20:58:24 +0000382 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +0000383 if ((int) iris_info.storage != 0x01)
384 {
385 unsigned char
386 *scanline;
387
388 /*
389 Read standard image format.
390 */
391 scanline=(unsigned char *) AcquireQuantumMemory(iris_info.columns,
392 bytes_per_pixel*sizeof(*scanline));
393 if (scanline == (unsigned char *) NULL)
394 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000395 for (z=0; z < (ssize_t) iris_info.depth; z++)
cristy3ed852e2009-09-05 21:47:34 +0000396 {
cristyb64823d2013-06-30 20:58:24 +0000397 p=pixels+bytes_per_pixel*z;
cristybb503372010-05-27 20:51:26 +0000398 for (y=0; y < (ssize_t) iris_info.rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000399 {
400 count=ReadBlob(image,bytes_per_pixel*iris_info.columns,scanline);
401 if (EOFBlob(image) != MagickFalse)
402 break;
403 if (bytes_per_pixel == 2)
cristybb503372010-05-27 20:51:26 +0000404 for (x=0; x < (ssize_t) iris_info.columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000405 {
406 *p=scanline[2*x];
407 *(p+1)=scanline[2*x+1];
408 p+=8;
409 }
410 else
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[x];
414 p+=4;
415 }
416 }
417 }
418 scanline=(unsigned char *) RelinquishMagickMemory(scanline);
419 }
420 else
421 {
cristyb64823d2013-06-30 20:58:24 +0000422 MemoryInfo
423 *packet_info;
424
cristy667a8922010-12-29 13:43:35 +0000425 size_t
426 *runlength;
427
cristy3ed852e2009-09-05 21:47:34 +0000428 ssize_t
429 offset,
430 *offsets;
431
432 unsigned char
433 *packets;
434
435 unsigned int
436 data_order;
437
cristy3ed852e2009-09-05 21:47:34 +0000438 /*
439 Read runlength-encoded image format.
440 */
441 offsets=(ssize_t *) AcquireQuantumMemory((size_t) iris_info.rows,
442 iris_info.depth*sizeof(*offsets));
cristybb503372010-05-27 20:51:26 +0000443 runlength=(size_t *) AcquireQuantumMemory(iris_info.rows,
cristy3ed852e2009-09-05 21:47:34 +0000444 iris_info.depth*sizeof(*runlength));
cristyb64823d2013-06-30 20:58:24 +0000445 packet_info=AcquireVirtualMemory((size_t) iris_info.columns+10UL,4UL*
446 sizeof(*packets));
cristy3ed852e2009-09-05 21:47:34 +0000447 if ((offsets == (ssize_t *) NULL) ||
cristyb64823d2013-06-30 20:58:24 +0000448 (runlength == (size_t *) NULL) ||
449 (packet_info == (MemoryInfo *) NULL))
450 {
451 if (offsets == (ssize_t *) NULL)
452 offsets=(ssize_t *) RelinquishMagickMemory(offsets);
453 if (runlength == (size_t *) NULL)
454 runlength=(size_t *) RelinquishMagickMemory(runlength);
455 if (packet_info == (MemoryInfo *) NULL)
456 packet_info=RelinquishVirtualMemory(packet_info);
457 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
458 }
459 packets=(unsigned char *) GetVirtualMemoryBlob(packet_info);
cristybb503372010-05-27 20:51:26 +0000460 for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++)
cristy6cff05d2010-09-02 11:22:46 +0000461 offsets[i]=(int) ReadBlobMSBLong(image);
cristybb503372010-05-27 20:51:26 +0000462 for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++)
cristy3ed852e2009-09-05 21:47:34 +0000463 {
464 runlength[i]=ReadBlobMSBLong(image);
465 if (runlength[i] > (4*(size_t) iris_info.columns+10))
466 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
467 }
468 /*
469 Check data order.
470 */
471 offset=0;
472 data_order=0;
cristybb503372010-05-27 20:51:26 +0000473 for (y=0; ((y < (ssize_t) iris_info.rows) && (data_order == 0)); y++)
474 for (z=0; ((z < (ssize_t) iris_info.depth) && (data_order == 0)); z++)
cristy3ed852e2009-09-05 21:47:34 +0000475 {
476 if (offsets[y+z*iris_info.rows] < offset)
477 data_order=1;
478 offset=offsets[y+z*iris_info.rows];
479 }
480 offset=(ssize_t) TellBlob(image);
481 if (data_order == 1)
482 {
cristybb503372010-05-27 20:51:26 +0000483 for (z=0; z < (ssize_t) iris_info.depth; z++)
cristy3ed852e2009-09-05 21:47:34 +0000484 {
cristyb64823d2013-06-30 20:58:24 +0000485 p=pixels;
cristybb503372010-05-27 20:51:26 +0000486 for (y=0; y < (ssize_t) iris_info.rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000487 {
488 if (offset != offsets[y+z*iris_info.rows])
489 {
490 offset=offsets[y+z*iris_info.rows];
cristybb503372010-05-27 20:51:26 +0000491 offset=(ssize_t) SeekBlob(image,(ssize_t) offset,SEEK_SET);
cristy3ed852e2009-09-05 21:47:34 +0000492 }
493 count=ReadBlob(image,(size_t) runlength[y+z*iris_info.rows],
494 packets);
495 if (EOFBlob(image) != MagickFalse)
496 break;
cristyeaedf062010-05-29 22:36:02 +0000497 offset+=(ssize_t) runlength[y+z*iris_info.rows];
cristybb503372010-05-27 20:51:26 +0000498 status=SGIDecode(bytes_per_pixel,(ssize_t)
cristy3ed852e2009-09-05 21:47:34 +0000499 (runlength[y+z*iris_info.rows]/bytes_per_pixel),packets,
500 1L*iris_info.columns,p+bytes_per_pixel*z);
501 if (status == MagickFalse)
502 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
503 p+=(iris_info.columns*4*bytes_per_pixel);
504 }
505 }
506 }
507 else
508 {
509 MagickOffsetType
510 position;
511
512 position=TellBlob(image);
cristyb64823d2013-06-30 20:58:24 +0000513 p=pixels;
cristybb503372010-05-27 20:51:26 +0000514 for (y=0; y < (ssize_t) iris_info.rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000515 {
cristybb503372010-05-27 20:51:26 +0000516 for (z=0; z < (ssize_t) iris_info.depth; z++)
cristy3ed852e2009-09-05 21:47:34 +0000517 {
518 if (offset != offsets[y+z*iris_info.rows])
519 {
520 offset=offsets[y+z*iris_info.rows];
cristybb503372010-05-27 20:51:26 +0000521 offset=(ssize_t) SeekBlob(image,(ssize_t) offset,SEEK_SET);
cristy3ed852e2009-09-05 21:47:34 +0000522 }
523 count=ReadBlob(image,(size_t) runlength[y+z*iris_info.rows],
524 packets);
525 if (EOFBlob(image) != MagickFalse)
526 break;
cristyeaedf062010-05-29 22:36:02 +0000527 offset+=(ssize_t) runlength[y+z*iris_info.rows];
cristybb503372010-05-27 20:51:26 +0000528 status=SGIDecode(bytes_per_pixel,(ssize_t)
cristy3ed852e2009-09-05 21:47:34 +0000529 (runlength[y+z*iris_info.rows]/bytes_per_pixel),packets,
530 1L*iris_info.columns,p+bytes_per_pixel*z);
531 if (status == MagickFalse)
532 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
533 }
534 p+=(iris_info.columns*4*bytes_per_pixel);
535 }
536 offset=(ssize_t) SeekBlob(image,position,SEEK_SET);
537 }
cristyb64823d2013-06-30 20:58:24 +0000538 packet_info=RelinquishVirtualMemory(packet_info);
cristybb503372010-05-27 20:51:26 +0000539 runlength=(size_t *) RelinquishMagickMemory(runlength);
cristy3ed852e2009-09-05 21:47:34 +0000540 offsets=(ssize_t *) RelinquishMagickMemory(offsets);
541 }
542 /*
543 Initialize image structure.
544 */
cristyb0a657e2012-08-29 00:45:37 +0000545 image->alpha_trait=iris_info.depth == 4 ? BlendPixelTrait :
546 UndefinedPixelTrait;
cristy3ed852e2009-09-05 21:47:34 +0000547 image->columns=iris_info.columns;
548 image->rows=iris_info.rows;
549 /*
550 Convert SGI raster image to pixel packets.
551 */
552 if (image->storage_class == DirectClass)
553 {
554 /*
555 Convert SGI image to DirectClass pixel packets.
556 */
557 if (bytes_per_pixel == 2)
558 {
cristybb503372010-05-27 20:51:26 +0000559 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000560 {
cristyb64823d2013-06-30 20:58:24 +0000561 p=pixels+(image->rows-y-1)*8*image->columns;
cristy3ed852e2009-09-05 21:47:34 +0000562 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000563 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000564 break;
cristybb503372010-05-27 20:51:26 +0000565 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000566 {
cristy4c08aed2011-07-01 19:47:50 +0000567 SetPixelRed(image,ScaleShortToQuantum((unsigned short)
568 ((*(p+0) << 8) | (*(p+1)))),q);
569 SetPixelGreen(image,ScaleShortToQuantum((unsigned short)
570 ((*(p+2) << 8) | (*(p+3)))),q);
571 SetPixelBlue(image,ScaleShortToQuantum((unsigned short)
572 ((*(p+4) << 8) | (*(p+5)))),q);
573 SetPixelAlpha(image,OpaqueAlpha,q);
cristy17f11b02014-12-20 19:37:04 +0000574 if (image->alpha_trait != UndefinedPixelTrait)
cristy4c08aed2011-07-01 19:47:50 +0000575 SetPixelAlpha(image,ScaleShortToQuantum((unsigned short)
576 ((*(p+6) << 8) | (*(p+7)))),q);
cristy3ed852e2009-09-05 21:47:34 +0000577 p+=8;
cristyed231572011-07-14 02:18:59 +0000578 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000579 }
580 if (SyncAuthenticPixels(image,exception) == MagickFalse)
581 break;
582 if (image->previous == (Image *) NULL)
583 {
cristy667a8922010-12-29 13:43:35 +0000584 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
585 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000586 if (status == MagickFalse)
587 break;
588 }
589 }
590 }
591 else
cristybb503372010-05-27 20:51:26 +0000592 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000593 {
cristyb64823d2013-06-30 20:58:24 +0000594 p=pixels+(image->rows-y-1)*4*image->columns;
cristy3ed852e2009-09-05 21:47:34 +0000595 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000596 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000597 break;
cristybb503372010-05-27 20:51:26 +0000598 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000599 {
cristy4c08aed2011-07-01 19:47:50 +0000600 SetPixelRed(image,ScaleCharToQuantum(*p),q);
601 SetPixelGreen(image,ScaleCharToQuantum(*(p+1)),q);
602 SetPixelBlue(image,ScaleCharToQuantum(*(p+2)),q);
603 SetPixelAlpha(image,OpaqueAlpha,q);
cristy17f11b02014-12-20 19:37:04 +0000604 if (image->alpha_trait != UndefinedPixelTrait)
cristy4c08aed2011-07-01 19:47:50 +0000605 SetPixelAlpha(image,ScaleCharToQuantum(*(p+3)),q);
cristy3ed852e2009-09-05 21:47:34 +0000606 p+=4;
cristyed231572011-07-14 02:18:59 +0000607 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000608 }
609 if (SyncAuthenticPixels(image,exception) == MagickFalse)
610 break;
611 if (image->previous == (Image *) NULL)
612 {
cristycee97112010-05-28 00:44:52 +0000613 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
cristy4c08aed2011-07-01 19:47:50 +0000614 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000615 if (status == MagickFalse)
616 break;
617 }
618 }
619 }
620 else
621 {
622 /*
623 Create grayscale map.
624 */
cristy018f07f2011-09-04 21:15:19 +0000625 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000626 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
627 /*
628 Convert SGI image to PseudoClass pixel packets.
629 */
630 if (bytes_per_pixel == 2)
631 {
cristybb503372010-05-27 20:51:26 +0000632 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000633 {
cristyb64823d2013-06-30 20:58:24 +0000634 p=pixels+(image->rows-y-1)*8*image->columns;
cristy3ed852e2009-09-05 21:47:34 +0000635 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000636 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000637 break;
cristybb503372010-05-27 20:51:26 +0000638 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000639 {
640 quantum=(*p << 8);
641 quantum|=(*(p+1));
cristy4c08aed2011-07-01 19:47:50 +0000642 SetPixelIndex(image,quantum,q);
cristy3ed852e2009-09-05 21:47:34 +0000643 p+=8;
cristyed231572011-07-14 02:18:59 +0000644 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000645 }
646 if (SyncAuthenticPixels(image,exception) == MagickFalse)
647 break;
648 if (image->previous == (Image *) NULL)
649 {
cristy667a8922010-12-29 13:43:35 +0000650 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
651 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000652 if (status == MagickFalse)
653 break;
654 }
655 }
656 }
657 else
cristybb503372010-05-27 20:51:26 +0000658 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000659 {
cristyb64823d2013-06-30 20:58:24 +0000660 p=pixels+(image->rows-y-1)*4*image->columns;
cristy3ed852e2009-09-05 21:47:34 +0000661 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000662 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000663 break;
cristybb503372010-05-27 20:51:26 +0000664 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000665 {
cristy4c08aed2011-07-01 19:47:50 +0000666 SetPixelIndex(image,*p,q);
cristy3ed852e2009-09-05 21:47:34 +0000667 p+=4;
cristyed231572011-07-14 02:18:59 +0000668 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000669 }
670 if (SyncAuthenticPixels(image,exception) == MagickFalse)
671 break;
672 if (image->previous == (Image *) NULL)
673 {
cristycee97112010-05-28 00:44:52 +0000674 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
675 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000676 if (status == MagickFalse)
677 break;
678 }
679 }
cristyea1a8aa2011-10-20 13:24:06 +0000680 (void) SyncImage(image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000681 }
cristyb64823d2013-06-30 20:58:24 +0000682 pixel_info=RelinquishVirtualMemory(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +0000683 if (EOFBlob(image) != MagickFalse)
684 {
685 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
686 image->filename);
687 break;
688 }
689 /*
690 Proceed to next image.
691 */
692 if (image_info->number_scenes != 0)
693 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
694 break;
695 iris_info.magic=ReadBlobMSBShort(image);
696 if (iris_info.magic == 0x01DA)
697 {
698 /*
699 Allocate next image structure.
700 */
cristy9950d572011-10-01 18:22:35 +0000701 AcquireNextImage(image_info,image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000702 if (GetNextImageInList(image) == (Image *) NULL)
703 {
704 image=DestroyImageList(image);
705 return((Image *) NULL);
706 }
707 image=SyncNextImageInList(image);
708 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
709 GetBlobSize(image));
710 if (status == MagickFalse)
711 break;
712 }
713 } while (iris_info.magic == 0x01DA);
714 (void) CloseBlob(image);
715 return(GetFirstImageInList(image));
716}
717
718/*
719%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
720% %
721% %
722% %
723% R e g i s t e r S G I I m a g e %
724% %
725% %
726% %
727%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
728%
729% RegisterSGIImage() adds properties for the SGI image format to
730% the list of supported formats. The properties include the image format
731% tag, a method to read and/or write the format, whether the format
732% supports the saving of more than one frame to the same file or blob,
733% whether the format supports native in-memory I/O, and a brief
734% description of the format.
735%
736% The format of the RegisterSGIImage method is:
737%
cristybb503372010-05-27 20:51:26 +0000738% size_t RegisterSGIImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000739%
740*/
cristybb503372010-05-27 20:51:26 +0000741ModuleExport size_t RegisterSGIImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000742{
743 MagickInfo
744 *entry;
745
dirk06b627a2015-04-06 18:59:17 +0000746 entry=AcquireMagickInfo("SGI","SGI","Irix RGB image");
cristy3ed852e2009-09-05 21:47:34 +0000747 entry->decoder=(DecodeImageHandler *) ReadSGIImage;
748 entry->encoder=(EncodeImageHandler *) WriteSGIImage;
749 entry->magick=(IsImageFormatHandler *) IsSGI;
dirk08e9a112015-02-22 01:51:41 +0000750 entry->flags|=CoderSeekableStreamFlag;
cristy3ed852e2009-09-05 21:47:34 +0000751 (void) RegisterMagickInfo(entry);
752 return(MagickImageCoderSignature);
753}
754
755/*
756%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
757% %
758% %
759% %
760% U n r e g i s t e r S G I I m a g e %
761% %
762% %
763% %
764%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
765%
766% UnregisterSGIImage() removes format registrations made by the
767% SGI module from the list of supported formats.
768%
769% The format of the UnregisterSGIImage method is:
770%
771% UnregisterSGIImage(void)
772%
773*/
774ModuleExport void UnregisterSGIImage(void)
775{
776 (void) UnregisterMagickInfo("SGI");
777}
778
779/*
780%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
781% %
782% %
783% %
784% W r i t e S G I I m a g e %
785% %
786% %
787% %
788%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
789%
790% WriteSGIImage() writes an image in SGI RGB encoded image format.
791%
792% The format of the WriteSGIImage method is:
793%
cristy3a37efd2011-08-28 20:31:03 +0000794% MagickBooleanType WriteSGIImage(const ImageInfo *image_info,
795% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000796%
797% A description of each parameter follows.
798%
799% o image_info: the image info.
800%
801% o image: The image.
802%
cristy3a37efd2011-08-28 20:31:03 +0000803% o exception: return any errors or warnings in this structure.
804%
cristy3ed852e2009-09-05 21:47:34 +0000805*/
806
807static size_t SGIEncode(unsigned char *pixels,size_t length,
808 unsigned char *packets)
809{
810 short
811 runlength;
812
813 register unsigned char
814 *p,
815 *q;
816
817 unsigned char
818 *limit,
819 *mark;
820
821 p=pixels;
822 limit=p+length*4;
823 q=packets;
824 while (p < limit)
825 {
826 mark=p;
827 p+=8;
828 while ((p < limit) && ((*(p-8) != *(p-4)) || (*(p-4) != *p)))
829 p+=4;
830 p-=8;
831 length=(size_t) (p-mark) >> 2;
832 while (length != 0)
833 {
834 runlength=(short) (length > 126 ? 126 : length);
835 length-=runlength;
836 *q++=(unsigned char) (0x80 | runlength);
837 for ( ; runlength > 0; runlength--)
838 {
839 *q++=(*mark);
840 mark+=4;
841 }
842 }
843 mark=p;
844 p+=4;
845 while ((p < limit) && (*p == *mark))
846 p+=4;
847 length=(size_t) (p-mark) >> 2;
848 while (length != 0)
849 {
850 runlength=(short) (length > 126 ? 126 : length);
851 length-=runlength;
852 *q++=(unsigned char) runlength;
853 *q++=(*mark);
854 }
855 }
856 *q++='\0';
857 return((size_t) (q-packets));
858}
859
cristy3a37efd2011-08-28 20:31:03 +0000860static MagickBooleanType WriteSGIImage(const ImageInfo *image_info,Image *image,
861 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000862{
863 CompressionType
864 compression;
865
866 const char
867 *value;
868
cristy3ed852e2009-09-05 21:47:34 +0000869 MagickBooleanType
870 status;
871
872 MagickOffsetType
873 scene;
874
875 MagickSizeType
876 number_pixels;
877
cristyb64823d2013-06-30 20:58:24 +0000878 MemoryInfo
879 *pixel_info;
880
cristy3ed852e2009-09-05 21:47:34 +0000881 SGIInfo
882 iris_info;
883
cristy4c08aed2011-07-01 19:47:50 +0000884 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000885 *p;
886
cristybb503372010-05-27 20:51:26 +0000887 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000888 i,
889 x;
890
891 register unsigned char
892 *q;
893
cristyc6da28e2011-04-28 01:41:35 +0000894 ssize_t
895 y,
896 z;
897
cristy3ed852e2009-09-05 21:47:34 +0000898 unsigned char
cristyb64823d2013-06-30 20:58:24 +0000899 *pixels,
cristy3ed852e2009-09-05 21:47:34 +0000900 *packets;
901
902 /*
903 Open output image file.
904 */
905 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000906 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000907 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000908 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000909 if (image->debug != MagickFalse)
910 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
911 if ((image->columns > 65535UL) || (image->rows > 65535UL))
912 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
cristy3a37efd2011-08-28 20:31:03 +0000913 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000914 assert(exception->signature == MagickCoreSignature);
cristy3a37efd2011-08-28 20:31:03 +0000915 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000916 if (status == MagickFalse)
917 return(status);
918 scene=0;
919 do
920 {
921 /*
922 Initialize SGI raster file header.
923 */
cristyaf8d3912014-02-21 14:50:33 +0000924 (void) TransformImageColorspace(image,sRGBColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +0000925 (void) ResetMagickMemory(&iris_info,0,sizeof(iris_info));
926 iris_info.magic=0x01DA;
927 compression=image->compression;
928 if (image_info->compression != UndefinedCompression)
929 compression=image_info->compression;
930 if (image->depth > 8)
931 compression=NoCompression;
932 if (compression == NoCompression)
933 iris_info.storage=(unsigned char) 0x00;
934 else
935 iris_info.storage=(unsigned char) 0x01;
936 iris_info.bytes_per_pixel=(unsigned char) (image->depth > 8 ? 2 : 1);
937 iris_info.dimension=3;
938 iris_info.columns=(unsigned short) image->columns;
939 iris_info.rows=(unsigned short) image->rows;
cristy17f11b02014-12-20 19:37:04 +0000940 if (image->alpha_trait != UndefinedPixelTrait)
cristy3ed852e2009-09-05 21:47:34 +0000941 iris_info.depth=4;
942 else
943 {
944 if ((image_info->type != TrueColorType) &&
dirkf1d85482015-04-06 00:36:00 +0000945 (SetImageGray(image,exception) != MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +0000946 {
947 iris_info.dimension=2;
948 iris_info.depth=1;
949 }
950 else
951 iris_info.depth=3;
952 }
953 iris_info.minimum_value=0;
cristybb503372010-05-27 20:51:26 +0000954 iris_info.maximum_value=(size_t) (image->depth <= 8 ?
cristy6e963d82012-06-19 15:23:24 +0000955 1UL*ScaleQuantumToChar(QuantumRange) :
956 1UL*ScaleQuantumToShort(QuantumRange));
cristy3ed852e2009-09-05 21:47:34 +0000957 /*
958 Write SGI header.
959 */
960 (void) WriteBlobMSBShort(image,iris_info.magic);
961 (void) WriteBlobByte(image,iris_info.storage);
962 (void) WriteBlobByte(image,iris_info.bytes_per_pixel);
963 (void) WriteBlobMSBShort(image,iris_info.dimension);
964 (void) WriteBlobMSBShort(image,iris_info.columns);
965 (void) WriteBlobMSBShort(image,iris_info.rows);
966 (void) WriteBlobMSBShort(image,iris_info.depth);
cristyeaedf062010-05-29 22:36:02 +0000967 (void) WriteBlobMSBLong(image,(unsigned int) iris_info.minimum_value);
968 (void) WriteBlobMSBLong(image,(unsigned int) iris_info.maximum_value);
969 (void) WriteBlobMSBLong(image,(unsigned int) iris_info.sans);
cristyd15e6592011-10-15 00:13:06 +0000970 value=GetImageProperty(image,"label",exception);
cristy3ed852e2009-09-05 21:47:34 +0000971 if (value != (const char *) NULL)
972 (void) CopyMagickString(iris_info.name,value,sizeof(iris_info.name));
973 (void) WriteBlob(image,sizeof(iris_info.name),(unsigned char *)
974 iris_info.name);
cristy0b29b252010-05-30 01:59:46 +0000975 (void) WriteBlobMSBLong(image,(unsigned int) iris_info.pixel_format);
cristy3ed852e2009-09-05 21:47:34 +0000976 (void) WriteBlob(image,sizeof(iris_info.filler),iris_info.filler);
977 /*
978 Allocate SGI pixels.
979 */
980 number_pixels=(MagickSizeType) image->columns*image->rows;
981 if ((4*iris_info.bytes_per_pixel*number_pixels) !=
982 ((MagickSizeType) (size_t) (4*iris_info.bytes_per_pixel*number_pixels)))
983 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
cristyb64823d2013-06-30 20:58:24 +0000984 pixel_info=AcquireVirtualMemory((size_t) number_pixels,4*
985 iris_info.bytes_per_pixel*sizeof(*pixels));
986 if (pixel_info == (MemoryInfo *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000987 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
cristyb64823d2013-06-30 20:58:24 +0000988 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +0000989 /*
990 Convert image pixels to uncompressed SGI pixels.
991 */
cristybb503372010-05-27 20:51:26 +0000992 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000993 {
cristy3a37efd2011-08-28 20:31:03 +0000994 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000995 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000996 break;
997 if (image->depth <= 8)
cristybb503372010-05-27 20:51:26 +0000998 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000999 {
1000 register unsigned char
1001 *q;
1002
cristyb64823d2013-06-30 20:58:24 +00001003 q=(unsigned char *) pixels;
cristy3ed852e2009-09-05 21:47:34 +00001004 q+=((iris_info.rows-1)-y)*(4*iris_info.columns)+4*x;
cristy4c08aed2011-07-01 19:47:50 +00001005 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
1006 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
1007 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
1008 *q++=ScaleQuantumToChar(GetPixelAlpha(image,p));
cristyed231572011-07-14 02:18:59 +00001009 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001010 }
1011 else
cristybb503372010-05-27 20:51:26 +00001012 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001013 {
1014 register unsigned short
1015 *q;
1016
cristyb64823d2013-06-30 20:58:24 +00001017 q=(unsigned short *) pixels;
cristy3ed852e2009-09-05 21:47:34 +00001018 q+=((iris_info.rows-1)-y)*(4*iris_info.columns)+4*x;
cristy4c08aed2011-07-01 19:47:50 +00001019 *q++=ScaleQuantumToShort(GetPixelRed(image,p));
1020 *q++=ScaleQuantumToShort(GetPixelGreen(image,p));
1021 *q++=ScaleQuantumToShort(GetPixelBlue(image,p));
1022 *q++=ScaleQuantumToShort(GetPixelAlpha(image,p));
cristyed231572011-07-14 02:18:59 +00001023 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001024 }
1025 if (image->previous == (Image *) NULL)
1026 {
cristycee97112010-05-28 00:44:52 +00001027 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristyc6da28e2011-04-28 01:41:35 +00001028 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001029 if (status == MagickFalse)
1030 break;
1031 }
1032 }
1033 switch (compression)
1034 {
1035 case NoCompression:
1036 {
1037 /*
1038 Write uncompressed SGI pixels.
1039 */
cristybb503372010-05-27 20:51:26 +00001040 for (z=0; z < (ssize_t) iris_info.depth; z++)
cristy3ed852e2009-09-05 21:47:34 +00001041 {
cristybb503372010-05-27 20:51:26 +00001042 for (y=0; y < (ssize_t) iris_info.rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001043 {
1044 if (image->depth <= 8)
cristybb503372010-05-27 20:51:26 +00001045 for (x=0; x < (ssize_t) iris_info.columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001046 {
1047 register unsigned char
1048 *q;
1049
cristyb64823d2013-06-30 20:58:24 +00001050 q=(unsigned char *) pixels;
cristy3ed852e2009-09-05 21:47:34 +00001051 q+=y*(4*iris_info.columns)+4*x+z;
1052 (void) WriteBlobByte(image,*q);
1053 }
1054 else
cristybb503372010-05-27 20:51:26 +00001055 for (x=0; x < (ssize_t) iris_info.columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001056 {
1057 register unsigned short
1058 *q;
1059
cristyb64823d2013-06-30 20:58:24 +00001060 q=(unsigned short *) pixels;
cristy3ed852e2009-09-05 21:47:34 +00001061 q+=y*(4*iris_info.columns)+4*x+z;
1062 (void) WriteBlobMSBShort(image,*q);
1063 }
1064 }
1065 }
1066 break;
1067 }
1068 default:
1069 {
cristyb64823d2013-06-30 20:58:24 +00001070 MemoryInfo
1071 *packet_info;
1072
cristyc6da28e2011-04-28 01:41:35 +00001073 size_t
1074 length,
1075 number_packets,
1076 *runlength;
1077
cristy3ed852e2009-09-05 21:47:34 +00001078 ssize_t
1079 offset,
1080 *offsets;
1081
cristy3ed852e2009-09-05 21:47:34 +00001082 /*
1083 Convert SGI uncompressed pixels.
1084 */
cristyfa6de8c2014-05-18 16:34:44 +00001085 offsets=(ssize_t *) AcquireQuantumMemory(iris_info.rows,
1086 iris_info.depth*sizeof(*offsets));
cristybb503372010-05-27 20:51:26 +00001087 runlength=(size_t *) AcquireQuantumMemory(iris_info.rows,
cristy3ed852e2009-09-05 21:47:34 +00001088 iris_info.depth*sizeof(*runlength));
cristyb64823d2013-06-30 20:58:24 +00001089 packet_info=AcquireVirtualMemory((2*(size_t) iris_info.columns+10)*
1090 image->rows,4*sizeof(*packets));
cristy3ed852e2009-09-05 21:47:34 +00001091 if ((offsets == (ssize_t *) NULL) ||
cristyb64823d2013-06-30 20:58:24 +00001092 (runlength == (size_t *) NULL) ||
1093 (packet_info == (MemoryInfo *) NULL))
1094 {
1095 if (offsets != (ssize_t *) NULL)
1096 offsets=(ssize_t *) RelinquishMagickMemory(offsets);
1097 if (runlength != (size_t *) NULL)
1098 runlength=(size_t *) RelinquishMagickMemory(runlength);
1099 if (packet_info != (MemoryInfo *) NULL)
1100 packet_info=RelinquishVirtualMemory(packet_info);
1101 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1102 }
1103 packets=(unsigned char *) GetVirtualMemoryBlob(packet_info);
cristy3ed852e2009-09-05 21:47:34 +00001104 offset=512+4*2*((ssize_t) iris_info.rows*iris_info.depth);
1105 number_packets=0;
cristyb64823d2013-06-30 20:58:24 +00001106 q=pixels;
cristybb503372010-05-27 20:51:26 +00001107 for (y=0; y < (ssize_t) iris_info.rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001108 {
cristybb503372010-05-27 20:51:26 +00001109 for (z=0; z < (ssize_t) iris_info.depth; z++)
cristy3ed852e2009-09-05 21:47:34 +00001110 {
1111 length=SGIEncode(q+z,(size_t) iris_info.columns,packets+
1112 number_packets);
1113 number_packets+=length;
1114 offsets[y+z*iris_info.rows]=offset;
cristybb503372010-05-27 20:51:26 +00001115 runlength[y+z*iris_info.rows]=(size_t) length;
cristy3ed852e2009-09-05 21:47:34 +00001116 offset+=(ssize_t) length;
1117 }
1118 q+=(iris_info.columns*4);
1119 }
1120 /*
1121 Write out line start and length tables and runlength-encoded pixels.
1122 */
cristybb503372010-05-27 20:51:26 +00001123 for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++)
cristyf9cca6a2010-06-04 23:49:28 +00001124 (void) WriteBlobMSBLong(image,(unsigned int) offsets[i]);
cristybb503372010-05-27 20:51:26 +00001125 for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++)
cristyeaedf062010-05-29 22:36:02 +00001126 (void) WriteBlobMSBLong(image,(unsigned int) runlength[i]);
cristy3ed852e2009-09-05 21:47:34 +00001127 (void) WriteBlob(image,number_packets,packets);
1128 /*
1129 Relinquish resources.
1130 */
cristy3ed852e2009-09-05 21:47:34 +00001131 offsets=(ssize_t *) RelinquishMagickMemory(offsets);
cristyb64823d2013-06-30 20:58:24 +00001132 runlength=(size_t *) RelinquishMagickMemory(runlength);
1133 packet_info=RelinquishVirtualMemory(packet_info);
cristy3ed852e2009-09-05 21:47:34 +00001134 break;
1135 }
1136 }
cristyb64823d2013-06-30 20:58:24 +00001137 pixel_info=RelinquishVirtualMemory(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +00001138 if (GetNextImageInList(image) == (Image *) NULL)
1139 break;
1140 image=SyncNextImageInList(image);
1141 status=SetImageProgress(image,SaveImagesTag,scene++,
1142 GetImageListLength(image));
1143 if (status == MagickFalse)
1144 break;
1145 } while (image_info->adjoin != MagickFalse);
1146 (void) CloseBlob(image);
1147 return(MagickTrue);
1148}