blob: 90ba848303e5d1b1f0a2578a08cf5df6ecbba4f5 [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 %
16% John Cristy %
17% July 1992 %
18% %
19% %
cristy7e41fe82010-12-04 23:12:08 +000020% Copyright 1999-2011 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
cristy4c08aed2011-07-01 19:47:50 +0000274 register Quantum
cristy667a8922010-12-29 13:43:35 +0000275 *q;
276
cristybb503372010-05-27 20:51:26 +0000277 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000278 i,
279 x;
280
cristy3ed852e2009-09-05 21:47:34 +0000281 register unsigned char
282 *p;
283
cristy3ed852e2009-09-05 21:47:34 +0000284 SGIInfo
285 iris_info;
286
287 size_t
cristy667a8922010-12-29 13:43:35 +0000288 bytes_per_pixel,
289 quantum;
290
291 ssize_t
292 count,
293 y,
294 z;
cristy3ed852e2009-09-05 21:47:34 +0000295
296 unsigned char
297 *iris_pixels;
298
cristy3ed852e2009-09-05 21:47:34 +0000299 /*
300 Open image file.
301 */
302 assert(image_info != (const ImageInfo *) NULL);
303 assert(image_info->signature == MagickSignature);
304 if (image_info->debug != MagickFalse)
305 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
306 image_info->filename);
307 assert(exception != (ExceptionInfo *) NULL);
308 assert(exception->signature == MagickSignature);
cristy9950d572011-10-01 18:22:35 +0000309 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000310 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
311 if (status == MagickFalse)
312 {
313 image=DestroyImageList(image);
314 return((Image *) NULL);
315 }
316 /*
317 Read SGI raster header.
318 */
319 iris_info.magic=ReadBlobMSBShort(image);
320 do
321 {
322 /*
323 Verify SGI identifier.
324 */
325 if (iris_info.magic != 0x01DA)
326 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
327 iris_info.storage=(unsigned char) ReadBlobByte(image);
328 switch (iris_info.storage)
329 {
330 case 0x00: image->compression=NoCompression; break;
331 case 0x01: image->compression=RLECompression; break;
332 default:
333 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
334 }
335 iris_info.bytes_per_pixel=(unsigned char) ReadBlobByte(image);
336 if ((iris_info.bytes_per_pixel == 0) || (iris_info.bytes_per_pixel > 2))
337 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
338 iris_info.dimension=ReadBlobMSBShort(image);
339 iris_info.columns=ReadBlobMSBShort(image);
340 iris_info.rows=ReadBlobMSBShort(image);
341 iris_info.depth=ReadBlobMSBShort(image);
342 if ((iris_info.depth == 0) || (iris_info.depth > 4))
343 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
344 iris_info.minimum_value=ReadBlobMSBLong(image);
345 iris_info.maximum_value=ReadBlobMSBLong(image);
346 iris_info.sans=ReadBlobMSBLong(image);
347 (void) ReadBlob(image,sizeof(iris_info.name),(unsigned char *)
348 iris_info.name);
349 iris_info.name[sizeof(iris_info.name)-1]='\0';
350 if (*iris_info.name != '\0')
cristyd15e6592011-10-15 00:13:06 +0000351 (void) SetImageProperty(image,"label",iris_info.name,exception);
cristy3ed852e2009-09-05 21:47:34 +0000352 iris_info.pixel_format=ReadBlobMSBLong(image);
353 if (iris_info.pixel_format != 0)
354 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
355 count=ReadBlob(image,sizeof(iris_info.filler),iris_info.filler);
cristyda16f162011-02-19 23:52:17 +0000356 (void) count;
cristy3ed852e2009-09-05 21:47:34 +0000357 image->columns=iris_info.columns;
358 image->rows=iris_info.rows;
cristybb503372010-05-27 20:51:26 +0000359 image->depth=(size_t) MagickMin(iris_info.depth,MAGICKCORE_QUANTUM_DEPTH);
cristy3ed852e2009-09-05 21:47:34 +0000360 if (iris_info.pixel_format == 0)
cristybb503372010-05-27 20:51:26 +0000361 image->depth=(size_t) MagickMin((size_t) 8*
cristy3ed852e2009-09-05 21:47:34 +0000362 iris_info.bytes_per_pixel,MAGICKCORE_QUANTUM_DEPTH);
363 if (iris_info.depth < 3)
364 {
365 image->storage_class=PseudoClass;
cristy667a8922010-12-29 13:43:35 +0000366 image->colors=iris_info.bytes_per_pixel > 1 ? 65535 : 256;
cristy3ed852e2009-09-05 21:47:34 +0000367 }
368 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
369 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
370 break;
371 /*
372 Allocate SGI pixels.
373 */
374 bytes_per_pixel=(size_t) iris_info.bytes_per_pixel;
375 number_pixels=(MagickSizeType) iris_info.columns*iris_info.rows;
376 if ((4*bytes_per_pixel*number_pixels) != ((MagickSizeType) (size_t)
377 (4*bytes_per_pixel*number_pixels)))
378 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
379 iris_pixels=(unsigned char *) AcquireQuantumMemory(iris_info.columns,
380 iris_info.rows*4*bytes_per_pixel*sizeof(*iris_pixels));
381 if (iris_pixels == (unsigned char *) NULL)
382 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
383 if ((int) iris_info.storage != 0x01)
384 {
385 unsigned char
386 *scanline;
387
388 /*
389 Read standard image format.
390 */
391 scanline=(unsigned char *) AcquireQuantumMemory(iris_info.columns,
392 bytes_per_pixel*sizeof(*scanline));
393 if (scanline == (unsigned char *) NULL)
394 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000395 for (z=0; z < (ssize_t) iris_info.depth; z++)
cristy3ed852e2009-09-05 21:47:34 +0000396 {
397 p=iris_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 {
cristy667a8922010-12-29 13:43:35 +0000422 size_t
423 *runlength;
424
cristy3ed852e2009-09-05 21:47:34 +0000425 ssize_t
426 offset,
427 *offsets;
428
429 unsigned char
430 *packets;
431
432 unsigned int
433 data_order;
434
cristy3ed852e2009-09-05 21:47:34 +0000435 /*
436 Read runlength-encoded image format.
437 */
438 offsets=(ssize_t *) AcquireQuantumMemory((size_t) iris_info.rows,
439 iris_info.depth*sizeof(*offsets));
440 packets=(unsigned char *) AcquireQuantumMemory((size_t)
441 iris_info.columns+10UL,4UL*sizeof(*packets));
cristybb503372010-05-27 20:51:26 +0000442 runlength=(size_t *) AcquireQuantumMemory(iris_info.rows,
cristy3ed852e2009-09-05 21:47:34 +0000443 iris_info.depth*sizeof(*runlength));
444 if ((offsets == (ssize_t *) NULL) ||
445 (packets == (unsigned char *) NULL) ||
cristybb503372010-05-27 20:51:26 +0000446 (runlength == (size_t *) NULL))
cristy3ed852e2009-09-05 21:47:34 +0000447 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000448 for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++)
cristy6cff05d2010-09-02 11:22:46 +0000449 offsets[i]=(int) ReadBlobMSBLong(image);
cristybb503372010-05-27 20:51:26 +0000450 for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++)
cristy3ed852e2009-09-05 21:47:34 +0000451 {
452 runlength[i]=ReadBlobMSBLong(image);
453 if (runlength[i] > (4*(size_t) iris_info.columns+10))
454 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
455 }
456 /*
457 Check data order.
458 */
459 offset=0;
460 data_order=0;
cristybb503372010-05-27 20:51:26 +0000461 for (y=0; ((y < (ssize_t) iris_info.rows) && (data_order == 0)); y++)
462 for (z=0; ((z < (ssize_t) iris_info.depth) && (data_order == 0)); z++)
cristy3ed852e2009-09-05 21:47:34 +0000463 {
464 if (offsets[y+z*iris_info.rows] < offset)
465 data_order=1;
466 offset=offsets[y+z*iris_info.rows];
467 }
468 offset=(ssize_t) TellBlob(image);
469 if (data_order == 1)
470 {
cristybb503372010-05-27 20:51:26 +0000471 for (z=0; z < (ssize_t) iris_info.depth; z++)
cristy3ed852e2009-09-05 21:47:34 +0000472 {
473 p=iris_pixels;
cristybb503372010-05-27 20:51:26 +0000474 for (y=0; y < (ssize_t) iris_info.rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000475 {
476 if (offset != offsets[y+z*iris_info.rows])
477 {
478 offset=offsets[y+z*iris_info.rows];
cristybb503372010-05-27 20:51:26 +0000479 offset=(ssize_t) SeekBlob(image,(ssize_t) offset,SEEK_SET);
cristy3ed852e2009-09-05 21:47:34 +0000480 }
481 count=ReadBlob(image,(size_t) runlength[y+z*iris_info.rows],
482 packets);
483 if (EOFBlob(image) != MagickFalse)
484 break;
cristyeaedf062010-05-29 22:36:02 +0000485 offset+=(ssize_t) runlength[y+z*iris_info.rows];
cristybb503372010-05-27 20:51:26 +0000486 status=SGIDecode(bytes_per_pixel,(ssize_t)
cristy3ed852e2009-09-05 21:47:34 +0000487 (runlength[y+z*iris_info.rows]/bytes_per_pixel),packets,
488 1L*iris_info.columns,p+bytes_per_pixel*z);
489 if (status == MagickFalse)
490 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
491 p+=(iris_info.columns*4*bytes_per_pixel);
492 }
493 }
494 }
495 else
496 {
497 MagickOffsetType
498 position;
499
500 position=TellBlob(image);
501 p=iris_pixels;
cristybb503372010-05-27 20:51:26 +0000502 for (y=0; y < (ssize_t) iris_info.rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000503 {
cristybb503372010-05-27 20:51:26 +0000504 for (z=0; z < (ssize_t) iris_info.depth; z++)
cristy3ed852e2009-09-05 21:47:34 +0000505 {
506 if (offset != offsets[y+z*iris_info.rows])
507 {
508 offset=offsets[y+z*iris_info.rows];
cristybb503372010-05-27 20:51:26 +0000509 offset=(ssize_t) SeekBlob(image,(ssize_t) offset,SEEK_SET);
cristy3ed852e2009-09-05 21:47:34 +0000510 }
511 count=ReadBlob(image,(size_t) runlength[y+z*iris_info.rows],
512 packets);
513 if (EOFBlob(image) != MagickFalse)
514 break;
cristyeaedf062010-05-29 22:36:02 +0000515 offset+=(ssize_t) runlength[y+z*iris_info.rows];
cristybb503372010-05-27 20:51:26 +0000516 status=SGIDecode(bytes_per_pixel,(ssize_t)
cristy3ed852e2009-09-05 21:47:34 +0000517 (runlength[y+z*iris_info.rows]/bytes_per_pixel),packets,
518 1L*iris_info.columns,p+bytes_per_pixel*z);
519 if (status == MagickFalse)
520 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
521 }
522 p+=(iris_info.columns*4*bytes_per_pixel);
523 }
524 offset=(ssize_t) SeekBlob(image,position,SEEK_SET);
525 }
cristybb503372010-05-27 20:51:26 +0000526 runlength=(size_t *) RelinquishMagickMemory(runlength);
cristy3ed852e2009-09-05 21:47:34 +0000527 packets=(unsigned char *) RelinquishMagickMemory(packets);
528 offsets=(ssize_t *) RelinquishMagickMemory(offsets);
529 }
530 /*
531 Initialize image structure.
532 */
533 image->matte=iris_info.depth == 4 ? MagickTrue : MagickFalse;
534 image->columns=iris_info.columns;
535 image->rows=iris_info.rows;
536 /*
537 Convert SGI raster image to pixel packets.
538 */
539 if (image->storage_class == DirectClass)
540 {
541 /*
542 Convert SGI image to DirectClass pixel packets.
543 */
544 if (bytes_per_pixel == 2)
545 {
cristybb503372010-05-27 20:51:26 +0000546 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000547 {
548 p=iris_pixels+(image->rows-y-1)*8*image->columns;
549 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000550 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000551 break;
cristybb503372010-05-27 20:51:26 +0000552 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000553 {
cristy4c08aed2011-07-01 19:47:50 +0000554 SetPixelRed(image,ScaleShortToQuantum((unsigned short)
555 ((*(p+0) << 8) | (*(p+1)))),q);
556 SetPixelGreen(image,ScaleShortToQuantum((unsigned short)
557 ((*(p+2) << 8) | (*(p+3)))),q);
558 SetPixelBlue(image,ScaleShortToQuantum((unsigned short)
559 ((*(p+4) << 8) | (*(p+5)))),q);
560 SetPixelAlpha(image,OpaqueAlpha,q);
cristy3ed852e2009-09-05 21:47:34 +0000561 if (image->matte != MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000562 SetPixelAlpha(image,ScaleShortToQuantum((unsigned short)
563 ((*(p+6) << 8) | (*(p+7)))),q);
cristy3ed852e2009-09-05 21:47:34 +0000564 p+=8;
cristyed231572011-07-14 02:18:59 +0000565 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000566 }
567 if (SyncAuthenticPixels(image,exception) == MagickFalse)
568 break;
569 if (image->previous == (Image *) NULL)
570 {
cristy667a8922010-12-29 13:43:35 +0000571 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
572 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000573 if (status == MagickFalse)
574 break;
575 }
576 }
577 }
578 else
cristybb503372010-05-27 20:51:26 +0000579 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000580 {
581 p=iris_pixels+(image->rows-y-1)*4*image->columns;
582 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000583 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000584 break;
cristybb503372010-05-27 20:51:26 +0000585 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000586 {
cristy4c08aed2011-07-01 19:47:50 +0000587 SetPixelRed(image,ScaleCharToQuantum(*p),q);
588 SetPixelGreen(image,ScaleCharToQuantum(*(p+1)),q);
589 SetPixelBlue(image,ScaleCharToQuantum(*(p+2)),q);
590 SetPixelAlpha(image,OpaqueAlpha,q);
cristy3ed852e2009-09-05 21:47:34 +0000591 if (image->matte != MagickFalse)
cristy4c08aed2011-07-01 19:47:50 +0000592 SetPixelAlpha(image,ScaleCharToQuantum(*(p+3)),q);
cristy3ed852e2009-09-05 21:47:34 +0000593 p+=4;
cristyed231572011-07-14 02:18:59 +0000594 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000595 }
596 if (SyncAuthenticPixels(image,exception) == MagickFalse)
597 break;
598 if (image->previous == (Image *) NULL)
599 {
cristycee97112010-05-28 00:44:52 +0000600 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
cristy4c08aed2011-07-01 19:47:50 +0000601 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000602 if (status == MagickFalse)
603 break;
604 }
605 }
606 }
607 else
608 {
609 /*
610 Create grayscale map.
611 */
cristy018f07f2011-09-04 21:15:19 +0000612 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000613 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
614 /*
615 Convert SGI image to PseudoClass pixel packets.
616 */
617 if (bytes_per_pixel == 2)
618 {
cristybb503372010-05-27 20:51:26 +0000619 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000620 {
621 p=iris_pixels+(image->rows-y-1)*8*image->columns;
622 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000623 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000624 break;
cristybb503372010-05-27 20:51:26 +0000625 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000626 {
627 quantum=(*p << 8);
628 quantum|=(*(p+1));
cristy4c08aed2011-07-01 19:47:50 +0000629 SetPixelIndex(image,quantum,q);
cristy3ed852e2009-09-05 21:47:34 +0000630 p+=8;
cristyed231572011-07-14 02:18:59 +0000631 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000632 }
633 if (SyncAuthenticPixels(image,exception) == MagickFalse)
634 break;
635 if (image->previous == (Image *) NULL)
636 {
cristy667a8922010-12-29 13:43:35 +0000637 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
638 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000639 if (status == MagickFalse)
640 break;
641 }
642 }
643 }
644 else
cristybb503372010-05-27 20:51:26 +0000645 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000646 {
647 p=iris_pixels+(image->rows-y-1)*4*image->columns;
648 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000649 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000650 break;
cristybb503372010-05-27 20:51:26 +0000651 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000652 {
cristy4c08aed2011-07-01 19:47:50 +0000653 SetPixelIndex(image,*p,q);
cristy3ed852e2009-09-05 21:47:34 +0000654 p+=4;
cristyed231572011-07-14 02:18:59 +0000655 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000656 }
657 if (SyncAuthenticPixels(image,exception) == MagickFalse)
658 break;
659 if (image->previous == (Image *) NULL)
660 {
cristycee97112010-05-28 00:44:52 +0000661 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
662 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000663 if (status == MagickFalse)
664 break;
665 }
666 }
667 (void) SyncImage(image);
668 }
669 iris_pixels=(unsigned char *) RelinquishMagickMemory(iris_pixels);
670 if (EOFBlob(image) != MagickFalse)
671 {
672 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
673 image->filename);
674 break;
675 }
676 /*
677 Proceed to next image.
678 */
679 if (image_info->number_scenes != 0)
680 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
681 break;
682 iris_info.magic=ReadBlobMSBShort(image);
683 if (iris_info.magic == 0x01DA)
684 {
685 /*
686 Allocate next image structure.
687 */
cristy9950d572011-10-01 18:22:35 +0000688 AcquireNextImage(image_info,image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000689 if (GetNextImageInList(image) == (Image *) NULL)
690 {
691 image=DestroyImageList(image);
692 return((Image *) NULL);
693 }
694 image=SyncNextImageInList(image);
695 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
696 GetBlobSize(image));
697 if (status == MagickFalse)
698 break;
699 }
700 } while (iris_info.magic == 0x01DA);
701 (void) CloseBlob(image);
702 return(GetFirstImageInList(image));
703}
704
705/*
706%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
707% %
708% %
709% %
710% R e g i s t e r S G I I m a g e %
711% %
712% %
713% %
714%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
715%
716% RegisterSGIImage() adds properties for the SGI image format to
717% the list of supported formats. The properties include the image format
718% tag, a method to read and/or write the format, whether the format
719% supports the saving of more than one frame to the same file or blob,
720% whether the format supports native in-memory I/O, and a brief
721% description of the format.
722%
723% The format of the RegisterSGIImage method is:
724%
cristybb503372010-05-27 20:51:26 +0000725% size_t RegisterSGIImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000726%
727*/
cristybb503372010-05-27 20:51:26 +0000728ModuleExport size_t RegisterSGIImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000729{
730 MagickInfo
731 *entry;
732
733 entry=SetMagickInfo("SGI");
734 entry->decoder=(DecodeImageHandler *) ReadSGIImage;
735 entry->encoder=(EncodeImageHandler *) WriteSGIImage;
736 entry->magick=(IsImageFormatHandler *) IsSGI;
737 entry->description=ConstantString("Irix RGB image");
738 entry->module=ConstantString("SGI");
739 entry->seekable_stream=MagickTrue;
740 (void) RegisterMagickInfo(entry);
741 return(MagickImageCoderSignature);
742}
743
744/*
745%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
746% %
747% %
748% %
749% U n r e g i s t e r S G I I m a g e %
750% %
751% %
752% %
753%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
754%
755% UnregisterSGIImage() removes format registrations made by the
756% SGI module from the list of supported formats.
757%
758% The format of the UnregisterSGIImage method is:
759%
760% UnregisterSGIImage(void)
761%
762*/
763ModuleExport void UnregisterSGIImage(void)
764{
765 (void) UnregisterMagickInfo("SGI");
766}
767
768/*
769%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
770% %
771% %
772% %
773% W r i t e S G I I m a g e %
774% %
775% %
776% %
777%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
778%
779% WriteSGIImage() writes an image in SGI RGB encoded image format.
780%
781% The format of the WriteSGIImage method is:
782%
cristy3a37efd2011-08-28 20:31:03 +0000783% MagickBooleanType WriteSGIImage(const ImageInfo *image_info,
784% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000785%
786% A description of each parameter follows.
787%
788% o image_info: the image info.
789%
790% o image: The image.
791%
cristy3a37efd2011-08-28 20:31:03 +0000792% o exception: return any errors or warnings in this structure.
793%
cristy3ed852e2009-09-05 21:47:34 +0000794*/
795
796static size_t SGIEncode(unsigned char *pixels,size_t length,
797 unsigned char *packets)
798{
799 short
800 runlength;
801
802 register unsigned char
803 *p,
804 *q;
805
806 unsigned char
807 *limit,
808 *mark;
809
810 p=pixels;
811 limit=p+length*4;
812 q=packets;
813 while (p < limit)
814 {
815 mark=p;
816 p+=8;
817 while ((p < limit) && ((*(p-8) != *(p-4)) || (*(p-4) != *p)))
818 p+=4;
819 p-=8;
820 length=(size_t) (p-mark) >> 2;
821 while (length != 0)
822 {
823 runlength=(short) (length > 126 ? 126 : length);
824 length-=runlength;
825 *q++=(unsigned char) (0x80 | runlength);
826 for ( ; runlength > 0; runlength--)
827 {
828 *q++=(*mark);
829 mark+=4;
830 }
831 }
832 mark=p;
833 p+=4;
834 while ((p < limit) && (*p == *mark))
835 p+=4;
836 length=(size_t) (p-mark) >> 2;
837 while (length != 0)
838 {
839 runlength=(short) (length > 126 ? 126 : length);
840 length-=runlength;
841 *q++=(unsigned char) runlength;
842 *q++=(*mark);
843 }
844 }
845 *q++='\0';
846 return((size_t) (q-packets));
847}
848
cristy3a37efd2011-08-28 20:31:03 +0000849static MagickBooleanType WriteSGIImage(const ImageInfo *image_info,Image *image,
850 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000851{
852 CompressionType
853 compression;
854
855 const char
856 *value;
857
cristy3ed852e2009-09-05 21:47:34 +0000858 MagickBooleanType
859 status;
860
861 MagickOffsetType
862 scene;
863
864 MagickSizeType
865 number_pixels;
866
867 SGIInfo
868 iris_info;
869
cristy4c08aed2011-07-01 19:47:50 +0000870 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000871 *p;
872
cristybb503372010-05-27 20:51:26 +0000873 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000874 i,
875 x;
876
877 register unsigned char
878 *q;
879
cristyc6da28e2011-04-28 01:41:35 +0000880 ssize_t
881 y,
882 z;
883
cristy3ed852e2009-09-05 21:47:34 +0000884 unsigned char
885 *iris_pixels,
886 *packets;
887
888 /*
889 Open output image file.
890 */
891 assert(image_info != (const ImageInfo *) NULL);
892 assert(image_info->signature == MagickSignature);
893 assert(image != (Image *) NULL);
894 assert(image->signature == MagickSignature);
895 if (image->debug != MagickFalse)
896 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
897 if ((image->columns > 65535UL) || (image->rows > 65535UL))
898 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
cristy3a37efd2011-08-28 20:31:03 +0000899 assert(exception != (ExceptionInfo *) NULL);
900 assert(exception->signature == MagickSignature);
901 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000902 if (status == MagickFalse)
903 return(status);
904 scene=0;
905 do
906 {
907 /*
908 Initialize SGI raster file header.
909 */
cristy510d06a2011-07-06 23:43:54 +0000910 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristye941a752011-10-15 01:52:48 +0000911 (void) TransformImageColorspace(image,RGBColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +0000912 (void) ResetMagickMemory(&iris_info,0,sizeof(iris_info));
913 iris_info.magic=0x01DA;
914 compression=image->compression;
915 if (image_info->compression != UndefinedCompression)
916 compression=image_info->compression;
917 if (image->depth > 8)
918 compression=NoCompression;
919 if (compression == NoCompression)
920 iris_info.storage=(unsigned char) 0x00;
921 else
922 iris_info.storage=(unsigned char) 0x01;
923 iris_info.bytes_per_pixel=(unsigned char) (image->depth > 8 ? 2 : 1);
924 iris_info.dimension=3;
925 iris_info.columns=(unsigned short) image->columns;
926 iris_info.rows=(unsigned short) image->rows;
927 if (image->matte != MagickFalse)
928 iris_info.depth=4;
929 else
930 {
931 if ((image_info->type != TrueColorType) &&
cristy3a37efd2011-08-28 20:31:03 +0000932 (IsImageGray(image,exception) != MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +0000933 {
934 iris_info.dimension=2;
935 iris_info.depth=1;
936 }
937 else
938 iris_info.depth=3;
939 }
940 iris_info.minimum_value=0;
cristybb503372010-05-27 20:51:26 +0000941 iris_info.maximum_value=(size_t) (image->depth <= 8 ?
cristy3ed852e2009-09-05 21:47:34 +0000942 1UL*ScaleQuantumToChar((Quantum) QuantumRange) :
943 1UL*ScaleQuantumToShort((Quantum) QuantumRange));
944 /*
945 Write SGI header.
946 */
947 (void) WriteBlobMSBShort(image,iris_info.magic);
948 (void) WriteBlobByte(image,iris_info.storage);
949 (void) WriteBlobByte(image,iris_info.bytes_per_pixel);
950 (void) WriteBlobMSBShort(image,iris_info.dimension);
951 (void) WriteBlobMSBShort(image,iris_info.columns);
952 (void) WriteBlobMSBShort(image,iris_info.rows);
953 (void) WriteBlobMSBShort(image,iris_info.depth);
cristyeaedf062010-05-29 22:36:02 +0000954 (void) WriteBlobMSBLong(image,(unsigned int) iris_info.minimum_value);
955 (void) WriteBlobMSBLong(image,(unsigned int) iris_info.maximum_value);
956 (void) WriteBlobMSBLong(image,(unsigned int) iris_info.sans);
cristyd15e6592011-10-15 00:13:06 +0000957 value=GetImageProperty(image,"label",exception);
cristy3ed852e2009-09-05 21:47:34 +0000958 if (value != (const char *) NULL)
959 (void) CopyMagickString(iris_info.name,value,sizeof(iris_info.name));
960 (void) WriteBlob(image,sizeof(iris_info.name),(unsigned char *)
961 iris_info.name);
cristy0b29b252010-05-30 01:59:46 +0000962 (void) WriteBlobMSBLong(image,(unsigned int) iris_info.pixel_format);
cristy3ed852e2009-09-05 21:47:34 +0000963 (void) WriteBlob(image,sizeof(iris_info.filler),iris_info.filler);
964 /*
965 Allocate SGI pixels.
966 */
967 number_pixels=(MagickSizeType) image->columns*image->rows;
968 if ((4*iris_info.bytes_per_pixel*number_pixels) !=
969 ((MagickSizeType) (size_t) (4*iris_info.bytes_per_pixel*number_pixels)))
970 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
971 iris_pixels=(unsigned char *) AcquireQuantumMemory((size_t) number_pixels,
972 4*iris_info.bytes_per_pixel*sizeof(*iris_pixels));
973 if (iris_pixels == (unsigned char *) NULL)
974 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
975 /*
976 Convert image pixels to uncompressed SGI pixels.
977 */
cristybb503372010-05-27 20:51:26 +0000978 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000979 {
cristy3a37efd2011-08-28 20:31:03 +0000980 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000981 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000982 break;
983 if (image->depth <= 8)
cristybb503372010-05-27 20:51:26 +0000984 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000985 {
986 register unsigned char
987 *q;
988
989 q=(unsigned char *) iris_pixels;
990 q+=((iris_info.rows-1)-y)*(4*iris_info.columns)+4*x;
cristy4c08aed2011-07-01 19:47:50 +0000991 *q++=ScaleQuantumToChar(GetPixelRed(image,p));
992 *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
993 *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
994 *q++=ScaleQuantumToChar(GetPixelAlpha(image,p));
cristyed231572011-07-14 02:18:59 +0000995 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000996 }
997 else
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 short
1001 *q;
1002
1003 q=(unsigned short *) iris_pixels;
1004 q+=((iris_info.rows-1)-y)*(4*iris_info.columns)+4*x;
cristy4c08aed2011-07-01 19:47:50 +00001005 *q++=ScaleQuantumToShort(GetPixelRed(image,p));
1006 *q++=ScaleQuantumToShort(GetPixelGreen(image,p));
1007 *q++=ScaleQuantumToShort(GetPixelBlue(image,p));
1008 *q++=ScaleQuantumToShort(GetPixelAlpha(image,p));
cristyed231572011-07-14 02:18:59 +00001009 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001010 }
1011 if (image->previous == (Image *) NULL)
1012 {
cristycee97112010-05-28 00:44:52 +00001013 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristyc6da28e2011-04-28 01:41:35 +00001014 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001015 if (status == MagickFalse)
1016 break;
1017 }
1018 }
1019 switch (compression)
1020 {
1021 case NoCompression:
1022 {
1023 /*
1024 Write uncompressed SGI pixels.
1025 */
cristybb503372010-05-27 20:51:26 +00001026 for (z=0; z < (ssize_t) iris_info.depth; z++)
cristy3ed852e2009-09-05 21:47:34 +00001027 {
cristybb503372010-05-27 20:51:26 +00001028 for (y=0; y < (ssize_t) iris_info.rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001029 {
1030 if (image->depth <= 8)
cristybb503372010-05-27 20:51:26 +00001031 for (x=0; x < (ssize_t) iris_info.columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001032 {
1033 register unsigned char
1034 *q;
1035
1036 q=(unsigned char *) iris_pixels;
1037 q+=y*(4*iris_info.columns)+4*x+z;
1038 (void) WriteBlobByte(image,*q);
1039 }
1040 else
cristybb503372010-05-27 20:51:26 +00001041 for (x=0; x < (ssize_t) iris_info.columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001042 {
1043 register unsigned short
1044 *q;
1045
1046 q=(unsigned short *) iris_pixels;
1047 q+=y*(4*iris_info.columns)+4*x+z;
1048 (void) WriteBlobMSBShort(image,*q);
1049 }
1050 }
1051 }
1052 break;
1053 }
1054 default:
1055 {
cristyc6da28e2011-04-28 01:41:35 +00001056 size_t
1057 length,
1058 number_packets,
1059 *runlength;
1060
cristy3ed852e2009-09-05 21:47:34 +00001061 ssize_t
1062 offset,
1063 *offsets;
1064
cristy3ed852e2009-09-05 21:47:34 +00001065 /*
1066 Convert SGI uncompressed pixels.
1067 */
1068 offsets=(ssize_t *) AcquireQuantumMemory(iris_info.rows*iris_info.depth,
1069 sizeof(*offsets));
1070 packets=(unsigned char *) AcquireQuantumMemory((2*(size_t)
1071 iris_info.columns+10)*image->rows,4*sizeof(*packets));
cristybb503372010-05-27 20:51:26 +00001072 runlength=(size_t *) AcquireQuantumMemory(iris_info.rows,
cristy3ed852e2009-09-05 21:47:34 +00001073 iris_info.depth*sizeof(*runlength));
1074 if ((offsets == (ssize_t *) NULL) ||
1075 (packets == (unsigned char *) NULL) ||
cristybb503372010-05-27 20:51:26 +00001076 (runlength == (size_t *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00001077 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1078 offset=512+4*2*((ssize_t) iris_info.rows*iris_info.depth);
1079 number_packets=0;
1080 q=iris_pixels;
cristybb503372010-05-27 20:51:26 +00001081 for (y=0; y < (ssize_t) iris_info.rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001082 {
cristybb503372010-05-27 20:51:26 +00001083 for (z=0; z < (ssize_t) iris_info.depth; z++)
cristy3ed852e2009-09-05 21:47:34 +00001084 {
1085 length=SGIEncode(q+z,(size_t) iris_info.columns,packets+
1086 number_packets);
1087 number_packets+=length;
1088 offsets[y+z*iris_info.rows]=offset;
cristybb503372010-05-27 20:51:26 +00001089 runlength[y+z*iris_info.rows]=(size_t) length;
cristy3ed852e2009-09-05 21:47:34 +00001090 offset+=(ssize_t) length;
1091 }
1092 q+=(iris_info.columns*4);
1093 }
1094 /*
1095 Write out line start and length tables and runlength-encoded pixels.
1096 */
cristybb503372010-05-27 20:51:26 +00001097 for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++)
cristyf9cca6a2010-06-04 23:49:28 +00001098 (void) WriteBlobMSBLong(image,(unsigned int) offsets[i]);
cristybb503372010-05-27 20:51:26 +00001099 for (i=0; i < (ssize_t) (iris_info.rows*iris_info.depth); i++)
cristyeaedf062010-05-29 22:36:02 +00001100 (void) WriteBlobMSBLong(image,(unsigned int) runlength[i]);
cristy3ed852e2009-09-05 21:47:34 +00001101 (void) WriteBlob(image,number_packets,packets);
1102 /*
1103 Relinquish resources.
1104 */
cristybb503372010-05-27 20:51:26 +00001105 runlength=(size_t *) RelinquishMagickMemory(runlength);
cristy3ed852e2009-09-05 21:47:34 +00001106 packets=(unsigned char *) RelinquishMagickMemory(packets);
1107 offsets=(ssize_t *) RelinquishMagickMemory(offsets);
1108 break;
1109 }
1110 }
1111 iris_pixels=(unsigned char *) RelinquishMagickMemory(iris_pixels);
1112 if (GetNextImageInList(image) == (Image *) NULL)
1113 break;
1114 image=SyncNextImageInList(image);
1115 status=SetImageProgress(image,SaveImagesTag,scene++,
1116 GetImageListLength(image));
1117 if (status == MagickFalse)
1118 break;
1119 } while (image_info->adjoin != MagickFalse);
1120 (void) CloseBlob(image);
1121 return(MagickTrue);
1122}