/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.3k | #define NULLTerminateASCIIField(field) \ |
82 | 11.3k | { \ |
83 | 11.3k | field[sizeof(field)-1]='\0'; \ |
84 | 11.3k | } |
85 | | |
86 | 521 | #define ThrowRLAReaderException(code_,reason_,image_) \ |
87 | 675 | do { \ |
88 | 675 | MagickFreeResourceLimitedMemory(magick_uint32_t *,scanlines); \ |
89 | 675 | ThrowReaderException(code_,reason_,image_); \ |
90 | 0 | } while (0); |
91 | | static Image *ReadRLAImage(const ImageInfo *image_info,ExceptionInfo *exception) |
92 | 749 | { |
93 | 749 | typedef struct _WindowFrame |
94 | 749 | { |
95 | 749 | short |
96 | 749 | left, |
97 | 749 | right, |
98 | 749 | bottom, |
99 | 749 | top; |
100 | 749 | } WindowFrame; |
101 | | |
102 | 749 | typedef struct _RLAInfo |
103 | 749 | { |
104 | 749 | WindowFrame |
105 | 749 | window, |
106 | 749 | active_window; |
107 | | |
108 | 749 | magick_uint16_t |
109 | 749 | frame, |
110 | 749 | storage_type, |
111 | 749 | number_channels, |
112 | 749 | number_matte_channels, |
113 | 749 | number_auxiliary_channels, |
114 | 749 | revision; /* aux_mask in RLB */ |
115 | | |
116 | 749 | char |
117 | 749 | gamma[16], |
118 | 749 | red_primary[24], |
119 | 749 | green_primary[24], |
120 | 749 | blue_primary[24], |
121 | 749 | white_point[24]; |
122 | | |
123 | 749 | magick_uint32_t |
124 | 749 | job_number; |
125 | | |
126 | 749 | char |
127 | 749 | name[128], |
128 | 749 | description[128], |
129 | 749 | program[64], |
130 | 749 | machine[32], |
131 | 749 | user[32], |
132 | 749 | date[20], |
133 | 749 | aspect[24], |
134 | 749 | aspect_ratio[8], |
135 | 749 | chan[32]; |
136 | | |
137 | 749 | magick_uint16_t |
138 | 749 | field; |
139 | | |
140 | | /* RLB varies after this point */ |
141 | | |
142 | 749 | } RLAInfo; |
143 | | |
144 | 749 | typedef struct _RLA3ExtraInfo |
145 | 749 | { |
146 | 749 | char |
147 | 749 | time[12], |
148 | 749 | filter[32]; |
149 | | |
150 | 749 | magick_uint16_t |
151 | 749 | bits_per_channel, |
152 | 749 | matte_type, |
153 | 749 | matte_bits, |
154 | 749 | auxiliary_type, |
155 | 749 | auxiliary_bits; |
156 | | |
157 | 749 | char |
158 | 749 | auxiliary[32], |
159 | 749 | space[36]; |
160 | | |
161 | 749 | magick_uint32_t |
162 | 749 | next; |
163 | 749 | } RLA3ExtraInfo; |
164 | | |
165 | 749 | typedef struct _RLBExtraInfo |
166 | 749 | { |
167 | 749 | magick_uint16_t |
168 | 749 | filter_type; |
169 | | |
170 | 749 | magick_uint32_t |
171 | 749 | magic_number, |
172 | 749 | lut_size, |
173 | 749 | user_space_size, |
174 | 749 | wf_space_size; |
175 | | |
176 | 749 | magick_uint16_t |
177 | 749 | lut_type, |
178 | 749 | mix_type, |
179 | 749 | encode_type, |
180 | 749 | padding; |
181 | | |
182 | 749 | char |
183 | 749 | space[100]; |
184 | 749 | } RLBExtraInfo; |
185 | | |
186 | 749 | Image |
187 | 749 | *image; |
188 | | |
189 | 749 | int |
190 | 749 | channel, |
191 | 749 | length, |
192 | 749 | number_channels, |
193 | 749 | runlength; |
194 | | |
195 | 749 | unsigned long |
196 | 749 | y; |
197 | | |
198 | 749 | magick_uint32_t |
199 | 749 | *scanlines=0; |
200 | | |
201 | 749 | register unsigned long |
202 | 749 | i, |
203 | 749 | x; |
204 | | |
205 | 749 | register PixelPacket |
206 | 749 | *q; |
207 | | |
208 | 749 | RLAInfo |
209 | 749 | rla_info; |
210 | | |
211 | 749 | RLA3ExtraInfo |
212 | 749 | rla3_extra_info; |
213 | | |
214 | 749 | RLBExtraInfo |
215 | 749 | rlb_extra_info; |
216 | | |
217 | 749 | MagickBool |
218 | 749 | is_rla3; |
219 | | |
220 | 749 | int |
221 | 749 | byte; |
222 | | |
223 | 749 | MagickPassFail |
224 | 749 | status; |
225 | | |
226 | 749 | magick_off_t |
227 | 749 | current_offset, |
228 | 749 | file_size; |
229 | | |
230 | | /* |
231 | | Open image file. |
232 | | */ |
233 | 749 | assert(image_info != (const ImageInfo *) NULL); |
234 | 749 | assert(image_info->signature == MagickSignature); |
235 | 749 | assert(exception != (ExceptionInfo *) NULL); |
236 | 749 | assert(exception->signature == MagickSignature); |
237 | 749 | image=AllocateImage(image_info); |
238 | 749 | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
239 | 749 | if (status == MagickFail) |
240 | 749 | ThrowReaderException(FileOpenError,UnableToOpenFile,image); |
241 | 749 | file_size=GetBlobSize(image); |
242 | 749 | is_rla3=MagickFalse; |
243 | 749 | memset(&rla_info,0,sizeof(rla_info)); |
244 | 749 | memset(&rla3_extra_info,0,sizeof(rla3_extra_info)); |
245 | 749 | memset(&rlb_extra_info,0,sizeof(rlb_extra_info)); |
246 | 749 | rla_info.window.left=ReadBlobMSBShort(image); |
247 | 749 | rla_info.window.right=ReadBlobMSBShort(image); |
248 | 749 | rla_info.window.bottom=ReadBlobMSBShort(image); |
249 | 749 | rla_info.window.top=ReadBlobMSBShort(image); |
250 | 749 | rla_info.active_window.left=ReadBlobMSBShort(image); |
251 | 749 | rla_info.active_window.right=ReadBlobMSBShort(image); |
252 | 749 | rla_info.active_window.bottom=ReadBlobMSBShort(image); |
253 | 749 | rla_info.active_window.top=ReadBlobMSBShort(image); |
254 | 749 | rla_info.frame=ReadBlobMSBShort(image); |
255 | 749 | rla_info.storage_type=ReadBlobMSBShort(image); |
256 | 749 | rla_info.number_channels=ReadBlobMSBShort(image); |
257 | 749 | rla_info.number_matte_channels=ReadBlobMSBShort(image); |
258 | 749 | if (rla_info.number_channels == 0) |
259 | 476 | rla_info.number_channels=3; |
260 | 749 | rla_info.number_auxiliary_channels=ReadBlobMSBShort(image); |
261 | 749 | rla_info.revision=ReadBlobMSBShort(image); |
262 | 749 | if (rla_info.revision == 0xFFFE) |
263 | 41 | is_rla3=MagickTrue; |
264 | 749 | (void) ReadBlob(image,16,(char *) rla_info.gamma); |
265 | 749 | NULLTerminateASCIIField(rla_info.gamma); |
266 | 749 | (void) ReadBlob(image,24,(char *) rla_info.red_primary); |
267 | 749 | NULLTerminateASCIIField(rla_info.red_primary); |
268 | 749 | (void) ReadBlob(image,24,(char *) rla_info.green_primary); |
269 | 749 | NULLTerminateASCIIField(rla_info.green_primary) |
270 | 749 | (void) ReadBlob(image,24,(char *) rla_info.blue_primary); |
271 | 749 | NULLTerminateASCIIField(rla_info.blue_primary); |
272 | 749 | (void) ReadBlob(image,24,(char *) rla_info.white_point); |
273 | 749 | NULLTerminateASCIIField(rla_info.white_point); |
274 | 749 | rla_info.job_number=(long) ReadBlobMSBLong(image); |
275 | 749 | (void) ReadBlob(image,128,(char *) rla_info.name); |
276 | 749 | NULLTerminateASCIIField(rla_info.name); |
277 | 749 | (void) ReadBlob(image,128,(char *) rla_info.description); |
278 | 749 | NULLTerminateASCIIField(rla_info.description); |
279 | 749 | (void) ReadBlob(image,64,(char *) rla_info.program); |
280 | 749 | NULLTerminateASCIIField(rla_info.program); |
281 | 749 | (void) ReadBlob(image,32,(char *) rla_info.machine); |
282 | 749 | NULLTerminateASCIIField(rla_info.machine); |
283 | 749 | (void) ReadBlob(image,32,(char *) rla_info.user); |
284 | 749 | NULLTerminateASCIIField(rla_info.user); |
285 | 749 | (void) ReadBlob(image,20,(char *) rla_info.date); |
286 | 749 | NULLTerminateASCIIField(rla_info.date); |
287 | 749 | (void) ReadBlob(image,24,(char *) rla_info.aspect); |
288 | 749 | NULLTerminateASCIIField(rla_info.aspect); |
289 | 749 | (void) ReadBlob(image,8,(char *) rla_info.aspect_ratio); |
290 | 749 | NULLTerminateASCIIField(rla_info.aspect_ratio); |
291 | 749 | (void) ReadBlob(image,32,(char *) rla_info.chan); |
292 | 749 | NULLTerminateASCIIField(rla_info.chan); |
293 | 749 | rla_info.field=ReadBlobMSBShort(image); |
294 | 749 | if (is_rla3) |
295 | 41 | { |
296 | 41 | (void) ReadBlob(image,12,(char *) rla3_extra_info.time); |
297 | 41 | NULLTerminateASCIIField(rla3_extra_info.time); |
298 | 41 | (void) ReadBlob(image,32,(char *) rla3_extra_info.filter); |
299 | 41 | NULLTerminateASCIIField(rla3_extra_info.filter); |
300 | 41 | rla3_extra_info.bits_per_channel=ReadBlobMSBShort(image); |
301 | 41 | rla3_extra_info.matte_type=ReadBlobMSBShort(image); |
302 | 41 | rla3_extra_info.matte_bits=ReadBlobMSBShort(image); |
303 | 41 | rla3_extra_info.auxiliary_type=ReadBlobMSBShort(image); |
304 | 41 | rla3_extra_info.auxiliary_bits=ReadBlobMSBShort(image); |
305 | 41 | (void) ReadBlob(image,32,(char *) rla3_extra_info.auxiliary); |
306 | 41 | NULLTerminateASCIIField(rla3_extra_info.auxiliary); |
307 | 41 | (void) ReadBlob(image,36,(char *) rla3_extra_info.space); |
308 | 41 | NULLTerminateASCIIField(rla3_extra_info.space); |
309 | 41 | rla3_extra_info.next=(long) ReadBlobMSBLong(image); |
310 | 41 | } |
311 | 708 | else |
312 | 708 | { |
313 | 708 | rlb_extra_info.filter_type=ReadBlobMSBShort(image); |
314 | 708 | rlb_extra_info.magic_number=ReadBlobMSBLong(image); |
315 | 708 | rlb_extra_info.lut_size=ReadBlobMSBLong(image); |
316 | 708 | rlb_extra_info.user_space_size=ReadBlobMSBLong(image); |
317 | 708 | rlb_extra_info.wf_space_size=ReadBlobMSBLong(image); |
318 | 708 | rlb_extra_info.lut_type=ReadBlobMSBShort(image); |
319 | 708 | rlb_extra_info.mix_type=ReadBlobMSBShort(image); |
320 | 708 | rlb_extra_info.encode_type=ReadBlobMSBShort(image); |
321 | 708 | rlb_extra_info.padding=ReadBlobMSBShort(image); |
322 | 708 | (void) ReadBlob(image,100,(char *) rlb_extra_info.space); |
323 | 708 | NULLTerminateASCIIField(rlb_extra_info.space); |
324 | 708 | } |
325 | 749 | if (EOFBlob(image)) |
326 | 629 | 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 | 629 | if (image->logging) |
339 | 629 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
340 | 629 | "Active Window : Left=%d Right=%d Top=%d, Bottom=%d", |
341 | 629 | (int) rla_info.active_window.left, |
342 | 629 | (int) rla_info.active_window.right, |
343 | 629 | (int) rla_info.active_window.top, |
344 | 629 | (int) rla_info.active_window.bottom); |
345 | 629 | if ((((long) rla_info.active_window.right - rla_info.active_window.left) < 0) || |
346 | 628 | (((long) rla_info.active_window.top-rla_info.active_window.bottom) < 0)) |
347 | 625 | ThrowRLAReaderException(CorruptImageError,ImproperImageHeader,image); |
348 | | |
349 | 625 | if (image->logging) |
350 | 625 | { |
351 | 625 | const char |
352 | 625 | *storage_type = "Unknown"; |
353 | | |
354 | 625 | switch (rla_info.storage_type) |
355 | 625 | { |
356 | 605 | case 0: |
357 | 605 | storage_type = "INT8"; |
358 | 605 | break; |
359 | 1 | case 1: |
360 | 1 | storage_type = "INT16"; |
361 | 1 | break; |
362 | 0 | case 2: |
363 | 0 | storage_type = "INT32"; |
364 | 0 | break; |
365 | 1 | case 3: |
366 | 1 | storage_type = "FLOAT32"; |
367 | 1 | break; |
368 | 625 | } |
369 | 625 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
370 | 625 | "Storage Type : %s",storage_type); |
371 | | |
372 | 625 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
373 | 625 | "Color Channels : %u", (unsigned int) rla_info.number_channels); |
374 | 625 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
375 | 625 | "Matte Channels : %u", (unsigned int) rla_info.number_matte_channels); |
376 | 625 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
377 | 625 | "Aux Channels : %u", (unsigned int) rla_info.number_auxiliary_channels); |
378 | 625 | if (is_rla3) |
379 | 35 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
380 | 35 | "Format Revision: 0x%04X", rla_info.revision); |
381 | 590 | else |
382 | 590 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
383 | 590 | "Aux Mask : 0x%04X", rla_info.revision); |
384 | 625 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
385 | 625 | "Gamma : %.16s", rla_info.gamma); |
386 | 625 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
387 | 625 | "Red Primary : %.24s", rla_info.red_primary); |
388 | 625 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
389 | 625 | "Green Primary : %.24s", rla_info.green_primary); |
390 | 625 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
391 | 625 | "Blue Primary : %.24s", rla_info.blue_primary); |
392 | 625 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
393 | 625 | "White Point : %.24s", rla_info.white_point); |
394 | | |
395 | 625 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
396 | 625 | "Job Number : %u", (unsigned int) rla_info.job_number); |
397 | 625 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
398 | 625 | "Name : %.128s", rla_info.name); |
399 | 625 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
400 | 625 | "Description : %.128s", rla_info.description); |
401 | 625 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
402 | 625 | "Program : %.64s", rla_info.program); |
403 | 625 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
404 | 625 | "Machine : %.32s", rla_info.machine); |
405 | 625 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
406 | 625 | "User : %.32s", rla_info.user); |
407 | 625 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
408 | 625 | "Date : %.20s", rla_info.date); |
409 | 625 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
410 | 625 | "Aspect : %.128s", rla_info.aspect); |
411 | 625 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
412 | 625 | "Aspect Ratio : %.8s", rla_info.aspect_ratio); |
413 | 625 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
414 | 625 | "Colorspace : %.32s", rla_info.chan); |
415 | | |
416 | 625 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
417 | 625 | "Field : %u", (unsigned int) rla_info.field); |
418 | | |
419 | 625 | if (is_rla3) |
420 | 35 | { |
421 | 35 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
422 | 35 | "Time : %.12s", rla3_extra_info.time); |
423 | 35 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
424 | 35 | "Filter : %.32s", rla3_extra_info.filter); |
425 | | |
426 | 35 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
427 | 35 | "BitsPerChannel : %u", rla3_extra_info.bits_per_channel); |
428 | 35 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
429 | 35 | "MatteType : %u", rla3_extra_info.matte_type); |
430 | 35 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
431 | 35 | "MatteBits : %u", rla3_extra_info.matte_bits); |
432 | 35 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
433 | 35 | "AuxType : %u", rla3_extra_info.auxiliary_type); |
434 | 35 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
435 | 35 | "AuxBits : %u", rla3_extra_info.auxiliary_bits); |
436 | 35 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
437 | 35 | "AuxData : %.32s", rla3_extra_info.auxiliary); |
438 | 35 | } |
439 | 590 | else |
440 | 590 | { |
441 | 590 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
442 | 590 | "FilterType : %u", rlb_extra_info.filter_type); |
443 | 590 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
444 | 590 | "MagickNumber : %u", rlb_extra_info.magic_number); |
445 | 590 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
446 | 590 | "LUT Size : %u", rlb_extra_info.lut_size); |
447 | 590 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
448 | 590 | "User Space : %u", rlb_extra_info.user_space_size); |
449 | 590 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
450 | 590 | "WF Space : %u", rlb_extra_info.wf_space_size); |
451 | 590 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
452 | 590 | "LUT Type : %u", rlb_extra_info.lut_type); |
453 | 590 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
454 | 590 | "MIX Type : %u", rlb_extra_info.mix_type); |
455 | 590 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
456 | 590 | "Encode Type : %u", rlb_extra_info.encode_type); |
457 | 590 | } |
458 | 625 | } |
459 | | |
460 | 625 | if ((rla_info.storage_type != 0) || (rla_info.storage_type > 3)) |
461 | 605 | ThrowRLAReaderException(CorruptImageError,ImproperImageHeader,image); |
462 | | |
463 | 605 | if (rla_info.storage_type != 0) |
464 | 605 | ThrowRLAReaderException(CoderError,DataStorageTypeIsNotSupported,image); |
465 | | |
466 | 605 | if (LocaleNCompare(rla_info.chan,"rgb",3) != 0) |
467 | 586 | ThrowRLAReaderException(CoderError,ColorTypeNotSupported,image); |
468 | | |
469 | 586 | 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 | 571 | 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 | 556 | image->matte=(rla_info.number_matte_channels != 0 ? MagickTrue: MagickFalse); |
490 | 556 | image->columns=rla_info.active_window.right-rla_info.active_window.left+1; |
491 | 556 | image->rows=rla_info.active_window.top-rla_info.active_window.bottom+1; |
492 | | |
493 | 556 | if (image->logging) |
494 | 556 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
495 | 556 | "Dimensions : %lux%lu",image->columns,image->rows); |
496 | | |
497 | 556 | if (image_info->ping) |
498 | 0 | { |
499 | 0 | CloseBlob(image); |
500 | 0 | return(image); |
501 | 0 | } |
502 | | |
503 | 556 | if (CheckImagePixelLimits(image, exception) != MagickPass) |
504 | 535 | ThrowRLAReaderException(ResourceLimitError,ImagePixelLimitExceeded,image); |
505 | | |
506 | 535 | number_channels=rla_info.number_channels+rla_info.number_matte_channels; |
507 | 535 | scanlines=MagickAllocateResourceLimitedArray(magick_uint32_t *,image->rows,sizeof(magick_uint32_t)); |
508 | 535 | if (scanlines == (magick_uint32_t *) NULL) |
509 | 535 | ThrowRLAReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
510 | 535 | if (*rla_info.description != '\0') |
511 | 275 | (void) SetImageAttribute(image,"comment",rla_info.description); |
512 | | /* |
513 | | Read offsets to each scanline data. |
514 | | */ |
515 | 535 | current_offset=TellBlob(image); |
516 | 64.2k | for (i=0; i < image->rows; i++) |
517 | 63.8k | { |
518 | 63.8k | 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 | 63.8k | if ((magick_off_t) scanlines[i] > file_size) |
525 | 37 | { |
526 | 37 | if (image->logging) |
527 | 37 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
528 | 37 | "scanline[%ld] offset %lu is beyond end of file", |
529 | 37 | i,(unsigned long) scanlines[i]); |
530 | 37 | ThrowRLAReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
531 | 0 | } |
532 | 63.7k | if ((magick_off_t) scanlines[i] < current_offset) |
533 | 87 | { |
534 | 87 | if (image->logging) |
535 | 87 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
536 | 87 | "scanline[%ld] offset %lu is too small!", |
537 | 87 | i,(unsigned long) scanlines[i]); |
538 | 87 | ThrowRLAReaderException(CorruptImageError,ImproperImageHeader,image); |
539 | 0 | } |
540 | 63.6k | if ((i != 0) && (scanlines[i-1] == scanlines[i])) |
541 | 18.8k | { |
542 | 18.8k | if (image->logging) |
543 | 18.8k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
544 | 18.8k | "scanline[%ld] offset %lu is a duplicate!", |
545 | 18.8k | i,(unsigned long) scanlines[i]); |
546 | 18.8k | } |
547 | 63.6k | } |
548 | 411 | if (EOFBlob(image)) |
549 | 411 | ThrowRLAReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
550 | | /* |
551 | | Read image data. |
552 | | */ |
553 | 411 | x=0; |
554 | 43.5k | for (y=0; y < image->rows; y++) |
555 | 43.4k | { |
556 | 43.4k | 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 | 170k | for (channel=0; channel < number_channels; channel++) |
566 | 127k | { |
567 | 127k | length=ReadBlobMSBShort(image); |
568 | 24.4M | while (length > 0) |
569 | 24.3M | { |
570 | 24.3M | if ((byte=ReadBlobByte(image)) == EOF) |
571 | 179 | { |
572 | 179 | status=MagickFail; |
573 | 179 | break; |
574 | 179 | } |
575 | 24.3M | runlength=byte; |
576 | 24.3M | if (byte > 127) |
577 | 163k | runlength=byte-256; |
578 | 24.3M | length--; |
579 | 24.3M | if (length == 0) |
580 | 32.3k | break; |
581 | 24.3M | if (runlength < 0) |
582 | 163k | { |
583 | 3.20M | while (runlength < 0) |
584 | 3.03M | { |
585 | 3.03M | if (x > image->rows*image->columns*number_channels) |
586 | 3.03M | ThrowRLAReaderException(CorruptImageError,UnableToRunlengthDecodeImage,image); |
587 | 3.03M | q=GetImagePixels(image,(long) (x % image->columns), |
588 | 3.03M | (long) (y % image->columns),1,1); |
589 | 3.03M | if (q == (PixelPacket *) NULL) |
590 | 0 | { |
591 | 0 | status=MagickFail; |
592 | 0 | break; |
593 | 0 | } |
594 | 3.03M | if ((byte=ReadBlobByte(image)) == EOF) |
595 | 86 | { |
596 | 86 | status=MagickFail; |
597 | 86 | break; |
598 | 86 | } |
599 | 3.03M | length--; |
600 | 3.03M | switch (channel) |
601 | 3.03M | { |
602 | 192k | case 0: |
603 | 192k | { |
604 | 192k | q->red=ScaleCharToQuantum(byte); |
605 | 192k | break; |
606 | 0 | } |
607 | 1.67M | case 1: |
608 | 1.67M | { |
609 | 1.67M | q->green=ScaleCharToQuantum(byte); |
610 | 1.67M | break; |
611 | 0 | } |
612 | 392k | case 2: |
613 | 392k | { |
614 | 392k | q->blue=ScaleCharToQuantum(byte); |
615 | 392k | break; |
616 | 0 | } |
617 | 779k | case 3: |
618 | 779k | { |
619 | 779k | q->opacity=(Quantum) (MaxRGB-ScaleCharToQuantum(byte)); |
620 | 779k | break; |
621 | 0 | } |
622 | 0 | default: |
623 | 0 | { |
624 | | /* Depth channel ? */ |
625 | 0 | break; |
626 | 0 | } |
627 | 3.03M | } |
628 | 3.03M | if (!SyncImagePixels(image)) |
629 | 0 | { |
630 | 0 | status=MagickFail; |
631 | 0 | break; |
632 | 0 | } |
633 | 3.03M | x++; |
634 | 3.03M | runlength++; |
635 | 3.03M | } |
636 | 163k | continue; |
637 | 163k | } |
638 | 24.1M | if ((byte=ReadBlobByte(image)) == EOF) |
639 | 67 | { |
640 | 67 | status=MagickFail; |
641 | 67 | break; |
642 | 67 | } |
643 | 24.1M | length--; |
644 | 24.1M | runlength++; |
645 | 24.1M | do |
646 | 84.9M | { |
647 | 84.9M | if (x > image->rows*image->columns*number_channels) |
648 | 84.9M | ThrowRLAReaderException(CorruptImageError,UnableToRunlengthDecodeImage,image); |
649 | 84.9M | q=GetImagePixels(image,(long) (x % image->columns), |
650 | 84.9M | (long) (y % image->columns),1,1); |
651 | 84.9M | if (q == (PixelPacket *) NULL) |
652 | 0 | { |
653 | 0 | status=MagickFail; |
654 | 0 | break; |
655 | 0 | } |
656 | 84.9M | switch (channel) |
657 | 84.9M | { |
658 | 2.12M | case 0: |
659 | 2.12M | { |
660 | 2.12M | q->red=ScaleCharToQuantum(byte); |
661 | 2.12M | break; |
662 | 0 | } |
663 | 63.2M | case 1: |
664 | 63.2M | { |
665 | 63.2M | q->green=ScaleCharToQuantum(byte); |
666 | 63.2M | break; |
667 | 0 | } |
668 | 9.99M | case 2: |
669 | 9.99M | { |
670 | 9.99M | q->blue=ScaleCharToQuantum(byte); |
671 | 9.99M | break; |
672 | 0 | } |
673 | 9.53M | case 3: |
674 | 9.53M | { |
675 | 9.53M | q->opacity=(Quantum) (MaxRGB-ScaleCharToQuantum(byte)); |
676 | 9.53M | break; |
677 | 0 | } |
678 | 0 | default: |
679 | 0 | { |
680 | | /* Depth channel ? */ |
681 | 0 | break; |
682 | 0 | } |
683 | 84.9M | } |
684 | 84.9M | if (!SyncImagePixels(image)) |
685 | 0 | { |
686 | 0 | status=MagickFail; |
687 | 0 | break; |
688 | 0 | } |
689 | 84.9M | x++; |
690 | 84.9M | runlength--; |
691 | 84.9M | } |
692 | 84.9M | while (runlength > 0); |
693 | | |
694 | 24.1M | if (MagickFail == status) |
695 | 0 | break; |
696 | 24.1M | } |
697 | 127k | if (MagickFail == status) |
698 | 266 | break; |
699 | 127k | } |
700 | 43.4k | if (QuantumTick(y,image->rows)) |
701 | 13.8k | if (!MagickMonitorFormatted(y,image->rows,exception,LoadImageText, |
702 | 13.8k | image->filename, |
703 | 13.8k | image->columns,image->rows)) |
704 | 0 | { |
705 | 0 | status=MagickFail; |
706 | 0 | break; |
707 | 0 | } |
708 | 43.4k | if (MagickFail == status) |
709 | 266 | break; |
710 | 43.4k | } |
711 | 395 | if (EOFBlob(image)) |
712 | 321 | ThrowRLAReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
713 | 74 | CloseBlob(image); |
714 | 74 | MagickFreeResourceLimitedMemory(magick_uint32_t *,scanlines); |
715 | 74 | StopTimer(&image->timer); |
716 | 74 | return(image); |
717 | 395 | } |
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 | } |