/src/graphicsmagick/coders/rla.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 | | % RRRR L AAA % |
15 | | % R R L A A % |
16 | | % RRRR L AAAAA % |
17 | | % R R L A A % |
18 | | % R R LLLLL A A % |
19 | | % % |
20 | | % % |
21 | | % Read Alias/Wavefront 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/attribute.h" |
40 | | #include "magick/blob.h" |
41 | | #include "magick/pixel_cache.h" |
42 | | #include "magick/log.h" |
43 | | #include "magick/magick.h" |
44 | | #include "magick/monitor.h" |
45 | | #include "magick/utility.h" |
46 | | #include "magick/static.h" |
47 | | |
48 | | /* |
49 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
50 | | % % |
51 | | % % |
52 | | % % |
53 | | % R e a d R L A I m a g e % |
54 | | % % |
55 | | % % |
56 | | % % |
57 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
58 | | % |
59 | | % Method ReadRLAImage reads a run-length encoded Wavefront RLA image file |
60 | | % and returns it. It allocates the memory necessary for the new Image |
61 | | % structure and returns a pointer to the new image. |
62 | | % |
63 | | % Note: This module was contributed by Lester Vecsey (master@internexus.net). |
64 | | % |
65 | | % The format of the ReadRLAImage method is: |
66 | | % |
67 | | % Image *ReadRLAImage(const ImageInfo *image_info,ExceptionInfo *exception) |
68 | | % |
69 | | % A description of each parameter follows: |
70 | | % |
71 | | % o image: Method ReadRLAImage returns a pointer to the image after |
72 | | % reading. A null image is returned if there is a memory shortage or |
73 | | % if the image cannot be read. |
74 | | % |
75 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
76 | | % |
77 | | % o exception: return any errors or warnings in this structure. |
78 | | % |
79 | | % |
80 | | */ |
81 | 11.1k | #define NULLTerminateASCIIField(field) \ |
82 | 11.1k | { \ |
83 | 11.1k | field[sizeof(field)-1]='\0'; \ |
84 | 11.1k | } |
85 | | |
86 | 507 | #define ThrowRLAReaderException(code_,reason_,image_) \ |
87 | 663 | do { \ |
88 | 663 | MagickFreeResourceLimitedMemory(magick_uint32_t *,scanlines); \ |
89 | 663 | ThrowReaderException(code_,reason_,image_); \ |
90 | 0 | } while (0); |
91 | | static Image *ReadRLAImage(const ImageInfo *image_info,ExceptionInfo *exception) |
92 | 734 | { |
93 | 734 | typedef struct _WindowFrame |
94 | 734 | { |
95 | 734 | short |
96 | 734 | left, |
97 | 734 | right, |
98 | 734 | bottom, |
99 | 734 | top; |
100 | 734 | } WindowFrame; |
101 | | |
102 | 734 | typedef struct _RLAInfo |
103 | 734 | { |
104 | 734 | WindowFrame |
105 | 734 | window, |
106 | 734 | active_window; |
107 | | |
108 | 734 | magick_uint16_t |
109 | 734 | frame, |
110 | 734 | storage_type, |
111 | 734 | number_channels, |
112 | 734 | number_matte_channels, |
113 | 734 | number_auxiliary_channels, |
114 | 734 | revision; /* aux_mask in RLB */ |
115 | | |
116 | 734 | char |
117 | 734 | gamma[16], |
118 | 734 | red_primary[24], |
119 | 734 | green_primary[24], |
120 | 734 | blue_primary[24], |
121 | 734 | white_point[24]; |
122 | | |
123 | 734 | magick_uint32_t |
124 | 734 | job_number; |
125 | | |
126 | 734 | char |
127 | 734 | name[128], |
128 | 734 | description[128], |
129 | 734 | program[64], |
130 | 734 | machine[32], |
131 | 734 | user[32], |
132 | 734 | date[20], |
133 | 734 | aspect[24], |
134 | 734 | aspect_ratio[8], |
135 | 734 | chan[32]; |
136 | | |
137 | 734 | magick_uint16_t |
138 | 734 | field; |
139 | | |
140 | | /* RLB varies after this point */ |
141 | | |
142 | 734 | } RLAInfo; |
143 | | |
144 | 734 | typedef struct _RLA3ExtraInfo |
145 | 734 | { |
146 | 734 | char |
147 | 734 | time[12], |
148 | 734 | filter[32]; |
149 | | |
150 | 734 | magick_uint16_t |
151 | 734 | bits_per_channel, |
152 | 734 | matte_type, |
153 | 734 | matte_bits, |
154 | 734 | auxiliary_type, |
155 | 734 | auxiliary_bits; |
156 | | |
157 | 734 | char |
158 | 734 | auxiliary[32], |
159 | 734 | space[36]; |
160 | | |
161 | 734 | magick_uint32_t |
162 | 734 | next; |
163 | 734 | } RLA3ExtraInfo; |
164 | | |
165 | 734 | typedef struct _RLBExtraInfo |
166 | 734 | { |
167 | 734 | magick_uint16_t |
168 | 734 | filter_type; |
169 | | |
170 | 734 | magick_uint32_t |
171 | 734 | magic_number, |
172 | 734 | lut_size, |
173 | 734 | user_space_size, |
174 | 734 | wf_space_size; |
175 | | |
176 | 734 | magick_uint16_t |
177 | 734 | lut_type, |
178 | 734 | mix_type, |
179 | 734 | encode_type, |
180 | 734 | padding; |
181 | | |
182 | 734 | char |
183 | 734 | space[100]; |
184 | 734 | } RLBExtraInfo; |
185 | | |
186 | 734 | Image |
187 | 734 | *image; |
188 | | |
189 | 734 | int |
190 | 734 | channel, |
191 | 734 | length, |
192 | 734 | number_channels, |
193 | 734 | runlength; |
194 | | |
195 | 734 | unsigned long |
196 | 734 | y; |
197 | | |
198 | 734 | magick_uint32_t |
199 | 734 | *scanlines=0; |
200 | | |
201 | 734 | register unsigned long |
202 | 734 | i, |
203 | 734 | x; |
204 | | |
205 | 734 | register PixelPacket |
206 | 734 | *q; |
207 | | |
208 | 734 | RLAInfo |
209 | 734 | rla_info; |
210 | | |
211 | 734 | RLA3ExtraInfo |
212 | 734 | rla3_extra_info; |
213 | | |
214 | 734 | RLBExtraInfo |
215 | 734 | rlb_extra_info; |
216 | | |
217 | 734 | MagickBool |
218 | 734 | is_rla3; |
219 | | |
220 | 734 | int |
221 | 734 | byte; |
222 | | |
223 | 734 | MagickPassFail |
224 | 734 | status; |
225 | | |
226 | 734 | magick_off_t |
227 | 734 | current_offset, |
228 | 734 | file_size; |
229 | | |
230 | | /* |
231 | | Open image file. |
232 | | */ |
233 | 734 | assert(image_info != (const ImageInfo *) NULL); |
234 | 734 | assert(image_info->signature == MagickSignature); |
235 | 734 | assert(exception != (ExceptionInfo *) NULL); |
236 | 734 | assert(exception->signature == MagickSignature); |
237 | 734 | image=AllocateImage(image_info); |
238 | 734 | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
239 | 734 | if (status == MagickFail) |
240 | 734 | ThrowReaderException(FileOpenError,UnableToOpenFile,image); |
241 | 734 | file_size=GetBlobSize(image); |
242 | 734 | is_rla3=MagickFalse; |
243 | 734 | memset(&rla_info,0,sizeof(rla_info)); |
244 | 734 | memset(&rla3_extra_info,0,sizeof(rla3_extra_info)); |
245 | 734 | memset(&rlb_extra_info,0,sizeof(rlb_extra_info)); |
246 | 734 | rla_info.window.left=ReadBlobMSBShort(image); |
247 | 734 | rla_info.window.right=ReadBlobMSBShort(image); |
248 | 734 | rla_info.window.bottom=ReadBlobMSBShort(image); |
249 | 734 | rla_info.window.top=ReadBlobMSBShort(image); |
250 | 734 | rla_info.active_window.left=ReadBlobMSBShort(image); |
251 | 734 | rla_info.active_window.right=ReadBlobMSBShort(image); |
252 | 734 | rla_info.active_window.bottom=ReadBlobMSBShort(image); |
253 | 734 | rla_info.active_window.top=ReadBlobMSBShort(image); |
254 | 734 | rla_info.frame=ReadBlobMSBShort(image); |
255 | 734 | rla_info.storage_type=ReadBlobMSBShort(image); |
256 | 734 | rla_info.number_channels=ReadBlobMSBShort(image); |
257 | 734 | rla_info.number_matte_channels=ReadBlobMSBShort(image); |
258 | 734 | if (rla_info.number_channels == 0) |
259 | 467 | rla_info.number_channels=3; |
260 | 734 | rla_info.number_auxiliary_channels=ReadBlobMSBShort(image); |
261 | 734 | rla_info.revision=ReadBlobMSBShort(image); |
262 | 734 | if (rla_info.revision == 0xFFFE) |
263 | 34 | is_rla3=MagickTrue; |
264 | 734 | (void) ReadBlob(image,16,(char *) rla_info.gamma); |
265 | 734 | NULLTerminateASCIIField(rla_info.gamma); |
266 | 734 | (void) ReadBlob(image,24,(char *) rla_info.red_primary); |
267 | 734 | NULLTerminateASCIIField(rla_info.red_primary); |
268 | 734 | (void) ReadBlob(image,24,(char *) rla_info.green_primary); |
269 | 734 | NULLTerminateASCIIField(rla_info.green_primary) |
270 | 734 | (void) ReadBlob(image,24,(char *) rla_info.blue_primary); |
271 | 734 | NULLTerminateASCIIField(rla_info.blue_primary); |
272 | 734 | (void) ReadBlob(image,24,(char *) rla_info.white_point); |
273 | 734 | NULLTerminateASCIIField(rla_info.white_point); |
274 | 734 | rla_info.job_number=(long) ReadBlobMSBLong(image); |
275 | 734 | (void) ReadBlob(image,128,(char *) rla_info.name); |
276 | 734 | NULLTerminateASCIIField(rla_info.name); |
277 | 734 | (void) ReadBlob(image,128,(char *) rla_info.description); |
278 | 734 | NULLTerminateASCIIField(rla_info.description); |
279 | 734 | (void) ReadBlob(image,64,(char *) rla_info.program); |
280 | 734 | NULLTerminateASCIIField(rla_info.program); |
281 | 734 | (void) ReadBlob(image,32,(char *) rla_info.machine); |
282 | 734 | NULLTerminateASCIIField(rla_info.machine); |
283 | 734 | (void) ReadBlob(image,32,(char *) rla_info.user); |
284 | 734 | NULLTerminateASCIIField(rla_info.user); |
285 | 734 | (void) ReadBlob(image,20,(char *) rla_info.date); |
286 | 734 | NULLTerminateASCIIField(rla_info.date); |
287 | 734 | (void) ReadBlob(image,24,(char *) rla_info.aspect); |
288 | 734 | NULLTerminateASCIIField(rla_info.aspect); |
289 | 734 | (void) ReadBlob(image,8,(char *) rla_info.aspect_ratio); |
290 | 734 | NULLTerminateASCIIField(rla_info.aspect_ratio); |
291 | 734 | (void) ReadBlob(image,32,(char *) rla_info.chan); |
292 | 734 | NULLTerminateASCIIField(rla_info.chan); |
293 | 734 | rla_info.field=ReadBlobMSBShort(image); |
294 | 734 | if (is_rla3) |
295 | 34 | { |
296 | 34 | (void) ReadBlob(image,12,(char *) rla3_extra_info.time); |
297 | 34 | NULLTerminateASCIIField(rla3_extra_info.time); |
298 | 34 | (void) ReadBlob(image,32,(char *) rla3_extra_info.filter); |
299 | 34 | NULLTerminateASCIIField(rla3_extra_info.filter); |
300 | 34 | rla3_extra_info.bits_per_channel=ReadBlobMSBShort(image); |
301 | 34 | rla3_extra_info.matte_type=ReadBlobMSBShort(image); |
302 | 34 | rla3_extra_info.matte_bits=ReadBlobMSBShort(image); |
303 | 34 | rla3_extra_info.auxiliary_type=ReadBlobMSBShort(image); |
304 | 34 | rla3_extra_info.auxiliary_bits=ReadBlobMSBShort(image); |
305 | 34 | (void) ReadBlob(image,32,(char *) rla3_extra_info.auxiliary); |
306 | 34 | NULLTerminateASCIIField(rla3_extra_info.auxiliary); |
307 | 34 | (void) ReadBlob(image,36,(char *) rla3_extra_info.space); |
308 | 34 | NULLTerminateASCIIField(rla3_extra_info.space); |
309 | 34 | rla3_extra_info.next=(long) ReadBlobMSBLong(image); |
310 | 34 | } |
311 | 700 | else |
312 | 700 | { |
313 | 700 | rlb_extra_info.filter_type=ReadBlobMSBShort(image); |
314 | 700 | rlb_extra_info.magic_number=ReadBlobMSBLong(image); |
315 | 700 | rlb_extra_info.lut_size=ReadBlobMSBLong(image); |
316 | 700 | rlb_extra_info.user_space_size=ReadBlobMSBLong(image); |
317 | 700 | rlb_extra_info.wf_space_size=ReadBlobMSBLong(image); |
318 | 700 | rlb_extra_info.lut_type=ReadBlobMSBShort(image); |
319 | 700 | rlb_extra_info.mix_type=ReadBlobMSBShort(image); |
320 | 700 | rlb_extra_info.encode_type=ReadBlobMSBShort(image); |
321 | 700 | rlb_extra_info.padding=ReadBlobMSBShort(image); |
322 | 700 | (void) ReadBlob(image,100,(char *) rlb_extra_info.space); |
323 | 700 | NULLTerminateASCIIField(rlb_extra_info.space); |
324 | 700 | } |
325 | 734 | if (EOFBlob(image)) |
326 | 623 | ThrowRLAReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
327 | | |
328 | | /* |
329 | | Verify revision. |
330 | | */ |
331 | | |
332 | | /* if (rla3_extra_info.revision != 0xFFFE) */ |
333 | | /* ThrowRLAReaderException(CorruptImageError,ImproperImageHeader,image); */ |
334 | | |
335 | | /* |
336 | | Verify dimensions. |
337 | | */ |
338 | 623 | if (image->logging) |
339 | 623 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
340 | 623 | "Active Window : Left=%d Right=%d Top=%d, Bottom=%d", |
341 | 623 | (int) rla_info.active_window.left, |
342 | 623 | (int) rla_info.active_window.right, |
343 | 623 | (int) rla_info.active_window.top, |
344 | 623 | (int) rla_info.active_window.bottom); |
345 | 623 | if ((((long) rla_info.active_window.right - rla_info.active_window.left) < 0) || |
346 | 622 | (((long) rla_info.active_window.top-rla_info.active_window.bottom) < 0)) |
347 | 620 | ThrowRLAReaderException(CorruptImageError,ImproperImageHeader,image); |
348 | | |
349 | 620 | if (image->logging) |
350 | 620 | { |
351 | 620 | const char |
352 | 620 | *storage_type = "Unknown"; |
353 | | |
354 | 620 | switch (rla_info.storage_type) |
355 | 620 | { |
356 | 600 | case 0: |
357 | 600 | storage_type = "INT8"; |
358 | 600 | break; |
359 | 0 | case 1: |
360 | 0 | storage_type = "INT16"; |
361 | 0 | break; |
362 | 1 | case 2: |
363 | 1 | storage_type = "INT32"; |
364 | 1 | break; |
365 | 1 | case 3: |
366 | 1 | storage_type = "FLOAT32"; |
367 | 1 | break; |
368 | 620 | } |
369 | 620 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
370 | 620 | "Storage Type : %s",storage_type); |
371 | | |
372 | 620 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
373 | 620 | "Color Channels : %u", (unsigned int) rla_info.number_channels); |
374 | 620 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
375 | 620 | "Matte Channels : %u", (unsigned int) rla_info.number_matte_channels); |
376 | 620 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
377 | 620 | "Aux Channels : %u", (unsigned int) rla_info.number_auxiliary_channels); |
378 | 620 | if (is_rla3) |
379 | 29 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
380 | 29 | "Format Revision: 0x%04X", rla_info.revision); |
381 | 591 | else |
382 | 591 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
383 | 591 | "Aux Mask : 0x%04X", rla_info.revision); |
384 | 620 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
385 | 620 | "Gamma : %.16s", rla_info.gamma); |
386 | 620 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
387 | 620 | "Red Primary : %.24s", rla_info.red_primary); |
388 | 620 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
389 | 620 | "Green Primary : %.24s", rla_info.green_primary); |
390 | 620 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
391 | 620 | "Blue Primary : %.24s", rla_info.blue_primary); |
392 | 620 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
393 | 620 | "White Point : %.24s", rla_info.white_point); |
394 | | |
395 | 620 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
396 | 620 | "Job Number : %u", (unsigned int) rla_info.job_number); |
397 | 620 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
398 | 620 | "Name : %.128s", rla_info.name); |
399 | 620 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
400 | 620 | "Description : %.128s", rla_info.description); |
401 | 620 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
402 | 620 | "Program : %.64s", rla_info.program); |
403 | 620 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
404 | 620 | "Machine : %.32s", rla_info.machine); |
405 | 620 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
406 | 620 | "User : %.32s", rla_info.user); |
407 | 620 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
408 | 620 | "Date : %.20s", rla_info.date); |
409 | 620 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
410 | 620 | "Aspect : %.128s", rla_info.aspect); |
411 | 620 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
412 | 620 | "Aspect Ratio : %.8s", rla_info.aspect_ratio); |
413 | 620 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
414 | 620 | "Colorspace : %.32s", rla_info.chan); |
415 | | |
416 | 620 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
417 | 620 | "Field : %u", (unsigned int) rla_info.field); |
418 | | |
419 | 620 | if (is_rla3) |
420 | 29 | { |
421 | 29 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
422 | 29 | "Time : %.12s", rla3_extra_info.time); |
423 | 29 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
424 | 29 | "Filter : %.32s", rla3_extra_info.filter); |
425 | | |
426 | 29 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
427 | 29 | "BitsPerChannel : %u", rla3_extra_info.bits_per_channel); |
428 | 29 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
429 | 29 | "MatteType : %u", rla3_extra_info.matte_type); |
430 | 29 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
431 | 29 | "MatteBits : %u", rla3_extra_info.matte_bits); |
432 | 29 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
433 | 29 | "AuxType : %u", rla3_extra_info.auxiliary_type); |
434 | 29 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
435 | 29 | "AuxBits : %u", rla3_extra_info.auxiliary_bits); |
436 | 29 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
437 | 29 | "AuxData : %.32s", rla3_extra_info.auxiliary); |
438 | 29 | } |
439 | 591 | else |
440 | 591 | { |
441 | 591 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
442 | 591 | "FilterType : %u", rlb_extra_info.filter_type); |
443 | 591 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
444 | 591 | "MagickNumber : %u", rlb_extra_info.magic_number); |
445 | 591 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
446 | 591 | "LUT Size : %u", rlb_extra_info.lut_size); |
447 | 591 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
448 | 591 | "User Space : %u", rlb_extra_info.user_space_size); |
449 | 591 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
450 | 591 | "WF Space : %u", rlb_extra_info.wf_space_size); |
451 | 591 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
452 | 591 | "LUT Type : %u", rlb_extra_info.lut_type); |
453 | 591 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
454 | 591 | "MIX Type : %u", rlb_extra_info.mix_type); |
455 | 591 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
456 | 591 | "Encode Type : %u", rlb_extra_info.encode_type); |
457 | 591 | } |
458 | 620 | } |
459 | | |
460 | 620 | if ((rla_info.storage_type != 0) || (rla_info.storage_type > 3)) |
461 | 600 | ThrowRLAReaderException(CorruptImageError,ImproperImageHeader,image); |
462 | | |
463 | 600 | if (rla_info.storage_type != 0) |
464 | 600 | ThrowRLAReaderException(CoderError,DataStorageTypeIsNotSupported,image); |
465 | | |
466 | 600 | if (LocaleNCompare(rla_info.chan,"rgb",3) != 0) |
467 | 581 | ThrowRLAReaderException(CoderError,ColorTypeNotSupported,image); |
468 | | |
469 | 581 | if (rla_info.number_channels > 3) |
470 | 15 | { |
471 | 15 | if (image->logging) |
472 | 15 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
473 | 15 | "Unsupported number of color channels: %u", |
474 | 15 | rla_info.number_channels); |
475 | 15 | ThrowRLAReaderException(CorruptImageError,UnsupportedNumberOfPlanes,image); |
476 | 0 | } |
477 | 566 | if (rla_info.number_matte_channels > 1) |
478 | 15 | { |
479 | 15 | if (image->logging) |
480 | 15 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
481 | 15 | "Unsupported number of matte channels: %u", |
482 | 15 | rla_info.number_matte_channels); |
483 | 15 | ThrowRLAReaderException(CorruptImageError,UnsupportedNumberOfPlanes,image); |
484 | 0 | } |
485 | | |
486 | | /* |
487 | | Initialize image structure. |
488 | | */ |
489 | 551 | image->matte=(rla_info.number_matte_channels != 0 ? MagickTrue: MagickFalse); |
490 | 551 | image->columns=rla_info.active_window.right-rla_info.active_window.left+1; |
491 | 551 | image->rows=rla_info.active_window.top-rla_info.active_window.bottom+1; |
492 | | |
493 | 551 | if (image->logging) |
494 | 551 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
495 | 551 | "Dimensions : %lux%lu",image->columns,image->rows); |
496 | | |
497 | 551 | if (image_info->ping) |
498 | 0 | { |
499 | 0 | CloseBlob(image); |
500 | 0 | return(image); |
501 | 0 | } |
502 | | |
503 | 551 | if (CheckImagePixelLimits(image, exception) != MagickPass) |
504 | 530 | ThrowRLAReaderException(ResourceLimitError,ImagePixelLimitExceeded,image); |
505 | | |
506 | 530 | number_channels=rla_info.number_channels+rla_info.number_matte_channels; |
507 | 530 | scanlines=MagickAllocateResourceLimitedArray(magick_uint32_t *,image->rows,sizeof(magick_uint32_t)); |
508 | 530 | if (scanlines == (magick_uint32_t *) NULL) |
509 | 530 | ThrowRLAReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
510 | 530 | if (*rla_info.description != '\0') |
511 | 267 | (void) SetImageAttribute(image,"comment",rla_info.description); |
512 | | /* |
513 | | Read offsets to each scanline data. |
514 | | */ |
515 | 530 | current_offset=TellBlob(image); |
516 | 58.4k | for (i=0; i < image->rows; i++) |
517 | 58.0k | { |
518 | 58.0k | scanlines[i]=(magick_uint32_t) ReadBlobMSBLong(image); |
519 | | #if 0 |
520 | | if (image->logging) |
521 | | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
522 | | "scanline[%ld] = %lu",i,(unsigned long) scanlines[i]); |
523 | | #endif |
524 | 58.0k | if ((magick_off_t) scanlines[i] > file_size) |
525 | 44 | { |
526 | 44 | if (image->logging) |
527 | 44 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
528 | 44 | "scanline[%ld] offset %lu is beyond end of file", |
529 | 44 | i,(unsigned long) scanlines[i]); |
530 | 44 | ThrowRLAReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
531 | 0 | } |
532 | 57.9k | if ((magick_off_t) scanlines[i] < current_offset) |
533 | 82 | { |
534 | 82 | if (image->logging) |
535 | 82 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
536 | 82 | "scanline[%ld] offset %lu is too small!", |
537 | 82 | i,(unsigned long) scanlines[i]); |
538 | 82 | ThrowRLAReaderException(CorruptImageError,ImproperImageHeader,image); |
539 | 0 | } |
540 | 57.9k | if ((i != 0) && (scanlines[i-1] == scanlines[i])) |
541 | 17.7k | { |
542 | 17.7k | if (image->logging) |
543 | 17.7k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
544 | 17.7k | "scanline[%ld] offset %lu is a duplicate!", |
545 | 17.7k | i,(unsigned long) scanlines[i]); |
546 | 17.7k | } |
547 | 57.9k | } |
548 | 404 | if (EOFBlob(image)) |
549 | 404 | ThrowRLAReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
550 | | /* |
551 | | Read image data. |
552 | | */ |
553 | 404 | x=0; |
554 | 37.3k | for (y=0; y < image->rows; y++) |
555 | 37.2k | { |
556 | 37.2k | if (SeekBlob(image,scanlines[image->rows-y-1],SEEK_SET) == -1) |
557 | 0 | { |
558 | 0 | if (image->logging) |
559 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
560 | 0 | "Failed seek to %lu", |
561 | 0 | (unsigned long) image->rows-y-1); |
562 | 0 | status=MagickFail; |
563 | 0 | break; |
564 | 0 | } |
565 | 143k | for (channel=0; channel < number_channels; channel++) |
566 | 106k | { |
567 | 106k | length=ReadBlobMSBShort(image); |
568 | 20.5M | while (length > 0) |
569 | 20.4M | { |
570 | 20.4M | if ((byte=ReadBlobByte(image)) == EOF) |
571 | 174 | { |
572 | 174 | status=MagickFail; |
573 | 174 | break; |
574 | 174 | } |
575 | 20.4M | runlength=byte; |
576 | 20.4M | if (byte > 127) |
577 | 136k | runlength=byte-256; |
578 | 20.4M | length--; |
579 | 20.4M | if (length == 0) |
580 | 28.6k | break; |
581 | 20.4M | if (runlength < 0) |
582 | 136k | { |
583 | 2.37M | while (runlength < 0) |
584 | 2.23M | { |
585 | 2.23M | if (x > image->rows*image->columns*number_channels) |
586 | 2.23M | ThrowRLAReaderException(CorruptImageError,UnableToRunlengthDecodeImage,image); |
587 | 2.23M | q=GetImagePixels(image,(long) (x % image->columns), |
588 | 2.23M | (long) (y % image->columns),1,1); |
589 | 2.23M | if (q == (PixelPacket *) NULL) |
590 | 0 | { |
591 | 0 | status=MagickFail; |
592 | 0 | break; |
593 | 0 | } |
594 | 2.23M | if ((byte=ReadBlobByte(image)) == EOF) |
595 | 87 | { |
596 | 87 | status=MagickFail; |
597 | 87 | break; |
598 | 87 | } |
599 | 2.23M | length--; |
600 | 2.23M | switch (channel) |
601 | 2.23M | { |
602 | 262k | case 0: |
603 | 262k | { |
604 | 262k | q->red=ScaleCharToQuantum(byte); |
605 | 262k | break; |
606 | 0 | } |
607 | 1.20M | case 1: |
608 | 1.20M | { |
609 | 1.20M | q->green=ScaleCharToQuantum(byte); |
610 | 1.20M | break; |
611 | 0 | } |
612 | 375k | case 2: |
613 | 375k | { |
614 | 375k | q->blue=ScaleCharToQuantum(byte); |
615 | 375k | break; |
616 | 0 | } |
617 | 391k | case 3: |
618 | 391k | { |
619 | 391k | q->opacity=(Quantum) (MaxRGB-ScaleCharToQuantum(byte)); |
620 | 391k | break; |
621 | 0 | } |
622 | 0 | default: |
623 | 0 | { |
624 | | /* Depth channel ? */ |
625 | 0 | break; |
626 | 0 | } |
627 | 2.23M | } |
628 | 2.23M | if (!SyncImagePixels(image)) |
629 | 0 | { |
630 | 0 | status=MagickFail; |
631 | 0 | break; |
632 | 0 | } |
633 | 2.23M | x++; |
634 | 2.23M | runlength++; |
635 | 2.23M | } |
636 | 136k | continue; |
637 | 136k | } |
638 | 20.3M | if ((byte=ReadBlobByte(image)) == EOF) |
639 | 67 | { |
640 | 67 | status=MagickFail; |
641 | 67 | break; |
642 | 67 | } |
643 | 20.3M | length--; |
644 | 20.3M | runlength++; |
645 | 20.3M | do |
646 | 72.3M | { |
647 | 72.3M | if (x > image->rows*image->columns*number_channels) |
648 | 72.3M | ThrowRLAReaderException(CorruptImageError,UnableToRunlengthDecodeImage,image); |
649 | 72.3M | q=GetImagePixels(image,(long) (x % image->columns), |
650 | 72.3M | (long) (y % image->columns),1,1); |
651 | 72.3M | if (q == (PixelPacket *) NULL) |
652 | 0 | { |
653 | 0 | status=MagickFail; |
654 | 0 | break; |
655 | 0 | } |
656 | 72.3M | switch (channel) |
657 | 72.3M | { |
658 | 2.87M | case 0: |
659 | 2.87M | { |
660 | 2.87M | q->red=ScaleCharToQuantum(byte); |
661 | 2.87M | break; |
662 | 0 | } |
663 | 53.0M | case 1: |
664 | 53.0M | { |
665 | 53.0M | q->green=ScaleCharToQuantum(byte); |
666 | 53.0M | break; |
667 | 0 | } |
668 | 9.23M | case 2: |
669 | 9.23M | { |
670 | 9.23M | q->blue=ScaleCharToQuantum(byte); |
671 | 9.23M | break; |
672 | 0 | } |
673 | 7.14M | case 3: |
674 | 7.14M | { |
675 | 7.14M | q->opacity=(Quantum) (MaxRGB-ScaleCharToQuantum(byte)); |
676 | 7.14M | break; |
677 | 0 | } |
678 | 0 | default: |
679 | 0 | { |
680 | | /* Depth channel ? */ |
681 | 0 | break; |
682 | 0 | } |
683 | 72.3M | } |
684 | 72.3M | if (!SyncImagePixels(image)) |
685 | 0 | { |
686 | 0 | status=MagickFail; |
687 | 0 | break; |
688 | 0 | } |
689 | 72.3M | x++; |
690 | 72.3M | runlength--; |
691 | 72.3M | } |
692 | 72.3M | while (runlength > 0); |
693 | | |
694 | 20.3M | if (MagickFail == status) |
695 | 0 | break; |
696 | 20.3M | } |
697 | 106k | if (MagickFail == status) |
698 | 260 | break; |
699 | 106k | } |
700 | 37.2k | if (QuantumTick(y,image->rows)) |
701 | 12.0k | if (!MagickMonitorFormatted(y,image->rows,exception,LoadImageText, |
702 | 12.0k | image->filename, |
703 | 12.0k | image->columns,image->rows)) |
704 | 0 | { |
705 | 0 | status=MagickFail; |
706 | 0 | break; |
707 | 0 | } |
708 | 37.2k | if (MagickFail == status) |
709 | 260 | break; |
710 | 37.2k | } |
711 | 385 | if (EOFBlob(image)) |
712 | 314 | ThrowRLAReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
713 | 71 | CloseBlob(image); |
714 | 71 | MagickFreeResourceLimitedMemory(magick_uint32_t *,scanlines); |
715 | 71 | StopTimer(&image->timer); |
716 | 71 | return(image); |
717 | 385 | } |
718 | | |
719 | | /* |
720 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
721 | | % % |
722 | | % % |
723 | | % % |
724 | | % R e g i s t e r R L A I m a g e % |
725 | | % % |
726 | | % % |
727 | | % % |
728 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
729 | | % |
730 | | % Method RegisterRLAImage adds attributes for the RLA image format to |
731 | | % the list of supported formats. The attributes include the image format |
732 | | % tag, a method to read and/or write the format, whether the format |
733 | | % supports the saving of more than one frame to the same file or blob, |
734 | | % whether the format supports native in-memory I/O, and a brief |
735 | | % description of the format. |
736 | | % |
737 | | % The format of the RegisterRLAImage method is: |
738 | | % |
739 | | % RegisterRLAImage(void) |
740 | | % |
741 | | */ |
742 | | ModuleExport void RegisterRLAImage(void) |
743 | 1 | { |
744 | 1 | MagickInfo |
745 | 1 | *entry; |
746 | | |
747 | 1 | entry=SetMagickInfo("RLA"); |
748 | 1 | entry->decoder=(DecoderHandler) ReadRLAImage; |
749 | 1 | entry->adjoin=False; |
750 | 1 | entry->description="Alias/Wavefront image"; |
751 | 1 | entry->seekable_stream=MagickTrue; |
752 | 1 | entry->module="RLA"; |
753 | 1 | entry->coder_class=UnstableCoderClass; |
754 | 1 | (void) RegisterMagickInfo(entry); |
755 | 1 | } |
756 | | |
757 | | /* |
758 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
759 | | % % |
760 | | % % |
761 | | % % |
762 | | % U n r e g i s t e r R L A I m a g e % |
763 | | % % |
764 | | % % |
765 | | % % |
766 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
767 | | % |
768 | | % Method UnregisterRLAImage removes format registrations made by the |
769 | | % RLA module from the list of supported formats. |
770 | | % |
771 | | % The format of the UnregisterRLAImage method is: |
772 | | % |
773 | | % UnregisterRLAImage(void) |
774 | | % |
775 | | */ |
776 | | ModuleExport void UnregisterRLAImage(void) |
777 | 0 | { |
778 | 0 | (void) UnregisterMagickInfo("RLA"); |
779 | 0 | } |