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