/src/imagemagick/coders/rla.c
Line | Count | Source |
1 | | /* |
2 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
3 | | % % |
4 | | % % |
5 | | % % |
6 | | % RRRR L AAA % |
7 | | % R R L A A % |
8 | | % RRRR L AAAAA % |
9 | | % R R L A A % |
10 | | % R R LLLLL A A % |
11 | | % % |
12 | | % % |
13 | | % Read Alias/Wavefront Image Format % |
14 | | % % |
15 | | % Software Design % |
16 | | % Cristy % |
17 | | % July 1992 % |
18 | | % % |
19 | | % % |
20 | | % Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization % |
21 | | % dedicated to making software imaging solutions freely available. % |
22 | | % % |
23 | | % You may not use this file except in compliance with the License. You may % |
24 | | % obtain a copy of the License at % |
25 | | % % |
26 | | % https://imagemagick.org/license/ % |
27 | | % % |
28 | | % Unless required by applicable law or agreed to in writing, software % |
29 | | % distributed under the License is distributed on an "AS IS" BASIS, % |
30 | | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % |
31 | | % See the License for the specific language governing permissions and % |
32 | | % limitations under the License. % |
33 | | % % |
34 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
35 | | % |
36 | | % |
37 | | */ |
38 | | |
39 | | /* |
40 | | Include declarations. |
41 | | */ |
42 | | #include "MagickCore/studio.h" |
43 | | #include "MagickCore/property.h" |
44 | | #include "MagickCore/blob.h" |
45 | | #include "MagickCore/blob-private.h" |
46 | | #include "MagickCore/cache.h" |
47 | | #include "MagickCore/exception.h" |
48 | | #include "MagickCore/exception-private.h" |
49 | | #include "MagickCore/image.h" |
50 | | #include "MagickCore/image-private.h" |
51 | | #include "MagickCore/list.h" |
52 | | #include "MagickCore/magick.h" |
53 | | #include "MagickCore/memory_.h" |
54 | | #include "MagickCore/monitor.h" |
55 | | #include "MagickCore/monitor-private.h" |
56 | | #include "MagickCore/pixel-accessor.h" |
57 | | #include "MagickCore/quantum-private.h" |
58 | | #include "MagickCore/static.h" |
59 | | #include "MagickCore/string_.h" |
60 | | #include "MagickCore/module.h" |
61 | | |
62 | | /* |
63 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
64 | | % % |
65 | | % % |
66 | | % % |
67 | | % R e a d R L A I m a g e % |
68 | | % % |
69 | | % % |
70 | | % % |
71 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
72 | | % |
73 | | % ReadRLAImage() reads a run-length encoded Wavefront RLA image file |
74 | | % and returns it. It allocates the memory necessary for the new Image |
75 | | % structure and returns a pointer to the new image. |
76 | | % |
77 | | % Note: This module was contributed by Lester Vecsey (master@internexus.net). |
78 | | % |
79 | | % The format of the ReadRLAImage method is: |
80 | | % |
81 | | % Image *ReadRLAImage(const ImageInfo *image_info,ExceptionInfo *exception) |
82 | | % |
83 | | % A description of each parameter follows: |
84 | | % |
85 | | % o image_info: the image info. |
86 | | % |
87 | | % o exception: return any errors or warnings in this structure. |
88 | | % |
89 | | */ |
90 | | static Image *ReadRLAImage(const ImageInfo *image_info,ExceptionInfo *exception) |
91 | 645 | { |
92 | 645 | typedef struct _WindowFrame |
93 | 645 | { |
94 | 645 | short |
95 | 645 | left, |
96 | 645 | right, |
97 | 645 | bottom, |
98 | 645 | top; |
99 | 645 | } WindowFrame; |
100 | | |
101 | 645 | typedef struct _RLAInfo |
102 | 645 | { |
103 | 645 | WindowFrame |
104 | 645 | window, |
105 | 645 | active_window; |
106 | | |
107 | 645 | short |
108 | 645 | frame, |
109 | 645 | storage_type, |
110 | 645 | number_channels, |
111 | 645 | number_matte_channels, |
112 | 645 | number_auxiliary_channels, |
113 | 645 | revision; |
114 | | |
115 | 645 | char |
116 | 645 | gamma[16+1], |
117 | 645 | red_primary[24+1], |
118 | 645 | green_primary[24+1], |
119 | 645 | blue_primary[24+1], |
120 | 645 | white_point[24+1]; |
121 | | |
122 | 645 | int |
123 | 645 | job_number; |
124 | | |
125 | 645 | char |
126 | 645 | name[128+1], |
127 | 645 | description[128+1], |
128 | 645 | program[64+1], |
129 | 645 | machine[32+1], |
130 | 645 | user[32+1], |
131 | 645 | date[20+1], |
132 | 645 | aspect[24+1], |
133 | 645 | aspect_ratio[8+1], |
134 | 645 | chan[32+1]; |
135 | | |
136 | 645 | short |
137 | 645 | field; |
138 | | |
139 | 645 | char |
140 | 645 | time[12], |
141 | 645 | filter[32]; |
142 | | |
143 | 645 | short |
144 | 645 | bits_per_channel, |
145 | 645 | matte_type, |
146 | 645 | matte_bits, |
147 | 645 | auxiliary_type, |
148 | 645 | auxiliary_bits; |
149 | | |
150 | 645 | char |
151 | 645 | auxiliary[32+1], |
152 | 645 | space[36+1]; |
153 | | |
154 | 645 | int |
155 | 645 | next; |
156 | 645 | } RLAInfo; |
157 | | |
158 | 645 | Image |
159 | 645 | *image; |
160 | | |
161 | 645 | int |
162 | 645 | channel, |
163 | 645 | length, |
164 | 645 | runlength; |
165 | | |
166 | 645 | MagickBooleanType |
167 | 645 | status; |
168 | | |
169 | 645 | MagickOffsetType |
170 | 645 | offset, |
171 | 645 | *scanlines; |
172 | | |
173 | 645 | ssize_t |
174 | 645 | i, |
175 | 645 | x; |
176 | | |
177 | 645 | Quantum |
178 | 645 | *q; |
179 | | |
180 | 645 | ssize_t |
181 | 645 | count, |
182 | 645 | y; |
183 | | |
184 | 645 | RLAInfo |
185 | 645 | rla_info; |
186 | | |
187 | 645 | unsigned char |
188 | 645 | byte; |
189 | | |
190 | | /* |
191 | | Open image file. |
192 | | */ |
193 | 645 | assert(image_info != (const ImageInfo *) NULL); |
194 | 645 | assert(image_info->signature == MagickCoreSignature); |
195 | 645 | assert(exception != (ExceptionInfo *) NULL); |
196 | 645 | assert(exception->signature == MagickCoreSignature); |
197 | 645 | if (IsEventLogging() != MagickFalse) |
198 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", |
199 | 0 | image_info->filename); |
200 | 645 | image=AcquireImage(image_info,exception); |
201 | 645 | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
202 | 645 | if (status == MagickFalse) |
203 | 0 | { |
204 | 0 | image=DestroyImageList(image); |
205 | 0 | return((Image *) NULL); |
206 | 0 | } |
207 | 645 | (void) memset(&rla_info,0,sizeof(rla_info)); |
208 | 645 | rla_info.window.left=(short) ReadBlobMSBShort(image); |
209 | 645 | rla_info.window.right=(short) ReadBlobMSBShort(image); |
210 | 645 | rla_info.window.bottom=(short) ReadBlobMSBShort(image); |
211 | 645 | rla_info.window.top=(short) ReadBlobMSBShort(image); |
212 | 645 | rla_info.active_window.left=(short) ReadBlobMSBShort(image); |
213 | 645 | rla_info.active_window.right=(short) ReadBlobMSBShort(image); |
214 | 645 | rla_info.active_window.bottom=(short) ReadBlobMSBShort(image); |
215 | 645 | rla_info.active_window.top=(short) ReadBlobMSBShort(image); |
216 | 645 | rla_info.frame=(short) ReadBlobMSBShort(image); |
217 | 645 | rla_info.storage_type=(short) ReadBlobMSBShort(image); |
218 | 645 | rla_info.number_channels=(short) ReadBlobMSBShort(image); |
219 | 645 | if (rla_info.number_channels < 0) |
220 | 640 | ThrowReaderException(CorruptImageError,"ImproperImageHeader"); |
221 | 640 | rla_info.number_matte_channels=(short) ReadBlobMSBShort(image); |
222 | 640 | if (rla_info.number_matte_channels < 0) |
223 | 637 | ThrowReaderException(CorruptImageError,"ImproperImageHeader"); |
224 | 637 | if ((rla_info.number_channels > 3) || (rla_info.number_matte_channels > 3)) |
225 | 597 | ThrowReaderException(CoderError,"Unsupported number of channels"); |
226 | 597 | if (rla_info.number_channels == 0) |
227 | 544 | rla_info.number_channels=3; |
228 | 597 | rla_info.number_channels+=rla_info.number_matte_channels; |
229 | 597 | rla_info.number_auxiliary_channels=(short) ReadBlobMSBShort(image); |
230 | 597 | rla_info.revision=(short) ReadBlobMSBShort(image); |
231 | 597 | (void) ReadBlob(image,16,(unsigned char *) rla_info.gamma); |
232 | 597 | (void) ReadBlob(image,24,(unsigned char *) rla_info.red_primary); |
233 | 597 | (void) ReadBlob(image,24,(unsigned char *) rla_info.green_primary); |
234 | 597 | (void) ReadBlob(image,24,(unsigned char *) rla_info.blue_primary); |
235 | 597 | (void) ReadBlob(image,24,(unsigned char *) rla_info.white_point); |
236 | 597 | rla_info.job_number=ReadBlobMSBSignedLong(image); |
237 | 597 | (void) ReadBlob(image,128,(unsigned char *) rla_info.name); |
238 | 597 | (void) ReadBlob(image,128,(unsigned char *) rla_info.description); |
239 | 597 | rla_info.description[127]='\0'; |
240 | 597 | (void) ReadBlob(image,64,(unsigned char *) rla_info.program); |
241 | 597 | (void) ReadBlob(image,32,(unsigned char *) rla_info.machine); |
242 | 597 | (void) ReadBlob(image,32,(unsigned char *) rla_info.user); |
243 | 597 | (void) ReadBlob(image,20,(unsigned char *) rla_info.date); |
244 | 597 | (void) ReadBlob(image,24,(unsigned char *) rla_info.aspect); |
245 | 597 | (void) ReadBlob(image,8,(unsigned char *) rla_info.aspect_ratio); |
246 | 597 | (void) ReadBlob(image,32,(unsigned char *) rla_info.chan); |
247 | 597 | rla_info.field=(short) ReadBlobMSBShort(image); |
248 | 597 | (void) ReadBlob(image,12,(unsigned char *) rla_info.time); |
249 | 597 | (void) ReadBlob(image,32,(unsigned char *) rla_info.filter); |
250 | 597 | rla_info.bits_per_channel=(short) ReadBlobMSBShort(image); |
251 | 597 | rla_info.matte_type=(short) ReadBlobMSBShort(image); |
252 | 597 | rla_info.matte_bits=(short) ReadBlobMSBShort(image); |
253 | 597 | rla_info.auxiliary_type=(short) ReadBlobMSBShort(image); |
254 | 597 | rla_info.auxiliary_bits=(short) ReadBlobMSBShort(image); |
255 | 597 | (void) ReadBlob(image,32,(unsigned char *) rla_info.auxiliary); |
256 | 597 | count=ReadBlob(image,36,(unsigned char *) rla_info.space); |
257 | 597 | if ((size_t) count != 36) |
258 | 438 | ThrowReaderException(CorruptImageError,"UnableToReadImageData"); |
259 | 438 | rla_info.next=ReadBlobMSBSignedLong(image); |
260 | | /* |
261 | | Initialize image structure. |
262 | | */ |
263 | 438 | image->alpha_trait=rla_info.number_matte_channels != 0 ? BlendPixelTrait : |
264 | 438 | UndefinedPixelTrait; |
265 | 438 | image->columns=(size_t) (rla_info.active_window.right- |
266 | 438 | rla_info.active_window.left+1); |
267 | 438 | image->rows=(size_t) (rla_info.active_window.top- |
268 | 438 | rla_info.active_window.bottom+1); |
269 | 438 | if (image_info->ping != MagickFalse) |
270 | 0 | { |
271 | 0 | (void) CloseBlob(image); |
272 | 0 | return(GetFirstImageInList(image)); |
273 | 0 | } |
274 | 438 | status=SetImageExtent(image,image->columns,image->rows,exception); |
275 | 438 | if (status == MagickFalse) |
276 | 86 | return(DestroyImageList(image)); |
277 | 352 | scanlines=(MagickOffsetType *) AcquireQuantumMemory(image->rows, |
278 | 352 | sizeof(*scanlines)); |
279 | 352 | if (scanlines == (MagickOffsetType *) NULL) |
280 | 352 | ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); |
281 | 352 | if (*rla_info.description != '\0') |
282 | 226 | (void) SetImageProperty(image,"comment",rla_info.description,exception); |
283 | | /* |
284 | | Read offsets to each scanline data. |
285 | | */ |
286 | 50.6k | for (i=0; i < (ssize_t) image->rows; i++) |
287 | 50.2k | scanlines[i]=(MagickOffsetType) ReadBlobMSBSignedLong(image); |
288 | 352 | if (EOFBlob(image) != MagickFalse) |
289 | 66 | { |
290 | 66 | scanlines=(MagickOffsetType *) RelinquishMagickMemory(scanlines); |
291 | 66 | ThrowReaderException(CorruptImageError,"ImproperImageHeader"); |
292 | 0 | } |
293 | | /* |
294 | | Read image data. |
295 | | */ |
296 | 5.53k | for (y=0; y < (ssize_t) image->rows; y++) |
297 | 5.47k | { |
298 | 5.47k | offset=SeekBlob(image,scanlines[(ssize_t) image->rows-y-1],SEEK_SET); |
299 | 5.47k | if (offset < 0) |
300 | 46 | { |
301 | 46 | scanlines=(MagickOffsetType *) RelinquishMagickMemory(scanlines); |
302 | 46 | ThrowReaderException(CorruptImageError,"ImproperImageHeader"); |
303 | 0 | } |
304 | 5.42k | x=0; |
305 | 27.1k | for (channel=0; channel < (int) rla_info.number_channels; channel++) |
306 | 21.6k | { |
307 | 21.6k | length=ReadBlobMSBSignedShort(image); |
308 | 1.59M | while (length > 0) |
309 | 1.58M | { |
310 | 1.58M | byte=(unsigned char) ReadBlobByte(image); |
311 | 1.58M | runlength=byte; |
312 | 1.58M | if (byte > 127) |
313 | 890k | runlength=byte-256; |
314 | 1.58M | length--; |
315 | 1.58M | if (length == 0) |
316 | 3.26k | break; |
317 | 1.57M | if (runlength < 0) |
318 | 889k | { |
319 | 2.93M | while (runlength < 0) |
320 | 2.04M | { |
321 | 2.04M | q=GetAuthenticPixels(image,x % (ssize_t) image->columns,y,1,1, |
322 | 2.04M | exception); |
323 | 2.04M | if (q == (Quantum *) NULL) |
324 | 0 | break; |
325 | 2.04M | byte=(unsigned char) ReadBlobByte(image); |
326 | 2.04M | length--; |
327 | 2.04M | switch (channel) |
328 | 2.04M | { |
329 | 719k | case 0: |
330 | 719k | { |
331 | 719k | SetPixelRed(image,ScaleCharToQuantum(byte),q); |
332 | 719k | break; |
333 | 0 | } |
334 | 525k | case 1: |
335 | 525k | { |
336 | 525k | SetPixelGreen(image,ScaleCharToQuantum(byte),q); |
337 | 525k | break; |
338 | 0 | } |
339 | 564k | case 2: |
340 | 564k | { |
341 | 564k | SetPixelBlue(image,ScaleCharToQuantum(byte),q); |
342 | 564k | break; |
343 | 0 | } |
344 | 184k | case 3: |
345 | 234k | default: |
346 | 234k | { |
347 | 234k | SetPixelAlpha(image,ScaleCharToQuantum(byte),q); |
348 | 234k | break; |
349 | 184k | } |
350 | 2.04M | } |
351 | 2.04M | if (SyncAuthenticPixels(image,exception) == MagickFalse) |
352 | 0 | break; |
353 | 2.04M | x++; |
354 | 2.04M | runlength++; |
355 | 2.04M | } |
356 | 889k | continue; |
357 | 889k | } |
358 | 688k | byte=(unsigned char) ReadBlobByte(image); |
359 | 688k | length--; |
360 | 688k | runlength++; |
361 | 688k | do |
362 | 8.62M | { |
363 | 8.62M | q=GetAuthenticPixels(image,x % (ssize_t) image->columns,y,1,1, |
364 | 8.62M | exception); |
365 | 8.62M | if (q == (Quantum *) NULL) |
366 | 0 | break; |
367 | 8.62M | switch (channel) |
368 | 8.62M | { |
369 | 2.24M | case 0: |
370 | 2.24M | { |
371 | 2.24M | SetPixelRed(image,ScaleCharToQuantum(byte),q); |
372 | 2.24M | break; |
373 | 0 | } |
374 | 3.14M | case 1: |
375 | 3.14M | { |
376 | 3.14M | SetPixelGreen(image,ScaleCharToQuantum(byte),q); |
377 | 3.14M | break; |
378 | 0 | } |
379 | 2.48M | case 2: |
380 | 2.48M | { |
381 | 2.48M | SetPixelBlue(image,ScaleCharToQuantum(byte),q); |
382 | 2.48M | break; |
383 | 0 | } |
384 | 644k | case 3: |
385 | 753k | default: |
386 | 753k | { |
387 | 753k | SetPixelAlpha(image,ScaleCharToQuantum(byte),q); |
388 | 753k | break; |
389 | 644k | } |
390 | 8.62M | } |
391 | 8.62M | if (SyncAuthenticPixels(image,exception) == MagickFalse) |
392 | 0 | break; |
393 | 8.62M | x++; |
394 | 8.62M | runlength--; |
395 | 8.62M | } |
396 | 8.62M | while (runlength > 0); |
397 | 688k | } |
398 | 21.6k | } |
399 | 5.42k | if ((x/(ssize_t) rla_info.number_channels) > (ssize_t) image->columns) |
400 | 104 | { |
401 | 104 | scanlines=(MagickOffsetType *) RelinquishMagickMemory(scanlines); |
402 | 104 | ThrowReaderException(CorruptImageError,"CorruptImage"); |
403 | 0 | } |
404 | 5.32k | if (EOFBlob(image) != MagickFalse) |
405 | 73 | break; |
406 | 5.24k | status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, |
407 | 5.24k | image->rows); |
408 | 5.24k | if (status == MagickFalse) |
409 | 0 | break; |
410 | 5.24k | } |
411 | 136 | scanlines=(MagickOffsetType *) RelinquishMagickMemory(scanlines); |
412 | 136 | if (EOFBlob(image) != MagickFalse) |
413 | 73 | ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", |
414 | 136 | image->filename); |
415 | 136 | if (CloseBlob(image) == MagickFalse) |
416 | 0 | status=MagickFalse; |
417 | 136 | if (status == MagickFalse) |
418 | 0 | return(DestroyImageList(image)); |
419 | 136 | return(GetFirstImageInList(image)); |
420 | 136 | } |
421 | | |
422 | | /* |
423 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
424 | | % % |
425 | | % % |
426 | | % % |
427 | | % R e g i s t e r R L A I m a g e % |
428 | | % % |
429 | | % % |
430 | | % % |
431 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
432 | | % |
433 | | % RegisterRLAImage() adds attributes for the RLA image format to |
434 | | % the list of supported formats. The attributes include the image format |
435 | | % tag, a method to read and/or write the format, whether the format |
436 | | % supports the saving of more than one frame to the same file or blob, |
437 | | % whether the format supports native in-memory I/O, and a brief |
438 | | % description of the format. |
439 | | % |
440 | | % The format of the RegisterRLAImage method is: |
441 | | % |
442 | | % size_t RegisterRLAImage(void) |
443 | | % |
444 | | */ |
445 | | ModuleExport size_t RegisterRLAImage(void) |
446 | 9 | { |
447 | 9 | MagickInfo |
448 | 9 | *entry; |
449 | | |
450 | 9 | entry=AcquireMagickInfo("RLA","RLA","Alias/Wavefront image"); |
451 | 9 | entry->decoder=(DecodeImageHandler *) ReadRLAImage; |
452 | 9 | entry->flags^=CoderAdjoinFlag; |
453 | 9 | entry->flags|=CoderDecoderSeekableStreamFlag; |
454 | 9 | (void) RegisterMagickInfo(entry); |
455 | 9 | return(MagickImageCoderSignature); |
456 | 9 | } |
457 | | |
458 | | /* |
459 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
460 | | % % |
461 | | % % |
462 | | % % |
463 | | % U n r e g i s t e r R L A I m a g e % |
464 | | % % |
465 | | % % |
466 | | % % |
467 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
468 | | % |
469 | | % UnregisterRLAImage() removes format registrations made by the |
470 | | % RLA module from the list of supported formats. |
471 | | % |
472 | | % The format of the UnregisterRLAImage method is: |
473 | | % |
474 | | % UnregisterRLAImage(void) |
475 | | % |
476 | | */ |
477 | | ModuleExport void UnregisterRLAImage(void) |
478 | 0 | { |
479 | 0 | (void) UnregisterMagickInfo("RLA"); |
480 | 0 | } |