blob: 843fd6fb273ddb449916598210fc5fe505daf81a [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
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% John Cristy %
17% July 1992 %
18% %
19% %
cristy1454be72011-12-19 01:52:48 +000020% Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% 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% http://www.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*/
cristy4c08aed2011-07-01 19:47:50 +000042#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"
cristy3ed852e2009-09-05 21:47:34 +000061
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*/
90static Image *ReadRLAImage(const ImageInfo *image_info,ExceptionInfo *exception)
91{
92 typedef struct _WindowFrame
93 {
94 short
95 left,
96 right,
97 bottom,
98 top;
99 } WindowFrame;
100
101 typedef struct _RLAInfo
102 {
103 WindowFrame
104 window,
105 active_window;
106
107 short
108 frame,
109 storage_type,
110 number_channels,
111 number_matte_channels,
112 number_auxiliary_channels,
113 revision;
114
115 char
116 gamma[16],
117 red_primary[24],
118 green_primary[24],
119 blue_primary[24],
120 white_point[24];
121
cristybb503372010-05-27 20:51:26 +0000122 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000123 job_number;
124
125 char
126 name[128],
127 description[128],
128 program[64],
129 machine[32],
130 user[32],
131 date[20],
132 aspect[24],
133 aspect_ratio[8],
134 chan[32];
135
136 short
137 field;
138
139 char
140 time[12],
141 filter[32];
142
143 short
144 bits_per_channel,
145 matte_type,
146 matte_bits,
147 auxiliary_type,
148 auxiliary_bits;
149
150 char
151 auxiliary[32],
152 space[36];
153
cristybb503372010-05-27 20:51:26 +0000154 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000155 next;
156 } RLAInfo;
157
158 Image
159 *image;
160
161 int
162 channel,
163 length,
164 runlength;
165
cristy3ed852e2009-09-05 21:47:34 +0000166 MagickBooleanType
167 status;
168
169 MagickOffsetType
170 offset;
171
cristybb503372010-05-27 20:51:26 +0000172 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000173 i,
174 x;
175
cristy4c08aed2011-07-01 19:47:50 +0000176 register Quantum
cristy3ed852e2009-09-05 21:47:34 +0000177 *q;
178
179 ssize_t
cristyc6da28e2011-04-28 01:41:35 +0000180 count,
181 *scanlines,
182 y;
cristy3ed852e2009-09-05 21:47:34 +0000183
184 RLAInfo
185 rla_info;
186
187 unsigned char
188 byte;
189
190 /*
191 Open image file.
192 */
193 assert(image_info != (const ImageInfo *) NULL);
194 assert(image_info->signature == MagickSignature);
195 if (image_info->debug != MagickFalse)
196 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
197 image_info->filename);
198 assert(exception != (ExceptionInfo *) NULL);
199 assert(exception->signature == MagickSignature);
cristy9950d572011-10-01 18:22:35 +0000200 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000201 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
202 if (status == MagickFalse)
203 {
204 image=DestroyImageList(image);
205 return((Image *) NULL);
206 }
207 rla_info.window.left=(short) ReadBlobMSBShort(image);
208 rla_info.window.right=(short) ReadBlobMSBShort(image);
209 rla_info.window.bottom=(short) ReadBlobMSBShort(image);
210 rla_info.window.top=(short) ReadBlobMSBShort(image);
211 rla_info.active_window.left=(short) ReadBlobMSBShort(image);
212 rla_info.active_window.right=(short) ReadBlobMSBShort(image);
213 rla_info.active_window.bottom=(short) ReadBlobMSBShort(image);
214 rla_info.active_window.top=(short) ReadBlobMSBShort(image);
215 rla_info.frame=(short) ReadBlobMSBShort(image);
216 rla_info.storage_type=(short) ReadBlobMSBShort(image);
217 rla_info.number_channels=(short) ReadBlobMSBShort(image);
218 rla_info.number_matte_channels=(short) ReadBlobMSBShort(image);
219 if (rla_info.number_channels == 0)
220 rla_info.number_channels=3;
221 rla_info.number_channels+=rla_info.number_matte_channels;
222 rla_info.number_auxiliary_channels=(short) ReadBlobMSBShort(image);
223 rla_info.revision=(short) ReadBlobMSBShort(image);
224 count=ReadBlob(image,16,(unsigned char *) rla_info.gamma);
225 count=ReadBlob(image,24,(unsigned char *) rla_info.red_primary);
226 count=ReadBlob(image,24,(unsigned char *) rla_info.green_primary);
227 count=ReadBlob(image,24,(unsigned char *) rla_info.blue_primary);
228 count=ReadBlob(image,24,(unsigned char *) rla_info.white_point);
cristy6cff05d2010-09-02 11:22:46 +0000229 rla_info.job_number=(int) ReadBlobMSBLong(image);
cristy3ed852e2009-09-05 21:47:34 +0000230 count=ReadBlob(image,128,(unsigned char *) rla_info.name);
231 count=ReadBlob(image,128,(unsigned char *) rla_info.description);
232 count=ReadBlob(image,64,(unsigned char *) rla_info.program);
233 count=ReadBlob(image,32,(unsigned char *) rla_info.machine);
234 count=ReadBlob(image,32,(unsigned char *) rla_info.user);
235 count=ReadBlob(image,20,(unsigned char *) rla_info.date);
236 count=ReadBlob(image,24,(unsigned char *) rla_info.aspect);
237 count=ReadBlob(image,8,(unsigned char *) rla_info.aspect_ratio);
238 count=ReadBlob(image,32,(unsigned char *) rla_info.chan);
239 rla_info.field=(short) ReadBlobMSBShort(image);
240 count=ReadBlob(image,12,(unsigned char *) rla_info.time);
241 count=ReadBlob(image,32,(unsigned char *) rla_info.filter);
242 rla_info.bits_per_channel=(short) ReadBlobMSBShort(image);
243 rla_info.matte_type=(short) ReadBlobMSBShort(image);
244 rla_info.matte_bits=(short) ReadBlobMSBShort(image);
245 rla_info.auxiliary_type=(short) ReadBlobMSBShort(image);
246 rla_info.auxiliary_bits=(short) ReadBlobMSBShort(image);
247 count=ReadBlob(image,32,(unsigned char *) rla_info.auxiliary);
248 count=ReadBlob(image,36,(unsigned char *) rla_info.space);
249 if ((size_t) count != 36)
250 ThrowReaderException(CorruptImageError,"UnableToReadImageData");
cristy6cff05d2010-09-02 11:22:46 +0000251 rla_info.next=(int) ReadBlobMSBLong(image);
cristy3ed852e2009-09-05 21:47:34 +0000252 /*
253 Initialize image structure.
254 */
255 image->matte=rla_info.number_matte_channels != 0 ? MagickTrue : MagickFalse;
256 image->columns=1UL*rla_info.active_window.right-rla_info.active_window.left+1;
257 image->rows=1UL*rla_info.active_window.top-rla_info.active_window.bottom+1;
258 if (image_info->ping != MagickFalse)
259 {
260 (void) CloseBlob(image);
261 return(GetFirstImageInList(image));
262 }
cristybb503372010-05-27 20:51:26 +0000263 scanlines=(ssize_t *) AcquireQuantumMemory(image->rows,sizeof(*scanlines));
264 if (scanlines == (ssize_t *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000265 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
266 if (*rla_info.description != '\0')
cristyd15e6592011-10-15 00:13:06 +0000267 (void) SetImageProperty(image,"comment",rla_info.description,exception);
cristy3ed852e2009-09-05 21:47:34 +0000268 /*
269 Read offsets to each scanline data.
270 */
cristybb503372010-05-27 20:51:26 +0000271 for (i=0; i < (ssize_t) image->rows; i++)
cristy6cff05d2010-09-02 11:22:46 +0000272 scanlines[i]=(int) ReadBlobMSBLong(image);
cristy3ed852e2009-09-05 21:47:34 +0000273 /*
274 Read image data.
275 */
276 x=0;
cristybb503372010-05-27 20:51:26 +0000277 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000278 {
279 offset=SeekBlob(image,scanlines[image->rows-y-1],SEEK_SET);
280 if (offset < 0)
281 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
282 for (channel=0; channel < (int) rla_info.number_channels; channel++)
283 {
284 length=(int) ReadBlobMSBShort(image);
285 while (length > 0)
286 {
287 byte=(unsigned char) ReadBlobByte(image);
288 runlength=byte;
289 if (byte > 127)
290 runlength=byte-256;
291 length--;
292 if (length == 0)
293 break;
294 if (runlength < 0)
295 {
296 while (runlength < 0)
297 {
cristybb503372010-05-27 20:51:26 +0000298 q=GetAuthenticPixels(image,(ssize_t) (x % image->columns),
299 (ssize_t) (y % image->rows),1,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000300 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000301 break;
302 byte=(unsigned char) ReadBlobByte(image);
303 length--;
304 switch (channel)
305 {
306 case 0:
307 {
cristy4c08aed2011-07-01 19:47:50 +0000308 SetPixelRed(image,ScaleCharToQuantum(byte),q);
cristy3ed852e2009-09-05 21:47:34 +0000309 break;
310 }
311 case 1:
312 {
cristy4c08aed2011-07-01 19:47:50 +0000313 SetPixelGreen(image,ScaleCharToQuantum(byte),q);
cristy3ed852e2009-09-05 21:47:34 +0000314 break;
315 }
316 case 2:
317 {
cristy4c08aed2011-07-01 19:47:50 +0000318 SetPixelBlue(image,ScaleCharToQuantum(byte),q);
cristy3ed852e2009-09-05 21:47:34 +0000319 break;
320 }
321 case 3:
322 default:
323 {
cristy4c08aed2011-07-01 19:47:50 +0000324 SetPixelAlpha(image,ScaleCharToQuantum(byte),q);
cristy3ed852e2009-09-05 21:47:34 +0000325 break;
326 }
327 }
328 if (SyncAuthenticPixels(image,exception) == MagickFalse)
329 break;
330 x++;
331 runlength++;
332 }
333 continue;
334 }
335 byte=(unsigned char) ReadBlobByte(image);
336 length--;
337 runlength++;
338 do
339 {
cristybb503372010-05-27 20:51:26 +0000340 q=GetAuthenticPixels(image,(ssize_t) (x % image->columns),
341 (ssize_t) (y % image->rows),1,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000342 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000343 break;
344 switch (channel)
345 {
346 case 0:
347 {
cristy4c08aed2011-07-01 19:47:50 +0000348 SetPixelRed(image,ScaleCharToQuantum(byte),q);
cristy3ed852e2009-09-05 21:47:34 +0000349 break;
350 }
351 case 1:
352 {
cristy4c08aed2011-07-01 19:47:50 +0000353 SetPixelGreen(image,ScaleCharToQuantum(byte),q);
cristy3ed852e2009-09-05 21:47:34 +0000354 break;
355 }
356 case 2:
357 {
cristy4c08aed2011-07-01 19:47:50 +0000358 SetPixelBlue(image,ScaleCharToQuantum(byte),q);
cristy3ed852e2009-09-05 21:47:34 +0000359 break;
360 }
361 case 3:
362 default:
363 {
cristy4c08aed2011-07-01 19:47:50 +0000364 SetPixelAlpha(image,ScaleCharToQuantum(byte),q);
cristy3ed852e2009-09-05 21:47:34 +0000365 break;
366 }
367 }
368 if (SyncAuthenticPixels(image,exception) == MagickFalse)
369 break;
370 x++;
371 runlength--;
372 }
373 while (runlength > 0);
374 }
375 }
cristycee97112010-05-28 00:44:52 +0000376 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
cristyc6da28e2011-04-28 01:41:35 +0000377 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000378 if (status == MagickFalse)
379 break;
380 }
381 if (EOFBlob(image) != MagickFalse)
382 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
383 image->filename);
384 (void) CloseBlob(image);
385 return(GetFirstImageInList(image));
386}
387
388/*
389%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
390% %
391% %
392% %
393% R e g i s t e r R L A I m a g e %
394% %
395% %
396% %
397%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
398%
399% RegisterRLAImage() adds attributes for the RLA image format to
400% the list of supported formats. The attributes include the image format
401% tag, a method to read and/or write the format, whether the format
402% supports the saving of more than one frame to the same file or blob,
403% whether the format supports native in-memory I/O, and a brief
404% description of the format.
405%
406% The format of the RegisterRLAImage method is:
407%
cristybb503372010-05-27 20:51:26 +0000408% size_t RegisterRLAImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000409%
410*/
cristybb503372010-05-27 20:51:26 +0000411ModuleExport size_t RegisterRLAImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000412{
413 MagickInfo
414 *entry;
415
416 entry=SetMagickInfo("RLA");
417 entry->decoder=(DecodeImageHandler *) ReadRLAImage;
418 entry->adjoin=MagickFalse;
cristyffaf9782011-04-13 19:50:51 +0000419 entry->seekable_stream=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +0000420 entry->description=ConstantString("Alias/Wavefront image");
421 entry->module=ConstantString("RLA");
422 (void) RegisterMagickInfo(entry);
423 return(MagickImageCoderSignature);
424}
425
426/*
427%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
428% %
429% %
430% %
431% U n r e g i s t e r R L A I m a g e %
432% %
433% %
434% %
435%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
436%
437% UnregisterRLAImage() removes format registrations made by the
438% RLA module from the list of supported formats.
439%
440% The format of the UnregisterRLAImage method is:
441%
442% UnregisterRLAImage(void)
443%
444*/
445ModuleExport void UnregisterRLAImage(void)
446{
447 (void) UnregisterMagickInfo("RLA");
448}