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-2016 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%    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*/
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*/
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+1],
117      red_primary[24+1],
118      green_primary[24+1],
119      blue_primary[24+1],
120      white_point[24+1];
121
122    int
123      job_number;
124
125    char
126      name[128+1],
127      description[128+1],
128      program[64+1],
129      machine[32+1],
130      user[32+1],
131      date[20+1],
132      aspect[24+1],
133      aspect_ratio[8+1],
134      chan[32+1];
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+1],
152      space[36+1];
153
154    int
155      next;
156  } RLAInfo;
157
158  Image
159    *image;
160
161  int
162    channel,
163    length,
164    runlength;
165
166  MagickBooleanType
167    status;
168
169  MagickOffsetType
170    offset,
171    *scanlines;
172
173  register ssize_t
174    i,
175    x;
176
177  register Quantum
178    *q;
179
180  ssize_t
181    count,
182    y;
183
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 == MagickCoreSignature);
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 == MagickCoreSignature);
200  image=AcquireImage(image_info,exception);
201  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
202  if (status == MagickFalse)
203    {
204      image=DestroyImageList(image);
205      return((Image *) NULL);
206    }
207  (void) ResetMagickMemory(&rla_info,0,sizeof(rla_info));
208  rla_info.window.left=(short) ReadBlobMSBShort(image);
209  rla_info.window.right=(short) ReadBlobMSBShort(image);
210  rla_info.window.bottom=(short) ReadBlobMSBShort(image);
211  rla_info.window.top=(short) ReadBlobMSBShort(image);
212  rla_info.active_window.left=(short) ReadBlobMSBShort(image);
213  rla_info.active_window.right=(short) ReadBlobMSBShort(image);
214  rla_info.active_window.bottom=(short) ReadBlobMSBShort(image);
215  rla_info.active_window.top=(short) ReadBlobMSBShort(image);
216  rla_info.frame=(short) ReadBlobMSBShort(image);
217  rla_info.storage_type=(short) ReadBlobMSBShort(image);
218  rla_info.number_channels=(short) ReadBlobMSBShort(image);
219  rla_info.number_matte_channels=(short) ReadBlobMSBShort(image);
220  if (rla_info.number_channels == 0)
221    rla_info.number_channels=3;
222  rla_info.number_channels+=rla_info.number_matte_channels;
223  rla_info.number_auxiliary_channels=(short) ReadBlobMSBShort(image);
224  rla_info.revision=(short) ReadBlobMSBShort(image);
225  count=ReadBlob(image,16,(unsigned char *) rla_info.gamma);
226  count=ReadBlob(image,24,(unsigned char *) rla_info.red_primary);
227  count=ReadBlob(image,24,(unsigned char *) rla_info.green_primary);
228  count=ReadBlob(image,24,(unsigned char *) rla_info.blue_primary);
229  count=ReadBlob(image,24,(unsigned char *) rla_info.white_point);
230  rla_info.job_number=ReadBlobMSBSignedLong(image);
231  count=ReadBlob(image,128,(unsigned char *) rla_info.name);
232  count=ReadBlob(image,128,(unsigned char *) rla_info.description);
233  rla_info.description[127]='\0';
234  count=ReadBlob(image,64,(unsigned char *) rla_info.program);
235  count=ReadBlob(image,32,(unsigned char *) rla_info.machine);
236  count=ReadBlob(image,32,(unsigned char *) rla_info.user);
237  count=ReadBlob(image,20,(unsigned char *) rla_info.date);
238  count=ReadBlob(image,24,(unsigned char *) rla_info.aspect);
239  count=ReadBlob(image,8,(unsigned char *) rla_info.aspect_ratio);
240  count=ReadBlob(image,32,(unsigned char *) rla_info.chan);
241  rla_info.field=(short) ReadBlobMSBShort(image);
242  count=ReadBlob(image,12,(unsigned char *) rla_info.time);
243  count=ReadBlob(image,32,(unsigned char *) rla_info.filter);
244  rla_info.bits_per_channel=(short) ReadBlobMSBShort(image);
245  rla_info.matte_type=(short) ReadBlobMSBShort(image);
246  rla_info.matte_bits=(short) ReadBlobMSBShort(image);
247  rla_info.auxiliary_type=(short) ReadBlobMSBShort(image);
248  rla_info.auxiliary_bits=(short) ReadBlobMSBShort(image);
249  count=ReadBlob(image,32,(unsigned char *) rla_info.auxiliary);
250  count=ReadBlob(image,36,(unsigned char *) rla_info.space);
251  if ((size_t) count != 36)
252    ThrowReaderException(CorruptImageError,"UnableToReadImageData");
253  rla_info.next=ReadBlobMSBSignedLong(image);
254  /*
255    Initialize image structure.
256  */
257  image->alpha_trait=rla_info.number_matte_channels != 0 ? BlendPixelTrait :
258    UndefinedPixelTrait;
259  image->columns=(size_t) (rla_info.active_window.right-
260    rla_info.active_window.left+1);
261  image->rows=(size_t) (rla_info.active_window.top-
262    rla_info.active_window.bottom+1);
263  if (image_info->ping != MagickFalse)
264    {
265      (void) CloseBlob(image);
266      return(GetFirstImageInList(image));
267    }
268  status=SetImageExtent(image,image->columns,image->rows,exception);
269  if (status == MagickFalse)
270    return(DestroyImageList(image));
271  scanlines=(MagickOffsetType *) AcquireQuantumMemory(image->rows,
272    sizeof(*scanlines));
273  if (scanlines == (MagickOffsetType *) NULL)
274    ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
275  if (*rla_info.description != '\0')
276    (void) SetImageProperty(image,"comment",rla_info.description,exception);
277  /*
278    Read offsets to each scanline data.
279  */
280  for (i=0; i < (ssize_t) image->rows; i++)
281    scanlines[i]=(MagickOffsetType) ReadBlobMSBSignedLong(image);
282  /*
283    Read image data.
284  */
285  x=0;
286  for (y=0; y < (ssize_t) image->rows; y++)
287  {
288    offset=SeekBlob(image,scanlines[image->rows-y-1],SEEK_SET);
289    if (offset < 0)
290      ThrowReaderException(CorruptImageError,"ImproperImageHeader");
291    for (channel=0; channel < (int) rla_info.number_channels; channel++)
292    {
293      length=ReadBlobMSBSignedShort(image);
294      while (length > 0)
295      {
296        byte=(unsigned char) ReadBlobByte(image);
297        runlength=byte;
298        if (byte > 127)
299          runlength=byte-256;
300        length--;
301        if (length == 0)
302          break;
303        if (runlength < 0)
304          {
305            while (runlength < 0)
306            {
307              q=GetAuthenticPixels(image,(ssize_t) (x % image->columns),
308                (ssize_t) (y % image->rows),1,1,exception);
309              if (q == (Quantum *) NULL)
310                break;
311              byte=(unsigned char) ReadBlobByte(image);
312              length--;
313              switch (channel)
314              {
315                case 0:
316                {
317                  SetPixelRed(image,ScaleCharToQuantum(byte),q);
318                  break;
319                }
320                case 1:
321                {
322                  SetPixelGreen(image,ScaleCharToQuantum(byte),q);
323                  break;
324                }
325                case 2:
326                {
327                  SetPixelBlue(image,ScaleCharToQuantum(byte),q);
328                  break;
329                }
330                case 3:
331                default:
332                {
333                  SetPixelAlpha(image,ScaleCharToQuantum(byte),q);
334                  break;
335                }
336              }
337              if (SyncAuthenticPixels(image,exception) == MagickFalse)
338                break;
339              x++;
340              runlength++;
341            }
342            continue;
343          }
344        byte=(unsigned char) ReadBlobByte(image);
345        length--;
346        runlength++;
347        do
348        {
349          q=GetAuthenticPixels(image,(ssize_t) (x % image->columns),
350            (ssize_t) (y % image->rows),1,1,exception);
351          if (q == (Quantum *) NULL)
352            break;
353          switch (channel)
354          {
355            case 0:
356            {
357              SetPixelRed(image,ScaleCharToQuantum(byte),q);
358              break;
359            }
360            case 1:
361            {
362              SetPixelGreen(image,ScaleCharToQuantum(byte),q);
363              break;
364            }
365            case 2:
366            {
367              SetPixelBlue(image,ScaleCharToQuantum(byte),q);
368              break;
369            }
370            case 3:
371            default:
372            {
373              SetPixelAlpha(image,ScaleCharToQuantum(byte),q);
374              break;
375            }
376          }
377          if (SyncAuthenticPixels(image,exception) == MagickFalse)
378            break;
379          x++;
380          runlength--;
381        }
382        while (runlength > 0);
383      }
384    }
385    status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
386      image->rows);
387    if (status == MagickFalse)
388      break;
389  }
390  if (EOFBlob(image) != MagickFalse)
391    ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
392      image->filename);
393  scanlines=(MagickOffsetType *) RelinquishMagickMemory(scanlines);
394  (void) CloseBlob(image);
395  return(GetFirstImageInList(image));
396}
397
398/*
399%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
400%                                                                             %
401%                                                                             %
402%                                                                             %
403%   R e g i s t e r R L A I m a g e                                           %
404%                                                                             %
405%                                                                             %
406%                                                                             %
407%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
408%
409%  RegisterRLAImage() adds attributes for the RLA image format to
410%  the list of supported formats.  The attributes include the image format
411%  tag, a method to read and/or write the format, whether the format
412%  supports the saving of more than one frame to the same file or blob,
413%  whether the format supports native in-memory I/O, and a brief
414%  description of the format.
415%
416%  The format of the RegisterRLAImage method is:
417%
418%      size_t RegisterRLAImage(void)
419%
420*/
421ModuleExport size_t RegisterRLAImage(void)
422{
423  MagickInfo
424    *entry;
425
426  entry=AcquireMagickInfo("RLA","RLA","Alias/Wavefront image");
427  entry->decoder=(DecodeImageHandler *) ReadRLAImage;
428  entry->flags^=CoderAdjoinFlag;
429  entry->flags|=CoderSeekableStreamFlag;
430  (void) RegisterMagickInfo(entry);
431  return(MagickImageCoderSignature);
432}
433
434/*
435%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
436%                                                                             %
437%                                                                             %
438%                                                                             %
439%   U n r e g i s t e r R L A I m a g e                                       %
440%                                                                             %
441%                                                                             %
442%                                                                             %
443%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
444%
445%  UnregisterRLAImage() removes format registrations made by the
446%  RLA module from the list of supported formats.
447%
448%  The format of the UnregisterRLAImage method is:
449%
450%      UnregisterRLAImage(void)
451%
452*/
453ModuleExport void UnregisterRLAImage(void)
454{
455  (void) UnregisterMagickInfo("RLA");
456}
457