/src/graphicsmagick/coders/sgi.c
Line | Count | Source |
1 | | /* |
2 | | % Copyright (C) 2003-2025 GraphicsMagick Group |
3 | | % Copyright (C) 2002 ImageMagick Studio |
4 | | % Copyright 1991-1999 E. I. du Pont de Nemours and Company |
5 | | % |
6 | | % This program is covered by multiple licenses, which are described in |
7 | | % Copyright.txt. You should have received a copy of Copyright.txt with this |
8 | | % package; otherwise see http://www.graphicsmagick.org/www/Copyright.html. |
9 | | % |
10 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
11 | | % % |
12 | | % % |
13 | | % % |
14 | | % SSSSS GGGG IIIII % |
15 | | % SS G I % |
16 | | % SSS G GG I % |
17 | | % SS G G I % |
18 | | % SSSSS GGG IIIII % |
19 | | % % |
20 | | % % |
21 | | % Read/Write Irix RGB Image Format. % |
22 | | % % |
23 | | % % |
24 | | % Software Design % |
25 | | % John Cristy % |
26 | | % July 1992 % |
27 | | % % |
28 | | % % |
29 | | % % |
30 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
31 | | % |
32 | | % |
33 | | */ |
34 | | |
35 | | /* |
36 | | Include declarations. |
37 | | */ |
38 | | #include "magick/studio.h" |
39 | | #include "magick/analyze.h" |
40 | | #include "magick/attribute.h" |
41 | | #include "magick/blob.h" |
42 | | #include "magick/colormap.h" |
43 | | #include "magick/log.h" |
44 | | #include "magick/magick.h" |
45 | | #include "magick/magick_endian.h" |
46 | | #include "magick/monitor.h" |
47 | | #include "magick/pixel_cache.h" |
48 | | #include "magick/utility.h" |
49 | | #include "magick/static.h" |
50 | | |
51 | | /* |
52 | | Typedef declaractions. |
53 | | */ |
54 | | |
55 | | /* |
56 | | The SGI file header is 512 bytes in size. |
57 | | */ |
58 | | typedef struct _SGIInfo |
59 | | { |
60 | | unsigned short |
61 | | magic; /* Identification number (474) */ |
62 | | |
63 | | magick_int8_t |
64 | | storage, /* Compression flag */ |
65 | | bytes_per_pixel; /* Bytes per pixel (per bit plane) */ |
66 | | |
67 | | magick_uint16_t |
68 | | dimension, /* Number of image dimensions */ |
69 | | xsize, /* Width of image in pixels */ |
70 | | ysize, /* Height of image in pixels */ |
71 | | zsize; /* Number of bit planes */ |
72 | | |
73 | | magick_uint32_t |
74 | | pix_min, /* Smallest pixel component value */ |
75 | | pix_max; /* Largest pixel component value */ |
76 | | |
77 | | char |
78 | | dummy1[4]; /* Not used */ |
79 | | |
80 | | char |
81 | | image_name[80]; /* Name of image (null terminated) */ |
82 | | |
83 | | magick_uint32_t |
84 | | color_map; /* Format of pixel data */ |
85 | | |
86 | | char |
87 | | dummy2[404]; /* Not used */ |
88 | | } SGIInfo; |
89 | | |
90 | | /* |
91 | | Forward declarations. |
92 | | */ |
93 | | static unsigned int |
94 | | WriteSGIImage(const ImageInfo *,Image *); |
95 | | /* |
96 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
97 | | % % |
98 | | % % |
99 | | % % |
100 | | % I s S G I % |
101 | | % % |
102 | | % % |
103 | | % % |
104 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
105 | | % |
106 | | % Method IsSGI returns True if the image format type, identified by the |
107 | | % magick string, is SGI. |
108 | | % |
109 | | % The format of the IsSGI method is: |
110 | | % |
111 | | % unsigned int IsSGI(const unsigned char *magick,const size_t length) |
112 | | % |
113 | | % A description of each parameter follows: |
114 | | % |
115 | | % o status: Method IsSGI returns True if the image format type is SGI. |
116 | | % |
117 | | % o magick: This string is generally the first few bytes of an image file |
118 | | % or blob. |
119 | | % |
120 | | % o length: Specifies the length of the magick string. |
121 | | % |
122 | | % |
123 | | */ |
124 | | static unsigned int IsSGI(const unsigned char *magick,const size_t length) |
125 | 0 | { |
126 | 0 | if (length < 2) |
127 | 0 | return(False); |
128 | 0 | if (memcmp(magick,"\001\332",2) == 0) |
129 | 0 | return(True); |
130 | 0 | return(False); |
131 | 0 | } |
132 | | |
133 | | /* |
134 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
135 | | % % |
136 | | % % |
137 | | % % |
138 | | % R e a d S G I I m a g e % |
139 | | % % |
140 | | % % |
141 | | % % |
142 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
143 | | % |
144 | | % Method ReadSGIImage reads a SGI RGB image file and returns it. It |
145 | | % allocates the memory necessary for the new Image structure and returns a |
146 | | % pointer to the new image. |
147 | | % |
148 | | % The format of the ReadSGIImage method is: |
149 | | % |
150 | | % Image *ReadSGIImage(const ImageInfo *image_info,ExceptionInfo *exception) |
151 | | % |
152 | | % A description of each parameter follows: |
153 | | % |
154 | | % o image: Method ReadSGIImage returns a pointer to the image after |
155 | | % reading. A null image is returned if there is a memory shortage or |
156 | | % if the image cannot be read. |
157 | | % |
158 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
159 | | % |
160 | | % o exception: return any errors or warnings in this structure. |
161 | | % |
162 | | % |
163 | | */ |
164 | | |
165 | | static int SGIDecode(const size_t bytes_per_pixel, |
166 | | unsigned char *max_packets,unsigned char *pixels, |
167 | | size_t npackets,size_t npixels) |
168 | 7.52k | { |
169 | 7.52k | size_t |
170 | 7.52k | count; |
171 | | |
172 | 7.52k | register unsigned char |
173 | 7.52k | *p, |
174 | 7.52k | *q; |
175 | | |
176 | 7.52k | unsigned int |
177 | 7.52k | pixel; |
178 | | |
179 | 7.52k | p=max_packets; |
180 | 7.52k | q=pixels; |
181 | 7.52k | if (bytes_per_pixel == 2) |
182 | 1.62k | { |
183 | 1.62k | for ( ; ; ) |
184 | 3.97k | { |
185 | 3.97k | if (npackets-- == 0) |
186 | 53 | return -1; |
187 | 3.92k | pixel=(*p++) << 8U; |
188 | 3.92k | pixel|=(*p++); |
189 | 3.92k | count=(pixel & 0x7fU); |
190 | 3.92k | if (count == 0) |
191 | 1.12k | break; |
192 | 2.79k | if (count > npixels) |
193 | 323 | return -1; |
194 | 2.47k | npixels -= count; |
195 | 2.47k | if (pixel & 0x80U) |
196 | 21.7k | for ( ; count != 0U; count--) |
197 | 21.0k | { |
198 | 21.0k | if (npackets-- == 0) |
199 | 22 | return -1; |
200 | 21.0k | *q=(*p++); |
201 | 21.0k | *(q+1)=(*p++); |
202 | 21.0k | q+=8U; |
203 | 21.0k | } |
204 | 1.79k | else |
205 | 1.79k | { |
206 | 1.79k | if (npackets-- == 0) |
207 | 103 | return -1; |
208 | 1.68k | pixel=(*p++) << 8U; |
209 | 1.68k | pixel|=(*p++); |
210 | 62.7k | for ( ; count != 0; count--) |
211 | 61.0k | { |
212 | 61.0k | *q=(unsigned char) (pixel >> 8U); |
213 | 61.0k | *(q+1)=(unsigned char) pixel; |
214 | 61.0k | q+=8U; |
215 | 61.0k | } |
216 | 1.68k | } |
217 | 2.47k | } |
218 | 1.12k | return 0; |
219 | 1.62k | } |
220 | 5.89k | for ( ; ; ) |
221 | 21.8k | { |
222 | 21.8k | if (npackets-- == 0) |
223 | 174 | return -1; |
224 | 21.7k | pixel=(*p++); |
225 | 21.7k | count= (pixel & 0x7fU); |
226 | 21.7k | if (count == 0) |
227 | 4.28k | break; |
228 | 17.4k | if (count > npixels) |
229 | 1.16k | return -1; |
230 | 16.2k | npixels -= count; |
231 | 16.2k | if (pixel & 0x80) |
232 | 258k | for ( ; count != 0; count--) |
233 | 252k | { |
234 | 252k | if (npackets-- == 0) |
235 | 16 | return -1; |
236 | 252k | *q=(*p++); |
237 | 252k | q+=4; |
238 | 252k | } |
239 | 9.88k | else |
240 | 9.88k | { |
241 | 9.88k | if (npackets-- == 0) |
242 | 254 | return -1; |
243 | 9.63k | pixel=(*p++); |
244 | 182k | for ( ; count != 0; count--) |
245 | 173k | { |
246 | 173k | *q=(unsigned char) pixel; |
247 | 173k | q+=4; |
248 | 173k | } |
249 | 9.63k | } |
250 | 16.2k | } |
251 | 4.28k | return 0; |
252 | 5.89k | } |
253 | | |
254 | 11.5k | #define ThrowSGIReaderException(code_,reason_,image_) \ |
255 | 11.5k | { \ |
256 | 11.5k | MagickFreeResourceLimitedMemory(unsigned char *,iris_pixels) \ |
257 | 11.5k | MagickFreeResourceLimitedMemory(unsigned char *,max_packets); \ |
258 | 11.5k | MagickFreeResourceLimitedMemory(magick_uint32_t *,offsets); \ |
259 | 11.5k | MagickFreeResourceLimitedMemory(magick_uint32_t *,runlength); \ |
260 | 11.5k | MagickFreeResourceLimitedMemory(unsigned char *,scanline) \ |
261 | 11.5k | ThrowReaderException(code_,reason_,image_); \ |
262 | 0 | } |
263 | | |
264 | | static Image *ReadSGIImage(const ImageInfo *image_info,ExceptionInfo *exception) |
265 | 120k | { |
266 | 120k | Image |
267 | 120k | *image; |
268 | | |
269 | 120k | size_t |
270 | 120k | z; |
271 | | |
272 | 120k | register IndexPacket |
273 | 120k | *indexes; |
274 | | |
275 | 120k | register size_t |
276 | 120k | i; |
277 | | |
278 | 120k | unsigned long |
279 | 120k | x, |
280 | 120k | y; |
281 | | |
282 | 120k | register PixelPacket |
283 | 120k | *q; |
284 | | |
285 | 120k | register unsigned char |
286 | 120k | *p; |
287 | | |
288 | 120k | SGIInfo |
289 | 120k | iris_info; |
290 | | |
291 | 120k | magick_uint32_t |
292 | 120k | *offsets = (magick_uint32_t *) NULL, |
293 | 120k | *runlength = (magick_uint32_t *) NULL; |
294 | | |
295 | 120k | unsigned char |
296 | 120k | *iris_pixels = (unsigned char *) NULL, |
297 | 120k | *max_packets = (unsigned char *) NULL, |
298 | 120k | *scanline = (unsigned char *) NULL; |
299 | | |
300 | 120k | unsigned int |
301 | 120k | status; |
302 | | |
303 | 120k | size_t |
304 | 120k | bytes_per_pixel; |
305 | | |
306 | 120k | magick_off_t |
307 | 120k | file_size; |
308 | | |
309 | | /* |
310 | | Open image file. |
311 | | */ |
312 | 120k | assert(image_info != (const ImageInfo *) NULL); |
313 | 120k | assert(image_info->signature == MagickSignature); |
314 | 120k | assert(exception != (ExceptionInfo *) NULL); |
315 | 120k | assert(exception->signature == MagickSignature); |
316 | 120k | image=AllocateImage(image_info); |
317 | 120k | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
318 | 120k | if (status == False) |
319 | 120k | ThrowReaderException(FileOpenError,UnableToOpenFile,image); |
320 | 120k | file_size=GetBlobSize(image); |
321 | 120k | do |
322 | 120k | { |
323 | | /* |
324 | | Read SGI raster header. |
325 | | */ |
326 | 120k | (void) memset(&iris_info, 0, sizeof(iris_info)); |
327 | 120k | iris_info.magic=ReadBlobMSBShort(image); |
328 | 120k | iris_info.storage=ReadBlobByte(image); |
329 | 120k | iris_info.bytes_per_pixel=ReadBlobByte(image) &0xF; |
330 | 120k | iris_info.dimension=ReadBlobMSBShort(image) & 0xFFFF; |
331 | 120k | iris_info.xsize=ReadBlobMSBShort(image) & 0xFFFF; |
332 | 120k | iris_info.ysize=ReadBlobMSBShort(image) & 0xFFFF; |
333 | 120k | iris_info.zsize=ReadBlobMSBShort(image) & 0xFFFF; |
334 | 120k | iris_info.pix_min=ReadBlobMSBLong(image) & 0xFFFFFFFF; |
335 | 120k | iris_info.pix_max=ReadBlobMSBLong(image) & 0xFFFFFFFF; |
336 | | |
337 | 120k | (void) ReadBlob(image,(unsigned int) sizeof(iris_info.dummy1), |
338 | 120k | iris_info.dummy1); |
339 | 120k | (void) ReadBlob(image,(unsigned int) sizeof(iris_info.image_name), |
340 | 120k | iris_info.image_name); |
341 | 120k | iris_info.image_name[sizeof(iris_info.image_name)-1]=0; |
342 | 120k | iris_info.color_map=ReadBlobMSBLong(image); |
343 | 120k | (void) ReadBlob(image,(unsigned int) sizeof(iris_info.dummy2), |
344 | 120k | iris_info.dummy2); |
345 | | |
346 | 120k | if (EOFBlob(image)) |
347 | 104k | ThrowReaderException(CorruptImageError,UnableToReadImageHeader,image); |
348 | | |
349 | 16.2k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
350 | 16.2k | "IRIS Header:\n" |
351 | 16.2k | " MAGIC=%u\n" |
352 | 16.2k | " STORAGE=%u (%s)\n" |
353 | 16.2k | " BPC=%u\n" |
354 | 16.2k | " DIMENSION=%u\n" |
355 | 16.2k | " XSIZE=%u\n" |
356 | 16.2k | " YSIZE=%u\n" |
357 | 16.2k | " ZSIZE=%u\n" |
358 | 16.2k | " PIXMIN=%u\n" |
359 | 16.2k | " PIXMAX=%u\n" |
360 | 16.2k | " IMAGENAME=\"%.79s\"\n" |
361 | 16.2k | " COLORMAP=%u", |
362 | 16.2k | (unsigned int) iris_info.magic, |
363 | 16.2k | (unsigned int) iris_info.storage, |
364 | 16.2k | (iris_info.storage == 1 ? "RLE" : "VERBATIM"), |
365 | 16.2k | (unsigned int) iris_info.bytes_per_pixel, |
366 | 16.2k | (unsigned int) iris_info.dimension, |
367 | 16.2k | (unsigned int) iris_info.xsize, |
368 | 16.2k | (unsigned int) iris_info.ysize, |
369 | 16.2k | (unsigned int) iris_info.zsize, |
370 | 16.2k | iris_info.pix_min, |
371 | 16.2k | iris_info.pix_max, |
372 | 16.2k | iris_info.image_name, |
373 | 16.2k | iris_info.color_map); |
374 | 16.2k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
375 | 16.2k | "File size %" MAGICK_OFF_F "d bytes", file_size); |
376 | | |
377 | | /* |
378 | | Validate image header and set image attributes. |
379 | | */ |
380 | 16.2k | if (iris_info.magic != 0x01DA) |
381 | 16.2k | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
382 | | |
383 | 16.2k | if (iris_info.storage == 0U) |
384 | 4.05k | { |
385 | | /* Uncompressed */ |
386 | 4.05k | image->compression=NoCompression; |
387 | 4.05k | } |
388 | 12.1k | else if (iris_info.storage == 1U) |
389 | 11.5k | { |
390 | | /* RLE compressed */ |
391 | 11.5k | image->compression=RLECompression; |
392 | 11.5k | } |
393 | 607 | else |
394 | 607 | { |
395 | | /* Error */ |
396 | 607 | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
397 | 0 | } |
398 | | |
399 | 15.5k | if (iris_info.color_map != 0U) |
400 | 2.60k | { |
401 | | /* We only support images with normal (no) colormap */ |
402 | 2.60k | ThrowReaderException(CorruptImageError,ImageTypeNotSupported,image); |
403 | 0 | } |
404 | | |
405 | 12.9k | if (iris_info.bytes_per_pixel == 1U) |
406 | 10.1k | { |
407 | | /* 8 bits per sample */ |
408 | 10.1k | image->depth=8; |
409 | 10.1k | } |
410 | 2.86k | else if (iris_info.bytes_per_pixel == 2U) |
411 | 1.34k | { |
412 | | /* 16 bits per sample */ |
413 | 1.34k | image->depth=Min(16,QuantumDepth); |
414 | 1.34k | } |
415 | 1.51k | else |
416 | 1.51k | { |
417 | | /* Error */ |
418 | 1.51k | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
419 | 0 | } |
420 | | |
421 | | /* We only support zsize up to 4. Code further on assumes that. */ |
422 | 11.4k | if (iris_info.zsize > 4U) |
423 | 10.2k | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
424 | | |
425 | 10.2k | if (iris_info.dimension == 1U) |
426 | 7.64k | { |
427 | | /* |
428 | | Image contains one channel and one scanline, with scanline |
429 | | length specified by xsize. |
430 | | */ |
431 | 7.64k | image->columns=iris_info.xsize; |
432 | 7.64k | image->rows=1; |
433 | 7.64k | if (iris_info.ysize != image->rows) |
434 | 7.59k | { |
435 | 7.59k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
436 | 7.59k | "Overriding unexpected value of YSIZE (%u) " |
437 | 7.59k | "for 1 dimensional image", iris_info.ysize); |
438 | 7.59k | iris_info.ysize=image->rows; |
439 | 7.59k | } |
440 | 7.64k | image->is_grayscale=MagickTrue; |
441 | 7.64k | if (iris_info.bytes_per_pixel == 1U) |
442 | 6.51k | { |
443 | | /* Use a grayscale colormap */ |
444 | 6.51k | image->storage_class=PseudoClass; |
445 | 6.51k | image->colors=256; |
446 | 6.51k | } |
447 | 7.64k | } |
448 | 2.59k | else if (iris_info.dimension == 2U) |
449 | 534 | { |
450 | | /* |
451 | | One channel with a number of scan lines. Width and height |
452 | | of image are given by the values of xsize and ysize. |
453 | | */ |
454 | 534 | image->columns=iris_info.xsize; |
455 | 534 | image->rows=iris_info.ysize; |
456 | 534 | image->is_grayscale=MagickTrue; |
457 | 534 | if (iris_info.bytes_per_pixel == 1) |
458 | 362 | { |
459 | | /* Use a grayscale colormap */ |
460 | 362 | image->storage_class=PseudoClass; |
461 | 362 | image->colors=256; |
462 | 362 | } |
463 | 534 | } |
464 | 2.06k | else if (iris_info.dimension == 3U) |
465 | 1.27k | { |
466 | | /* |
467 | | A number of channels. Width and height of image are given |
468 | | by the values of xsize and ysize. The number of channels is |
469 | | specified by zsize. |
470 | | |
471 | | B/W images have a zsize of 1. RGB images have a zsize of 3. |
472 | | RGB images with an alpha channel have a zsize of 4. Images |
473 | | may have more than four channels but the meaning of |
474 | | additional channels is implementation dependent. |
475 | | */ |
476 | | |
477 | 1.27k | image->columns=iris_info.xsize; |
478 | 1.27k | image->rows=iris_info.ysize; |
479 | | |
480 | 1.27k | if (iris_info.zsize == 1U) |
481 | 73 | { |
482 | | /* B/W image */ |
483 | 73 | image->matte = MagickFalse; |
484 | 73 | image->is_grayscale=MagickTrue; |
485 | 73 | if (iris_info.bytes_per_pixel == 1U) |
486 | 62 | { |
487 | | /* Use a grayscale colormap */ |
488 | 62 | image->storage_class=PseudoClass; |
489 | 62 | image->colors=256U; |
490 | 62 | } |
491 | 73 | } |
492 | 1.20k | else if (iris_info.zsize == 3U) |
493 | 119 | { |
494 | | /* RGB */ |
495 | 119 | image->matte=MagickFalse; |
496 | 119 | } |
497 | 1.08k | else if (iris_info.zsize == 4U) |
498 | 81 | { |
499 | | /* RGBA */ |
500 | 81 | image->matte=MagickTrue; |
501 | 81 | } |
502 | 1.00k | else |
503 | 1.00k | { |
504 | | /* Error */ |
505 | 1.00k | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
506 | 0 | } |
507 | 1.27k | } |
508 | 786 | else |
509 | 786 | { |
510 | | /* Error */ |
511 | 786 | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
512 | 0 | } |
513 | | |
514 | 8.45k | if (iris_info.image_name[0]) |
515 | 4.30k | (void) SetImageAttribute(image,"comment",iris_info.image_name); |
516 | | |
517 | 8.45k | if (image_info->ping && (image_info->subrange != 0)) |
518 | 0 | if (image->scene >= (image_info->subimage+image_info->subrange-1)) |
519 | 0 | break; |
520 | | |
521 | 8.45k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
522 | 8.45k | "Image columns=%lu rows=%lu", image->columns, image->rows); |
523 | | |
524 | 8.45k | if (CheckImagePixelLimits(image, exception) != MagickPass) |
525 | 8.01k | ThrowReaderException(ResourceLimitError,ImagePixelLimitExceeded,image); |
526 | | |
527 | | /* |
528 | | Allocate SGI pixels. |
529 | | */ |
530 | 8.01k | bytes_per_pixel=iris_info.bytes_per_pixel; |
531 | 8.01k | if (iris_info.storage != 0x01) |
532 | 1.50k | { |
533 | 1.50k | double |
534 | 1.50k | uncompressed_size; |
535 | | |
536 | 1.50k | size_t |
537 | 1.50k | iris_pixels_size; |
538 | | |
539 | | /* |
540 | | Check that filesize is reasonable given header |
541 | | */ |
542 | 1.50k | uncompressed_size=((double) (iris_info.dimension == 3U ? iris_info.zsize : 1U)* |
543 | 1.50k | image->columns*image->rows*iris_info.bytes_per_pixel); |
544 | 1.50k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
545 | 1.50k | "Uncompressed size: %.0f", uncompressed_size); |
546 | | |
547 | | /* Not compressed */ |
548 | 1.50k | if (uncompressed_size > file_size) |
549 | 3 | ThrowReaderException(CorruptImageError,InsufficientImageDataInFile, |
550 | 1.50k | image); |
551 | | |
552 | | /* |
553 | | Read standard image format. |
554 | | */ |
555 | 1.50k | scanline=MagickAllocateResourceLimitedArray(unsigned char *, |
556 | 1.50k | bytes_per_pixel,iris_info.xsize); |
557 | 1.50k | if (scanline == (unsigned char *) NULL) |
558 | 0 | ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed, |
559 | 1.50k | image); |
560 | | |
561 | 1.50k | iris_pixels_size = MagickArraySize(MagickArraySize(4U,bytes_per_pixel), |
562 | 1.50k | MagickArraySize(iris_info.xsize,iris_info.ysize)); |
563 | 1.50k | iris_pixels=MagickAllocateResourceLimitedMemory(unsigned char *,iris_pixels_size); |
564 | 1.50k | if (iris_pixels == (unsigned char *) NULL) |
565 | 1.50k | ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
566 | 1.50k | (void) memset(iris_pixels,0,iris_pixels_size); |
567 | | |
568 | 1.50k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
569 | 1.50k | " Reading SGI scanlines"); |
570 | 3.37k | for (z=0U; z < iris_info.zsize; z++) |
571 | 1.98k | { |
572 | 1.98k | p=iris_pixels+bytes_per_pixel*z; |
573 | 329k | for (y=0U; y < iris_info.ysize; y++) |
574 | 327k | { |
575 | 327k | if (ReadBlob(image,bytes_per_pixel*iris_info.xsize, |
576 | 327k | (char *) scanline) != bytes_per_pixel*iris_info.xsize) |
577 | 118 | { |
578 | 118 | ThrowSGIReaderException(CorruptImageError, |
579 | 0 | UnexpectedEndOfFile, image); |
580 | 0 | break; |
581 | 118 | } |
582 | 327k | if (bytes_per_pixel == 2U) |
583 | 3.03M | for (x=0; x < iris_info.xsize; x++) |
584 | 3.02M | { |
585 | 3.02M | *p=scanline[2U*x]; |
586 | 3.02M | *(p+1U)=scanline[2U*x+1U]; |
587 | 3.02M | p+=8U; |
588 | 3.02M | } |
589 | 317k | else |
590 | 30.0M | for (x=0; x < iris_info.xsize; x++) |
591 | 29.7M | { |
592 | 29.7M | *p=scanline[x]; |
593 | 29.7M | p+=4U; |
594 | 29.7M | } |
595 | 327k | } |
596 | 1.86k | if (EOFBlob(image)) |
597 | 0 | break; |
598 | 1.86k | } |
599 | 1.38k | MagickFreeResourceLimitedMemory(unsigned char *,scanline); |
600 | 1.38k | } |
601 | 6.50k | else |
602 | 6.50k | { |
603 | 6.50k | unsigned int |
604 | 6.50k | data_order; |
605 | | |
606 | 6.50k | magick_off_t |
607 | 6.50k | offset; |
608 | | |
609 | 6.50k | size_t |
610 | 6.50k | iris_pixels_size, |
611 | 6.50k | max_packets_alloc_size, |
612 | 6.50k | rle_alloc_size, |
613 | 6.50k | rle_dimensions; |
614 | | |
615 | 6.50k | magick_off_t |
616 | 6.50k | here; |
617 | | |
618 | 6.50k | rle_dimensions=MagickArraySize(iris_info.ysize, iris_info.zsize); |
619 | 6.50k | rle_alloc_size=MagickArraySize(rle_dimensions, sizeof(magick_uint32_t)); |
620 | | |
621 | 6.50k | if ((rle_dimensions == 0U) || (rle_alloc_size == 0U)) |
622 | 225 | ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed, |
623 | 6.50k | image); |
624 | | |
625 | | /* |
626 | | Read runlength-encoded image format. |
627 | | */ |
628 | 6.28k | if (TellBlob(image)+rle_alloc_size > (size_t) file_size) |
629 | 6.25k | ThrowSGIReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
630 | 6.25k | offsets=MagickAllocateResourceLimitedMemory(magick_uint32_t *,rle_alloc_size); |
631 | 6.25k | if (offsets == (magick_uint32_t *) NULL) |
632 | 0 | ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed, |
633 | 6.25k | image); |
634 | 6.25k | if (ReadBlob(image,rle_alloc_size,offsets) != rle_alloc_size) |
635 | 6.25k | ThrowSGIReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
636 | | |
637 | 6.25k | if (TellBlob(image)+rle_alloc_size > (size_t) file_size) |
638 | 6.22k | ThrowSGIReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
639 | 6.22k | runlength=MagickAllocateResourceLimitedMemory(magick_uint32_t *,rle_alloc_size); |
640 | 6.22k | if (runlength == (magick_uint32_t *) NULL) |
641 | 0 | ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed, |
642 | 6.22k | image); |
643 | 6.22k | if (ReadBlob(image,rle_alloc_size,runlength) != rle_alloc_size) |
644 | 6.22k | ThrowSGIReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
645 | | |
646 | 6.22k | #if !defined(WORDS_BIGENDIAN) |
647 | 6.22k | MagickSwabArrayOfUInt32(offsets,rle_dimensions); |
648 | 6.22k | MagickSwabArrayOfUInt32(runlength,rle_dimensions); |
649 | 6.22k | #endif |
650 | 6.22k | here=TellBlob(image); |
651 | | |
652 | 18.7k | for (i=0U; i < rle_dimensions; i++) |
653 | 14.6k | if ((offsets[i] != ((magick_off_t) offsets[i])) || |
654 | 14.6k | (offsets[i] < here) || |
655 | 13.3k | (offsets[i] > file_size)) |
656 | 4.11k | ThrowSGIReaderException(CorruptImageError,UnableToRunlengthDecodeImage,image); |
657 | 14.9k | for (i=0U; i < rle_dimensions; i++) |
658 | 11.3k | { |
659 | 11.3k | if (runlength[i] > ((size_t) 4U*iris_info.xsize+10U)) |
660 | 10.8k | ThrowSGIReaderException(CorruptImageError,UnableToRunlengthDecodeImage,image); |
661 | 10.8k | } |
662 | | |
663 | 3.58k | max_packets_alloc_size=MagickArraySize((size_t) iris_info.xsize+10U,4U); |
664 | 3.58k | max_packets=MagickAllocateResourceLimitedMemory(unsigned char *,max_packets_alloc_size); |
665 | 3.58k | if (max_packets == (unsigned char *) NULL) |
666 | 0 | ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed, |
667 | 3.58k | image); |
668 | | |
669 | 3.58k | iris_pixels_size=MagickArraySize(MagickArraySize(4U,bytes_per_pixel), |
670 | 3.58k | MagickArraySize(iris_info.xsize,iris_info.ysize)); |
671 | 3.58k | iris_pixels=MagickAllocateResourceLimitedMemory(unsigned char *,iris_pixels_size); |
672 | 3.58k | if (iris_pixels == (unsigned char *) NULL) |
673 | 3.58k | ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
674 | | |
675 | 3.58k | (void) memset(iris_pixels,0,iris_pixels_size); |
676 | | |
677 | | /* |
678 | | Check data order. |
679 | | */ |
680 | 3.58k | offset=0; |
681 | 3.58k | data_order=0U; |
682 | 9.76k | for (y=0; ((y < iris_info.ysize) && !data_order); y++) |
683 | 14.3k | for (z=0U; ((z < iris_info.zsize) && !data_order); z++) |
684 | 8.19k | { |
685 | 8.19k | const size_t run_index = (size_t) y+z*iris_info.ysize; |
686 | 8.19k | if (run_index >= rle_alloc_size) |
687 | 0 | ThrowSGIReaderException(CorruptImageError, |
688 | 8.19k | UnableToRunlengthDecodeImage,image); |
689 | 8.19k | if (offsets[run_index] < offset) |
690 | 142 | data_order=1; |
691 | 8.19k | offset=(magick_off_t) offsets[run_index]; |
692 | 8.19k | } |
693 | 3.58k | offset=TellBlob(image); |
694 | 3.58k | if (data_order == 1) |
695 | 142 | { |
696 | 232 | for (z=0U; z < iris_info.zsize; z++) |
697 | 191 | { |
698 | 191 | p=iris_pixels; |
699 | 2.61k | for (y=0U; y < iris_info.ysize; y++) |
700 | 2.52k | { |
701 | 2.52k | const size_t run_index = (size_t) y+z*iris_info.ysize; |
702 | 2.52k | size_t length; |
703 | 2.52k | if (run_index >= rle_alloc_size) |
704 | 0 | ThrowSGIReaderException(CorruptImageError, |
705 | 2.52k | UnableToRunlengthDecodeImage,image); |
706 | 2.52k | if (offset != (magick_off_t) offsets[run_index]) |
707 | 1.94k | { |
708 | 1.94k | offset=(magick_off_t) offsets[run_index]; |
709 | 1.94k | if (SeekBlob(image,offset,SEEK_SET) != offset) |
710 | 0 | ThrowSGIReaderException(CorruptImageError, |
711 | 1.94k | UnableToRunlengthDecodeImage, image); |
712 | 1.94k | } |
713 | 2.52k | length=runlength[run_index]; |
714 | 2.52k | if (length > max_packets_alloc_size) |
715 | 0 | ThrowSGIReaderException(CorruptImageError, |
716 | 2.52k | UnableToRunlengthDecodeImage,image); |
717 | 2.52k | if (ReadBlob(image,length,(char *) max_packets) != length) |
718 | 73 | ThrowSGIReaderException(CorruptImageError, |
719 | 2.52k | UnexpectedEndOfFile, image); |
720 | 2.45k | offset+=(magick_off_t) length; |
721 | 2.45k | if (SGIDecode(bytes_per_pixel,max_packets,p+bytes_per_pixel*z, |
722 | 2.45k | length/bytes_per_pixel, |
723 | 2.45k | iris_info.xsize) == -1) |
724 | 28 | ThrowSGIReaderException(CorruptImageError, |
725 | 2.45k | UnableToRunlengthDecodeImage,image); |
726 | 2.42k | p+=((size_t) iris_info.xsize*4U*bytes_per_pixel); |
727 | 2.42k | } |
728 | 191 | } |
729 | 142 | } |
730 | 3.44k | else |
731 | 3.44k | { |
732 | 3.44k | p=iris_pixels; |
733 | 5.56k | for (y=0; y < iris_info.ysize; y++) |
734 | 4.26k | { |
735 | 7.25k | for (z=0; z < iris_info.zsize; z++) |
736 | 5.13k | { |
737 | 5.13k | const size_t run_index = (size_t) y+z*iris_info.ysize; |
738 | 5.13k | size_t length; |
739 | 5.13k | if (run_index >= rle_alloc_size) |
740 | 0 | ThrowSGIReaderException(CorruptImageError, |
741 | 5.13k | UnableToRunlengthDecodeImage,image); |
742 | 5.13k | if (offset != (magick_off_t) offsets[run_index]) |
743 | 3.80k | { |
744 | 3.80k | offset=(magick_off_t) offsets[run_index]; |
745 | 3.80k | if (SeekBlob(image,offset,SEEK_SET) != offset) |
746 | 0 | ThrowSGIReaderException(CorruptImageError, |
747 | 3.80k | UnableToRunlengthDecodeImage, image); |
748 | 3.80k | } |
749 | 5.13k | length=runlength[run_index]; |
750 | 5.13k | if (length > max_packets_alloc_size) |
751 | 0 | ThrowSGIReaderException(CorruptImageError, |
752 | 5.13k | UnableToRunlengthDecodeImage,image); |
753 | 5.13k | if (ReadBlob(image,length, (char *) max_packets) != length) |
754 | 62 | ThrowSGIReaderException(CorruptImageError, |
755 | 5.13k | UnexpectedEndOfFile, image); |
756 | 5.06k | offset+=length; |
757 | 5.06k | if (SGIDecode(bytes_per_pixel,max_packets,p+bytes_per_pixel*z, |
758 | 5.06k | length/bytes_per_pixel, |
759 | 5.06k | iris_info.xsize) == -1) |
760 | 2.08k | ThrowSGIReaderException(CorruptImageError, |
761 | 5.06k | UnableToRunlengthDecodeImage,image); |
762 | 2.98k | } |
763 | 2.12k | p+=((size_t) iris_info.xsize*4U*bytes_per_pixel); |
764 | 2.12k | if (EOFBlob(image)) |
765 | 0 | break; |
766 | 2.12k | } |
767 | 3.44k | } |
768 | 1.34k | MagickFreeResourceLimitedMemory(magick_uint32_t *,runlength); |
769 | 1.34k | MagickFreeResourceLimitedMemory(unsigned char *,max_packets); |
770 | 1.34k | MagickFreeResourceLimitedMemory(magick_uint32_t *,offsets); |
771 | 1.34k | } |
772 | | |
773 | | /* |
774 | | Convert SGI raster image to pixel packets. |
775 | | */ |
776 | 2.73k | if (image->storage_class == DirectClass) |
777 | 624 | { |
778 | | /* |
779 | | Convert SGI image to DirectClass pixel packets. |
780 | | */ |
781 | 624 | if (bytes_per_pixel == 2U) |
782 | 523 | { |
783 | 19.1k | for (y=0; y < image->rows; y++) |
784 | 18.6k | { |
785 | 18.6k | p=iris_pixels+((size_t)image->rows-y-1)*8*image->columns; |
786 | 18.6k | q=SetImagePixels(image,0,y,image->columns,1); |
787 | 18.6k | if (q == (PixelPacket *) NULL) |
788 | 0 | break; |
789 | 1.25M | for (x=0U; x < image->columns; x++) |
790 | 1.23M | { |
791 | 1.23M | q->red=ScaleShortToQuantum((*(p+0) << 8U) | (*(p+1))); |
792 | 1.23M | q->green=ScaleShortToQuantum((*(p+2) << 8U) | (*(p+3))); |
793 | 1.23M | q->blue=ScaleShortToQuantum((*(p+4) << 8U) | (*(p+5))); |
794 | 1.23M | if (image->matte) |
795 | 2.24k | q->opacity=(Quantum) |
796 | 2.24k | (MaxRGB-ScaleShortToQuantum((*(p+6) << 8) | (*(p+7)))); |
797 | 1.23M | else |
798 | 1.23M | q->opacity=OpaqueOpacity; |
799 | 1.23M | p+=8U; |
800 | 1.23M | q++; |
801 | 1.23M | } |
802 | 18.6k | if (!SyncImagePixels(image)) |
803 | 0 | break; |
804 | 18.6k | if (QuantumTick(y,image->rows)) |
805 | 6.27k | if (!MagickMonitorFormatted(y,image->rows,exception, |
806 | 6.27k | LoadImageText,image->filename, |
807 | 6.27k | image->columns,image->rows)) |
808 | 0 | break; |
809 | 18.6k | } |
810 | 523 | } |
811 | 101 | else |
812 | 74.0k | for (y=0; y < image->rows; y++) |
813 | 73.9k | { |
814 | 73.9k | p=iris_pixels+((size_t) image->rows-y-1)*4*image->columns; |
815 | 73.9k | q=SetImagePixels(image,0,y,image->columns,1); |
816 | 73.9k | if (q == (PixelPacket *) NULL) |
817 | 0 | break; |
818 | 831k | for (x=0; x < image->columns; x++) |
819 | 757k | { |
820 | 757k | q->red=ScaleCharToQuantum(*p); |
821 | 757k | q->green=ScaleCharToQuantum(*(p+1)); |
822 | 757k | q->blue=ScaleCharToQuantum(*(p+2)); |
823 | 757k | if (image->matte) |
824 | 667k | q->opacity=(Quantum) (MaxRGB-ScaleCharToQuantum(*(p+3))); |
825 | 90.3k | else |
826 | 90.3k | q->opacity=OpaqueOpacity; |
827 | 757k | p+=4; |
828 | 757k | q++; |
829 | 757k | } |
830 | 73.9k | if (!SyncImagePixels(image)) |
831 | 0 | break; |
832 | 73.9k | if (QuantumTick(y,image->rows)) |
833 | 7.25k | if (!MagickMonitorFormatted(y,image->rows,exception, |
834 | 7.25k | LoadImageText,image->filename, |
835 | 7.25k | image->columns,image->rows)) |
836 | 0 | break; |
837 | 73.9k | } |
838 | 624 | } |
839 | 2.10k | else |
840 | 2.10k | { |
841 | | /* |
842 | | Create grayscale map. |
843 | | */ |
844 | 2.10k | if (!AllocateImageColormap(image,image->colors)) |
845 | 0 | ThrowSGIReaderException(ResourceLimitError,MemoryAllocationFailed, |
846 | 2.10k | image); |
847 | | /* |
848 | | Convert SGI image to PseudoClass pixel packets. |
849 | | */ |
850 | 2.10k | if (bytes_per_pixel == 2) |
851 | 0 | { |
852 | 0 | for (y=0; y < image->rows; y++) |
853 | 0 | { |
854 | 0 | p=iris_pixels+((size_t)image->rows-y-1)*8*image->columns; |
855 | 0 | q=SetImagePixels(image,0,y,image->columns,1); |
856 | 0 | if (q == (PixelPacket *) NULL) |
857 | 0 | break; |
858 | 0 | indexes=AccessMutableIndexes(image); |
859 | 0 | for (x=0; x < image->columns; x++) |
860 | 0 | { |
861 | 0 | indexes[x]=(*p << 8); |
862 | 0 | indexes[x]|=(*(p+1)); |
863 | 0 | p+=8; |
864 | 0 | q++; |
865 | 0 | } |
866 | 0 | if (!SyncImagePixels(image)) |
867 | 0 | break; |
868 | 0 | if (QuantumTick(y,image->rows)) |
869 | 0 | if (!MagickMonitorFormatted(y,image->rows,exception, |
870 | 0 | LoadImageText,image->filename, |
871 | 0 | image->columns,image->rows)) |
872 | 0 | break; |
873 | 0 | } |
874 | 0 | } |
875 | 2.10k | else |
876 | 2.10k | { |
877 | 39.4k | for (y=0; y < image->rows; y++) |
878 | 37.3k | { |
879 | 37.3k | p=iris_pixels+((size_t)image->rows-y-1)*4U*image->columns; |
880 | 37.3k | q=SetImagePixels(image,0,y,image->columns,1); |
881 | 37.3k | if (q == (PixelPacket *) NULL) |
882 | 0 | break; |
883 | 37.3k | indexes=AccessMutableIndexes(image); |
884 | 9.62M | for (x=0; x < image->columns; x++) |
885 | 9.59M | { |
886 | 9.59M | indexes[x]=(*p); |
887 | 9.59M | p+=4; |
888 | 9.59M | q++; |
889 | 9.59M | } |
890 | 37.3k | if (!SyncImagePixels(image)) |
891 | 0 | break; |
892 | 37.3k | if (QuantumTick(y,image->rows)) |
893 | 10.0k | if (!MagickMonitorFormatted(y,image->rows,exception, |
894 | 10.0k | LoadImageText,image->filename, |
895 | 10.0k | image->columns,image->rows)) |
896 | 0 | break; |
897 | 37.3k | } |
898 | 2.10k | } |
899 | 2.10k | if (y < image->rows) |
900 | 0 | { |
901 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
902 | 0 | "Only transferred %lu rows out of %lu", |
903 | 0 | y, image->rows); |
904 | 0 | MagickFreeResourceLimitedMemory(unsigned char *,iris_pixels); |
905 | | /* |
906 | | Not sure what a proper error report is here |
907 | | */ |
908 | 0 | ThrowSGIReaderException(CorruptImageError,UnableToReadImageData,image); |
909 | 0 | } |
910 | 2.10k | (void) SyncImage(image); |
911 | 2.10k | } |
912 | 2.73k | MagickFreeResourceLimitedMemory(unsigned char *,iris_pixels); |
913 | 2.73k | if (EOFBlob(image)) |
914 | 0 | { |
915 | 0 | ThrowSGIReaderException(CorruptImageError,UnexpectedEndOfFile, |
916 | 0 | image); |
917 | 0 | break; |
918 | 0 | } |
919 | 2.73k | } while (0); |
920 | 2.73k | CloseBlob(image); |
921 | 2.73k | StopTimer(&image->timer); |
922 | 2.73k | return(image); |
923 | 120k | } |
924 | | |
925 | | /* |
926 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
927 | | % % |
928 | | % % |
929 | | % % |
930 | | % R e g i s t e r S G I I m a g e % |
931 | | % % |
932 | | % % |
933 | | % % |
934 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
935 | | % |
936 | | % Method RegisterSGIImage adds attributes for the SGI image format to |
937 | | % the list of supported formats. The attributes include the image format |
938 | | % tag, a method to read and/or write the format, whether the format |
939 | | % supports the saving of more than one frame to the same file or blob, |
940 | | % whether the format supports native in-memory I/O, and a brief |
941 | | % description of the format. |
942 | | % |
943 | | % The format of the RegisterSGIImage method is: |
944 | | % |
945 | | % RegisterSGIImage(void) |
946 | | % |
947 | | */ |
948 | | ModuleExport void RegisterSGIImage(void) |
949 | 6 | { |
950 | 6 | MagickInfo |
951 | 6 | *entry; |
952 | | |
953 | 6 | entry=SetMagickInfo("SGI"); |
954 | 6 | entry->decoder=(DecoderHandler) ReadSGIImage; |
955 | 6 | entry->encoder=(EncoderHandler) WriteSGIImage; |
956 | 6 | entry->magick=(MagickHandler) IsSGI; |
957 | 6 | entry->description="Irix RGB image"; |
958 | 6 | entry->module="SGI"; |
959 | 6 | entry->adjoin=MagickFalse; |
960 | 6 | entry->seekable_stream=True; |
961 | 6 | (void) RegisterMagickInfo(entry); |
962 | 6 | } |
963 | | |
964 | | /* |
965 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
966 | | % % |
967 | | % % |
968 | | % % |
969 | | % U n r e g i s t e r S G I I m a g e % |
970 | | % % |
971 | | % % |
972 | | % % |
973 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
974 | | % |
975 | | % Method UnregisterSGIImage removes format registrations made by the |
976 | | % SGI module from the list of supported formats. |
977 | | % |
978 | | % The format of the UnregisterSGIImage method is: |
979 | | % |
980 | | % UnregisterSGIImage(void) |
981 | | % |
982 | | */ |
983 | | ModuleExport void UnregisterSGIImage(void) |
984 | 0 | { |
985 | 0 | (void) UnregisterMagickInfo("SGI"); |
986 | 0 | } |
987 | | |
988 | | /* |
989 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
990 | | % % |
991 | | % % |
992 | | % % |
993 | | % W r i t e S G I I m a g e % |
994 | | % % |
995 | | % % |
996 | | % % |
997 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
998 | | % |
999 | | % Method WriteSGIImage writes an image in SGI RGB encoded image format. |
1000 | | % |
1001 | | % The format of the WriteSGIImage method is: |
1002 | | % |
1003 | | % unsigned int WriteSGIImage(const ImageInfo *image_info,Image *image) |
1004 | | % |
1005 | | % A description of each parameter follows. |
1006 | | % |
1007 | | % o status: Method WriteSGIImage return True if the image is written. |
1008 | | % False is returned is there is a memory shortage or if the image file |
1009 | | % fails to write. |
1010 | | % |
1011 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
1012 | | % |
1013 | | % o image: A pointer to an Image structure. |
1014 | | % |
1015 | | % |
1016 | | */ |
1017 | | |
1018 | | static size_t SGIEncode(unsigned char *pixels,size_t count, |
1019 | | unsigned char *packets) |
1020 | 371k | { |
1021 | 371k | short |
1022 | 371k | runlength; |
1023 | | |
1024 | 371k | register unsigned char |
1025 | 371k | *p, |
1026 | 371k | *q; |
1027 | | |
1028 | 371k | unsigned char |
1029 | 371k | *limit, |
1030 | 371k | *mark; |
1031 | | |
1032 | 371k | p=pixels; |
1033 | 371k | limit=p+count*4; |
1034 | 371k | q=packets; |
1035 | 1.04M | while (p < limit) |
1036 | 676k | { |
1037 | 676k | mark=p; |
1038 | 676k | p+=8; |
1039 | 7.36M | while ((p < limit) && ((*(p-8) != *(p-4)) || (*(p-4) != *p))) |
1040 | 6.68M | p+=4; |
1041 | 676k | p-=8; |
1042 | 676k | count=((p-mark) >> 2); |
1043 | 1.01M | while (count) |
1044 | 333k | { |
1045 | 333k | runlength=(short) (count > 126 ? 126 : count); |
1046 | 333k | count-=runlength; |
1047 | 333k | *q++=0x80 | runlength; |
1048 | 7.01M | for ( ; runlength > 0; runlength--) |
1049 | 6.68M | { |
1050 | 6.68M | *q++=(*mark); |
1051 | 6.68M | mark+=4; |
1052 | 6.68M | } |
1053 | 333k | } |
1054 | 676k | mark=p; |
1055 | 676k | p+=4; |
1056 | 9.55M | while ((p < limit) && (*p == *mark)) |
1057 | 8.88M | p+=4; |
1058 | 676k | count=((p-mark) >> 2); |
1059 | 1.41M | while (count) |
1060 | 737k | { |
1061 | 737k | runlength=(short) (count > 126 ? 126 : count); |
1062 | 737k | count-=runlength; |
1063 | 737k | *q++=(unsigned char) runlength; |
1064 | 737k | *q++=(*mark); |
1065 | 737k | } |
1066 | 676k | } |
1067 | 371k | *q++=0; |
1068 | 371k | return(q-packets); |
1069 | 371k | } |
1070 | | |
1071 | 0 | #define ThrowSGIWriterException(code_,reason_,image_) \ |
1072 | 0 | { \ |
1073 | 0 | MagickFreeResourceLimitedMemory(unsigned char *,scanline) \ |
1074 | 0 | MagickFreeResourceLimitedMemory(magick_uint32_t *,offsets); \ |
1075 | 0 | MagickFreeResourceLimitedMemory(unsigned char *,packets); \ |
1076 | 0 | MagickFreeResourceLimitedMemory(magick_uint32_t *,runlength); \ |
1077 | 0 | MagickFreeResourceLimitedMemory(unsigned char *,iris_pixels); \ |
1078 | 0 | ThrowWriterException(code_,reason_,image_); \ |
1079 | 0 | } |
1080 | | |
1081 | | static unsigned int WriteSGIImage(const ImageInfo *image_info,Image *image) |
1082 | 390 | { |
1083 | 390 | long |
1084 | 390 | y, |
1085 | 390 | z; |
1086 | | |
1087 | 390 | SGIInfo |
1088 | 390 | iris_info; |
1089 | | |
1090 | 390 | register const PixelPacket |
1091 | 390 | *p; |
1092 | | |
1093 | 390 | register long |
1094 | 390 | i, |
1095 | 390 | x; |
1096 | | |
1097 | 390 | register unsigned char |
1098 | 390 | *q; |
1099 | | |
1100 | 390 | magick_uint32_t |
1101 | 390 | *offsets = (magick_uint32_t *) NULL, |
1102 | 390 | *runlength = (magick_uint32_t *) NULL; |
1103 | | |
1104 | 390 | unsigned char |
1105 | 390 | *iris_pixels = (unsigned char *) NULL, |
1106 | 390 | *packets = (unsigned char *) NULL, |
1107 | 390 | *scanline = (unsigned char *) NULL; |
1108 | | |
1109 | 390 | unsigned int |
1110 | 390 | status; |
1111 | | |
1112 | 390 | unsigned long |
1113 | 390 | number_pixels; |
1114 | | |
1115 | | /* |
1116 | | Open output image file. |
1117 | | */ |
1118 | 390 | assert(image_info != (const ImageInfo *) NULL); |
1119 | 390 | assert(image_info->signature == MagickSignature); |
1120 | 390 | assert(image != (Image *) NULL); |
1121 | 390 | assert(image->signature == MagickSignature); |
1122 | 390 | if ((image->columns > 65535L) || (image->rows > 65535L)) |
1123 | 390 | ThrowWriterException(ImageError,WidthOrHeightExceedsLimit,image); |
1124 | 390 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); |
1125 | 390 | if (status == MagickFail) |
1126 | 390 | ThrowWriterException(FileOpenError,UnableToOpenFile,image); |
1127 | 390 | do |
1128 | 390 | { |
1129 | 390 | ImageCharacteristics |
1130 | 390 | characteristics; |
1131 | | |
1132 | | /* |
1133 | | Ensure that image is in an RGB space. |
1134 | | */ |
1135 | 390 | (void) TransformColorspace(image,RGBColorspace); |
1136 | | /* |
1137 | | Analyze image to be written. |
1138 | | */ |
1139 | 390 | (void) GetImageCharacteristics(image,&characteristics, |
1140 | 390 | (OptimizeType == image_info->type), |
1141 | 390 | &image->exception); |
1142 | | /* |
1143 | | Initialize SGI raster file header. |
1144 | | */ |
1145 | 390 | iris_info.magic=0x01DA; |
1146 | 390 | if (image_info->compression == NoCompression) |
1147 | 0 | iris_info.storage=0x00; |
1148 | 390 | else |
1149 | 390 | iris_info.storage=0x01; |
1150 | 390 | iris_info.bytes_per_pixel=1; /* one byte per pixel */ |
1151 | 390 | iris_info.dimension=3; |
1152 | 390 | iris_info.xsize=(unsigned short) image->columns; |
1153 | 390 | iris_info.ysize=(unsigned short) image->rows; |
1154 | 390 | if (image->matte != MagickFalse) |
1155 | 51 | iris_info.zsize=4; |
1156 | 339 | else |
1157 | 339 | { |
1158 | 339 | if ((image_info->type != TrueColorType) && |
1159 | 339 | (characteristics.grayscale)) |
1160 | 182 | { |
1161 | 182 | iris_info.dimension=2; |
1162 | 182 | iris_info.zsize=1; |
1163 | 182 | } |
1164 | 157 | else |
1165 | 157 | iris_info.zsize=3; |
1166 | 339 | } |
1167 | 390 | iris_info.pix_min=0; |
1168 | 390 | iris_info.pix_max=ScaleQuantumToChar(MaxRGB); |
1169 | | |
1170 | 390 | (void) memset(iris_info.dummy1,0,sizeof(iris_info.dummy1)); |
1171 | 390 | { |
1172 | 390 | const ImageAttribute |
1173 | 390 | *attribute; |
1174 | | |
1175 | 390 | (void) memset(iris_info.image_name,0,sizeof(iris_info.image_name)); |
1176 | 390 | if ((attribute=GetImageAttribute(image,"comment"))) |
1177 | 229 | (void) strlcpy(iris_info.image_name,attribute->value,sizeof(iris_info.image_name)); |
1178 | 390 | } |
1179 | 390 | iris_info.color_map=0; |
1180 | 390 | (void) memset(iris_info.dummy2,0,sizeof(iris_info.dummy2)); |
1181 | | |
1182 | | /* |
1183 | | Write SGI header. |
1184 | | */ |
1185 | 390 | (void) WriteBlobMSBShort(image,iris_info.magic); |
1186 | 390 | (void) WriteBlobByte(image,iris_info.storage); |
1187 | 390 | (void) WriteBlobByte(image,iris_info.bytes_per_pixel); |
1188 | 390 | (void) WriteBlobMSBShort(image,iris_info.dimension); |
1189 | 390 | (void) WriteBlobMSBShort(image,iris_info.xsize); |
1190 | 390 | (void) WriteBlobMSBShort(image,iris_info.ysize); |
1191 | 390 | (void) WriteBlobMSBShort(image,iris_info.zsize); |
1192 | 390 | (void) WriteBlobMSBLong(image,iris_info.pix_min); |
1193 | 390 | (void) WriteBlobMSBLong(image,iris_info.pix_max); |
1194 | 390 | (void) WriteBlob(image,sizeof(iris_info.dummy1), |
1195 | 390 | (char *) iris_info.dummy1); |
1196 | 390 | (void) WriteBlob(image,sizeof(iris_info.image_name), |
1197 | 390 | (char *) iris_info.image_name); |
1198 | 390 | (void) WriteBlobMSBLong(image,iris_info.color_map); |
1199 | 390 | (void) WriteBlob(image,sizeof(iris_info.dummy2), |
1200 | 390 | (char *) iris_info.dummy2); |
1201 | | /* |
1202 | | Allocate SGI pixels. |
1203 | | */ |
1204 | 390 | number_pixels=image->columns*image->rows; |
1205 | 390 | iris_pixels=MagickAllocateResourceLimitedArray(unsigned char *,4,number_pixels); |
1206 | 390 | if (iris_pixels == (unsigned char *) NULL) |
1207 | 390 | ThrowSGIWriterException(ResourceLimitError,MemoryAllocationFailed,image); |
1208 | | /* |
1209 | | Convert image pixels to uncompressed SGI pixels. |
1210 | | */ |
1211 | 128k | for (y=0; y < (long) image->rows; y++) |
1212 | 127k | { |
1213 | 127k | p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception); |
1214 | 127k | if (p == (const PixelPacket *) NULL) |
1215 | 0 | break; |
1216 | 127k | q=iris_pixels+(((size_t)iris_info.ysize-1)-y)*((size_t)iris_info.xsize*4); |
1217 | 11.7M | for (x=0; x < (long) image->columns; x++) |
1218 | 11.5M | { |
1219 | 11.5M | *q++=ScaleQuantumToChar(p->red); |
1220 | 11.5M | *q++=ScaleQuantumToChar(p->green); |
1221 | 11.5M | *q++=ScaleQuantumToChar(p->blue); |
1222 | 11.5M | *q++=ScaleQuantumToChar(MaxRGB-p->opacity); |
1223 | 11.5M | p++; |
1224 | 11.5M | } |
1225 | 127k | if (QuantumTick(y,image->rows)) |
1226 | 21.2k | if (!MagickMonitorFormatted(y,image->rows,&image->exception, |
1227 | 21.2k | SaveImageText,image->filename, |
1228 | 21.2k | image->columns,image->rows)) |
1229 | 0 | break; |
1230 | 127k | } |
1231 | 390 | if (image_info->compression == NoCompression) |
1232 | 0 | { |
1233 | | /* |
1234 | | Write uncompressed SGI pixels. |
1235 | | */ |
1236 | 0 | scanline=MagickAllocateResourceLimitedMemory(unsigned char *,iris_info.xsize); |
1237 | 0 | if (scanline == (unsigned char *) NULL) |
1238 | 0 | ThrowSGIWriterException(ResourceLimitError,MemoryAllocationFailed, |
1239 | 0 | image); |
1240 | 0 | for (z=0; z < (int) iris_info.zsize; z++) |
1241 | 0 | { |
1242 | 0 | q=iris_pixels+z; |
1243 | 0 | for (y=0; y < (long) iris_info.ysize; y++) |
1244 | 0 | { |
1245 | 0 | for (x=0; x < (long) iris_info.xsize; x++) |
1246 | 0 | { |
1247 | 0 | scanline[x]=(*q); |
1248 | 0 | q+=4; |
1249 | 0 | } |
1250 | 0 | (void) WriteBlob(image,iris_info.xsize,(char *) scanline); |
1251 | 0 | } |
1252 | 0 | } |
1253 | 0 | MagickFreeResourceLimitedMemory(unsigned char *,scanline); |
1254 | 0 | } |
1255 | 390 | else |
1256 | 390 | { |
1257 | 390 | magick_uint32_t |
1258 | 390 | length, |
1259 | 390 | number_packets, |
1260 | 390 | offset; |
1261 | | |
1262 | | /* |
1263 | | Convert SGI uncompressed pixels. |
1264 | | */ |
1265 | 390 | offsets=MagickAllocateResourceLimitedArray(magick_uint32_t *,iris_info.ysize, |
1266 | 390 | MagickArraySize(iris_info.zsize, |
1267 | 390 | sizeof(magick_uint32_t))); |
1268 | 390 | packets=MagickAllocateResourceLimitedArray(unsigned char *, |
1269 | 390 | 4*(2*(size_t) iris_info.xsize+10), |
1270 | 390 | image->rows); |
1271 | 390 | runlength=MagickAllocateResourceLimitedArray(magick_uint32_t *,iris_info.ysize, |
1272 | 390 | MagickArraySize(iris_info.zsize, |
1273 | 390 | sizeof(magick_uint32_t))); |
1274 | 390 | if ((offsets == (magick_uint32_t *) NULL) || |
1275 | 390 | (packets == (unsigned char *) NULL) || |
1276 | 390 | (runlength == (magick_uint32_t *) NULL)) |
1277 | 0 | ThrowSGIWriterException(ResourceLimitError,MemoryAllocationFailed, |
1278 | 390 | image); |
1279 | 390 | offset=512+4*2*((size_t) iris_info.ysize*iris_info.zsize); |
1280 | 390 | number_packets=0; |
1281 | 390 | q=iris_pixels; |
1282 | 128k | for (y=0; y < (long) iris_info.ysize; y++) |
1283 | 127k | { |
1284 | 499k | for (z=0; z < (int) iris_info.zsize; z++) |
1285 | 371k | { |
1286 | 371k | length=(magick_uint32_t) |
1287 | 371k | SGIEncode(q+z,(int) iris_info.xsize,packets+number_packets); |
1288 | 371k | number_packets+=length; |
1289 | 371k | offsets[y+z*iris_info.ysize]=offset; |
1290 | 371k | runlength[y+z*iris_info.ysize]=length; |
1291 | 371k | offset+=length; |
1292 | 371k | } |
1293 | 127k | q+=((size_t)iris_info.xsize*4); |
1294 | 127k | } |
1295 | | /* |
1296 | | Write out line start and length tables and runlength-encoded pixels. |
1297 | | */ |
1298 | 371k | for (i=0; i < (int) (iris_info.ysize*iris_info.zsize); i++) |
1299 | 371k | (void) WriteBlobMSBLong(image,offsets[i]); |
1300 | 371k | for (i=0; i < (int) (iris_info.ysize*iris_info.zsize); i++) |
1301 | 371k | (void) WriteBlobMSBLong(image,runlength[i]); |
1302 | 390 | (void) WriteBlob(image,number_packets,(char *) packets); |
1303 | | /* |
1304 | | Free memory. |
1305 | | */ |
1306 | 390 | MagickFreeResourceLimitedMemory(magick_uint32_t *,runlength); |
1307 | 390 | MagickFreeResourceLimitedMemory(unsigned char *,packets); |
1308 | 390 | MagickFreeResourceLimitedMemory(magick_uint32_t *,offsets); |
1309 | 390 | } |
1310 | 390 | MagickFreeResourceLimitedMemory(unsigned char *,iris_pixels); |
1311 | 390 | } while (0); |
1312 | 390 | status &= CloseBlob(image); |
1313 | 390 | return(status); |
1314 | 390 | } |