/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/script/license.php % |
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 | 679 | { |
92 | 679 | typedef struct _WindowFrame |
93 | 679 | { |
94 | 679 | short |
95 | 679 | left, |
96 | 679 | right, |
97 | 679 | bottom, |
98 | 679 | top; |
99 | 679 | } WindowFrame; |
100 | | |
101 | 679 | typedef struct _RLAInfo |
102 | 679 | { |
103 | 679 | WindowFrame |
104 | 679 | window, |
105 | 679 | active_window; |
106 | | |
107 | 679 | short |
108 | 679 | frame, |
109 | 679 | storage_type, |
110 | 679 | number_channels, |
111 | 679 | number_matte_channels, |
112 | 679 | number_auxiliary_channels, |
113 | 679 | revision; |
114 | | |
115 | 679 | char |
116 | 679 | gamma[16+1], |
117 | 679 | red_primary[24+1], |
118 | 679 | green_primary[24+1], |
119 | 679 | blue_primary[24+1], |
120 | 679 | white_point[24+1]; |
121 | | |
122 | 679 | int |
123 | 679 | job_number; |
124 | | |
125 | 679 | char |
126 | 679 | name[128+1], |
127 | 679 | description[128+1], |
128 | 679 | program[64+1], |
129 | 679 | machine[32+1], |
130 | 679 | user[32+1], |
131 | 679 | date[20+1], |
132 | 679 | aspect[24+1], |
133 | 679 | aspect_ratio[8+1], |
134 | 679 | chan[32+1]; |
135 | | |
136 | 679 | short |
137 | 679 | field; |
138 | | |
139 | 679 | char |
140 | 679 | time[12], |
141 | 679 | filter[32]; |
142 | | |
143 | 679 | short |
144 | 679 | bits_per_channel, |
145 | 679 | matte_type, |
146 | 679 | matte_bits, |
147 | 679 | auxiliary_type, |
148 | 679 | auxiliary_bits; |
149 | | |
150 | 679 | char |
151 | 679 | auxiliary[32+1], |
152 | 679 | space[36+1]; |
153 | | |
154 | 679 | int |
155 | 679 | next; |
156 | 679 | } RLAInfo; |
157 | | |
158 | 679 | Image |
159 | 679 | *image; |
160 | | |
161 | 679 | int |
162 | 679 | channel, |
163 | 679 | length, |
164 | 679 | runlength; |
165 | | |
166 | 679 | MagickBooleanType |
167 | 679 | status; |
168 | | |
169 | 679 | MagickOffsetType |
170 | 679 | offset, |
171 | 679 | *scanlines; |
172 | | |
173 | 679 | ssize_t |
174 | 679 | i, |
175 | 679 | x; |
176 | | |
177 | 679 | Quantum |
178 | 679 | *q; |
179 | | |
180 | 679 | ssize_t |
181 | 679 | count, |
182 | 679 | y; |
183 | | |
184 | 679 | RLAInfo |
185 | 679 | rla_info; |
186 | | |
187 | 679 | unsigned char |
188 | 679 | byte; |
189 | | |
190 | | /* |
191 | | Open image file. |
192 | | */ |
193 | 679 | assert(image_info != (const ImageInfo *) NULL); |
194 | 679 | assert(image_info->signature == MagickCoreSignature); |
195 | 679 | assert(exception != (ExceptionInfo *) NULL); |
196 | 679 | assert(exception->signature == MagickCoreSignature); |
197 | 679 | if (IsEventLogging() != MagickFalse) |
198 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", |
199 | 0 | image_info->filename); |
200 | 679 | image=AcquireImage(image_info,exception); |
201 | 679 | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
202 | 679 | if (status == MagickFalse) |
203 | 0 | { |
204 | 0 | image=DestroyImageList(image); |
205 | 0 | return((Image *) NULL); |
206 | 0 | } |
207 | 679 | (void) memset(&rla_info,0,sizeof(rla_info)); |
208 | 679 | rla_info.window.left=(short) ReadBlobMSBShort(image); |
209 | 679 | rla_info.window.right=(short) ReadBlobMSBShort(image); |
210 | 679 | rla_info.window.bottom=(short) ReadBlobMSBShort(image); |
211 | 679 | rla_info.window.top=(short) ReadBlobMSBShort(image); |
212 | 679 | rla_info.active_window.left=(short) ReadBlobMSBShort(image); |
213 | 679 | rla_info.active_window.right=(short) ReadBlobMSBShort(image); |
214 | 679 | rla_info.active_window.bottom=(short) ReadBlobMSBShort(image); |
215 | 679 | rla_info.active_window.top=(short) ReadBlobMSBShort(image); |
216 | 679 | rla_info.frame=(short) ReadBlobMSBShort(image); |
217 | 679 | rla_info.storage_type=(short) ReadBlobMSBShort(image); |
218 | 679 | rla_info.number_channels=(short) ReadBlobMSBShort(image); |
219 | 679 | if (rla_info.number_channels < 0) |
220 | 673 | ThrowReaderException(CorruptImageError,"ImproperImageHeader"); |
221 | 673 | rla_info.number_matte_channels=(short) ReadBlobMSBShort(image); |
222 | 673 | if (rla_info.number_matte_channels < 0) |
223 | 671 | ThrowReaderException(CorruptImageError,"ImproperImageHeader"); |
224 | 671 | if ((rla_info.number_channels > 3) || (rla_info.number_matte_channels > 3)) |
225 | 636 | ThrowReaderException(CoderError,"Unsupported number of channels"); |
226 | 636 | if (rla_info.number_channels == 0) |
227 | 588 | rla_info.number_channels=3; |
228 | 636 | rla_info.number_channels+=rla_info.number_matte_channels; |
229 | 636 | rla_info.number_auxiliary_channels=(short) ReadBlobMSBShort(image); |
230 | 636 | rla_info.revision=(short) ReadBlobMSBShort(image); |
231 | 636 | (void) ReadBlob(image,16,(unsigned char *) rla_info.gamma); |
232 | 636 | (void) ReadBlob(image,24,(unsigned char *) rla_info.red_primary); |
233 | 636 | (void) ReadBlob(image,24,(unsigned char *) rla_info.green_primary); |
234 | 636 | (void) ReadBlob(image,24,(unsigned char *) rla_info.blue_primary); |
235 | 636 | (void) ReadBlob(image,24,(unsigned char *) rla_info.white_point); |
236 | 636 | rla_info.job_number=ReadBlobMSBSignedLong(image); |
237 | 636 | (void) ReadBlob(image,128,(unsigned char *) rla_info.name); |
238 | 636 | (void) ReadBlob(image,128,(unsigned char *) rla_info.description); |
239 | 636 | rla_info.description[127]='\0'; |
240 | 636 | (void) ReadBlob(image,64,(unsigned char *) rla_info.program); |
241 | 636 | (void) ReadBlob(image,32,(unsigned char *) rla_info.machine); |
242 | 636 | (void) ReadBlob(image,32,(unsigned char *) rla_info.user); |
243 | 636 | (void) ReadBlob(image,20,(unsigned char *) rla_info.date); |
244 | 636 | (void) ReadBlob(image,24,(unsigned char *) rla_info.aspect); |
245 | 636 | (void) ReadBlob(image,8,(unsigned char *) rla_info.aspect_ratio); |
246 | 636 | (void) ReadBlob(image,32,(unsigned char *) rla_info.chan); |
247 | 636 | rla_info.field=(short) ReadBlobMSBShort(image); |
248 | 636 | (void) ReadBlob(image,12,(unsigned char *) rla_info.time); |
249 | 636 | (void) ReadBlob(image,32,(unsigned char *) rla_info.filter); |
250 | 636 | rla_info.bits_per_channel=(short) ReadBlobMSBShort(image); |
251 | 636 | rla_info.matte_type=(short) ReadBlobMSBShort(image); |
252 | 636 | rla_info.matte_bits=(short) ReadBlobMSBShort(image); |
253 | 636 | rla_info.auxiliary_type=(short) ReadBlobMSBShort(image); |
254 | 636 | rla_info.auxiliary_bits=(short) ReadBlobMSBShort(image); |
255 | 636 | (void) ReadBlob(image,32,(unsigned char *) rla_info.auxiliary); |
256 | 636 | count=ReadBlob(image,36,(unsigned char *) rla_info.space); |
257 | 636 | if ((size_t) count != 36) |
258 | 475 | ThrowReaderException(CorruptImageError,"UnableToReadImageData"); |
259 | 475 | rla_info.next=ReadBlobMSBSignedLong(image); |
260 | | /* |
261 | | Initialize image structure. |
262 | | */ |
263 | 475 | image->alpha_trait=rla_info.number_matte_channels != 0 ? BlendPixelTrait : |
264 | 475 | UndefinedPixelTrait; |
265 | 475 | image->columns=(size_t) (rla_info.active_window.right- |
266 | 475 | rla_info.active_window.left+1); |
267 | 475 | image->rows=(size_t) (rla_info.active_window.top- |
268 | 475 | rla_info.active_window.bottom+1); |
269 | 475 | if (image_info->ping != MagickFalse) |
270 | 0 | { |
271 | 0 | (void) CloseBlob(image); |
272 | 0 | return(GetFirstImageInList(image)); |
273 | 0 | } |
274 | 475 | status=SetImageExtent(image,image->columns,image->rows,exception); |
275 | 475 | if (status == MagickFalse) |
276 | 84 | return(DestroyImageList(image)); |
277 | 391 | scanlines=(MagickOffsetType *) AcquireQuantumMemory(image->rows, |
278 | 391 | sizeof(*scanlines)); |
279 | 391 | if (scanlines == (MagickOffsetType *) NULL) |
280 | 391 | ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); |
281 | 391 | if (*rla_info.description != '\0') |
282 | 247 | (void) SetImageProperty(image,"comment",rla_info.description,exception); |
283 | | /* |
284 | | Read offsets to each scanline data. |
285 | | */ |
286 | 63.0k | for (i=0; i < (ssize_t) image->rows; i++) |
287 | 62.6k | scanlines[i]=(MagickOffsetType) ReadBlobMSBSignedLong(image); |
288 | 391 | if (EOFBlob(image) != MagickFalse) |
289 | 67 | { |
290 | 67 | scanlines=(MagickOffsetType *) RelinquishMagickMemory(scanlines); |
291 | 67 | ThrowReaderException(CorruptImageError,"ImproperImageHeader"); |
292 | 0 | } |
293 | | /* |
294 | | Read image data. |
295 | | */ |
296 | 5.67k | for (y=0; y < (ssize_t) image->rows; y++) |
297 | 5.61k | { |
298 | 5.61k | offset=SeekBlob(image,scanlines[(ssize_t) image->rows-y-1],SEEK_SET); |
299 | 5.61k | if (offset < 0) |
300 | 50 | { |
301 | 50 | scanlines=(MagickOffsetType *) RelinquishMagickMemory(scanlines); |
302 | 50 | ThrowReaderException(CorruptImageError,"ImproperImageHeader"); |
303 | 0 | } |
304 | 5.56k | x=0; |
305 | 27.0k | for (channel=0; channel < (int) rla_info.number_channels; channel++) |
306 | 21.5k | { |
307 | 21.5k | length=ReadBlobMSBSignedShort(image); |
308 | 1.83M | while (length > 0) |
309 | 1.81M | { |
310 | 1.81M | byte=(unsigned char) ReadBlobByte(image); |
311 | 1.81M | runlength=byte; |
312 | 1.81M | if (byte > 127) |
313 | 891k | runlength=byte-256; |
314 | 1.81M | length--; |
315 | 1.81M | if (length == 0) |
316 | 3.90k | break; |
317 | 1.81M | if (runlength < 0) |
318 | 889k | { |
319 | 2.88M | while (runlength < 0) |
320 | 1.99M | { |
321 | 1.99M | q=GetAuthenticPixels(image,x % (ssize_t) image->columns,y,1,1, |
322 | 1.99M | exception); |
323 | 1.99M | if (q == (Quantum *) NULL) |
324 | 0 | break; |
325 | 1.99M | byte=(unsigned char) ReadBlobByte(image); |
326 | 1.99M | length--; |
327 | 1.99M | switch (channel) |
328 | 1.99M | { |
329 | 722k | case 0: |
330 | 722k | { |
331 | 722k | SetPixelRed(image,ScaleCharToQuantum(byte),q); |
332 | 722k | break; |
333 | 0 | } |
334 | 468k | case 1: |
335 | 468k | { |
336 | 468k | SetPixelGreen(image,ScaleCharToQuantum(byte),q); |
337 | 468k | break; |
338 | 0 | } |
339 | 513k | case 2: |
340 | 513k | { |
341 | 513k | SetPixelBlue(image,ScaleCharToQuantum(byte),q); |
342 | 513k | break; |
343 | 0 | } |
344 | 208k | case 3: |
345 | 286k | default: |
346 | 286k | { |
347 | 286k | SetPixelAlpha(image,ScaleCharToQuantum(byte),q); |
348 | 286k | break; |
349 | 208k | } |
350 | 1.99M | } |
351 | 1.99M | if (SyncAuthenticPixels(image,exception) == MagickFalse) |
352 | 0 | break; |
353 | 1.99M | x++; |
354 | 1.99M | runlength++; |
355 | 1.99M | } |
356 | 889k | continue; |
357 | 889k | } |
358 | 921k | byte=(unsigned char) ReadBlobByte(image); |
359 | 921k | length--; |
360 | 921k | runlength++; |
361 | 921k | do |
362 | 9.47M | { |
363 | 9.47M | q=GetAuthenticPixels(image,x % (ssize_t) image->columns,y,1,1, |
364 | 9.47M | exception); |
365 | 9.47M | if (q == (Quantum *) NULL) |
366 | 0 | break; |
367 | 9.47M | switch (channel) |
368 | 9.47M | { |
369 | 2.77M | case 0: |
370 | 2.77M | { |
371 | 2.77M | SetPixelRed(image,ScaleCharToQuantum(byte),q); |
372 | 2.77M | break; |
373 | 0 | } |
374 | 3.38M | case 1: |
375 | 3.38M | { |
376 | 3.38M | SetPixelGreen(image,ScaleCharToQuantum(byte),q); |
377 | 3.38M | break; |
378 | 0 | } |
379 | 2.54M | case 2: |
380 | 2.54M | { |
381 | 2.54M | SetPixelBlue(image,ScaleCharToQuantum(byte),q); |
382 | 2.54M | break; |
383 | 0 | } |
384 | 651k | case 3: |
385 | 773k | default: |
386 | 773k | { |
387 | 773k | SetPixelAlpha(image,ScaleCharToQuantum(byte),q); |
388 | 773k | break; |
389 | 651k | } |
390 | 9.47M | } |
391 | 9.47M | if (SyncAuthenticPixels(image,exception) == MagickFalse) |
392 | 0 | break; |
393 | 9.47M | x++; |
394 | 9.47M | runlength--; |
395 | 9.47M | } |
396 | 9.47M | while (runlength > 0); |
397 | 921k | } |
398 | 21.5k | } |
399 | 5.56k | if ((x/(ssize_t) rla_info.number_channels) > (ssize_t) image->columns) |
400 | 123 | { |
401 | 123 | scanlines=(MagickOffsetType *) RelinquishMagickMemory(scanlines); |
402 | 123 | ThrowReaderException(CorruptImageError,"CorruptImage"); |
403 | 0 | } |
404 | 5.43k | if (EOFBlob(image) != MagickFalse) |
405 | 84 | break; |
406 | 5.35k | status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, |
407 | 5.35k | image->rows); |
408 | 5.35k | if (status == MagickFalse) |
409 | 0 | break; |
410 | 5.35k | } |
411 | 151 | scanlines=(MagickOffsetType *) RelinquishMagickMemory(scanlines); |
412 | 151 | if (EOFBlob(image) != MagickFalse) |
413 | 84 | ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", |
414 | 151 | image->filename); |
415 | 151 | if (CloseBlob(image) == MagickFalse) |
416 | 0 | status=MagickFalse; |
417 | 151 | if (status == MagickFalse) |
418 | 0 | return(DestroyImageList(image)); |
419 | 151 | return(GetFirstImageInList(image)); |
420 | 151 | } |
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 | } |