]> granicus.if.org Git - imagemagick/blob - coders/rle.c
(no commit message)
[imagemagick] / coders / rle.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                            RRRR   L      EEEEE                              %
7 %                            R   R  L      E                                  %
8 %                            RRRR   L      EEE                                %
9 %                            R R    L      E                                  %
10 %                            R  R   LLLLL  EEEEE                              %
11 %                                                                             %
12 %                                                                             %
13 %                          Read URT RLE Image Format                          %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                John Cristy                                  %
17 %                                 July 1992                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2011 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 \f
39 /*
40   Include declarations.
41 */
42 #include "magick/studio.h"
43 #include "magick/property.h"
44 #include "magick/blob.h"
45 #include "magick/blob-private.h"
46 #include "magick/cache.h"
47 #include "magick/colormap.h"
48 #include "magick/exception.h"
49 #include "magick/exception-private.h"
50 #include "magick/image.h"
51 #include "magick/image-private.h"
52 #include "magick/list.h"
53 #include "magick/magick.h"
54 #include "magick/memory_.h"
55 #include "magick/monitor.h"
56 #include "magick/monitor-private.h"
57 #include "magick/quantum-private.h"
58 #include "magick/pixel.h"
59 #include "magick/static.h"
60 #include "magick/string_.h"
61 #include "magick/module.h"
62 \f
63 /*
64 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
65 %                                                                             %
66 %                                                                             %
67 %                                                                             %
68 %   I s R L E                                                                 %
69 %                                                                             %
70 %                                                                             %
71 %                                                                             %
72 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
73 %
74 %  IsRLE() returns MagickTrue if the image format type, identified by the
75 %  magick string, is RLE.
76 %
77 %  The format of the ReadRLEImage method is:
78 %
79 %      MagickBooleanType IsRLE(const unsigned char *magick,const size_t length)
80 %
81 %  A description of each parameter follows:
82 %
83 %    o magick: compare image format pattern against these bytes.
84 %
85 %    o length: Specifies the length of the magick string.
86 %
87 %
88 */
89 static MagickBooleanType IsRLE(const unsigned char *magick,const size_t length)
90 {
91   if (length < 2)
92     return(MagickFalse);
93   if (memcmp(magick,"\122\314",2) == 0)
94     return(MagickTrue);
95   return(MagickFalse);
96 }
97 \f
98 /*
99 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
100 %                                                                             %
101 %                                                                             %
102 %                                                                             %
103 %   R e a d R L E I m a g e                                                   %
104 %                                                                             %
105 %                                                                             %
106 %                                                                             %
107 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
108 %
109 %  ReadRLEImage() reads a run-length encoded Utah Raster Toolkit
110 %  image file and returns it.  It allocates the memory necessary for the new
111 %  Image structure and returns a pointer to the new image.
112 %
113 %  The format of the ReadRLEImage method is:
114 %
115 %      Image *ReadRLEImage(const ImageInfo *image_info,ExceptionInfo *exception)
116 %
117 %  A description of each parameter follows:
118 %
119 %    o image_info: the image info.
120 %
121 %    o exception: return any errors or warnings in this structure.
122 %
123 %
124 */
125 static Image *ReadRLEImage(const ImageInfo *image_info,ExceptionInfo *exception)
126 {
127 #define SkipLinesOp  0x01
128 #define SetColorOp  0x02
129 #define SkipPixelsOp  0x03
130 #define ByteDataOp  0x05
131 #define RunDataOp  0x06
132 #define EOFOp  0x07
133
134   char
135     magick[12];
136
137   Image
138     *image;
139
140   int
141     opcode,
142     operand,
143     status;
144
145   MagickStatusType
146     flags;
147
148   MagickSizeType
149     number_pixels;
150
151   register IndexPacket
152     *indexes;
153
154   register ssize_t
155     x;
156
157   register PixelPacket
158     *q;
159
160   register ssize_t
161     i;
162
163   register unsigned char
164     *p;
165
166   size_t
167     bits_per_pixel,
168     map_length,
169     number_colormaps,
170     number_planes,
171     one;
172
173   ssize_t
174     count,
175     y;
176
177   unsigned char
178     background_color[256],
179     *colormap,
180     pixel,
181     plane,
182     *rle_pixels;
183
184   /*
185     Open image file.
186   */
187   assert(image_info != (const ImageInfo *) NULL);
188   assert(image_info->signature == MagickSignature);
189   if (image_info->debug != MagickFalse)
190     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
191       image_info->filename);
192   assert(exception != (ExceptionInfo *) NULL);
193   assert(exception->signature == MagickSignature);
194   image=AcquireImage(image_info);
195   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
196   if (status == MagickFalse)
197     {
198       image=DestroyImageList(image);
199       return((Image *) NULL);
200     }
201   /*
202     Determine if this a RLE file.
203   */
204   count=ReadBlob(image,2,(unsigned char *) magick);
205   if ((count == 0) || (memcmp(magick,"\122\314",2) != 0))
206     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
207   do
208   {
209     /*
210       Read image header.
211     */
212     (void) ReadBlobLSBShort(image);
213     (void) ReadBlobLSBShort(image);
214     image->columns=ReadBlobLSBShort(image);
215     image->rows=ReadBlobLSBShort(image);
216     flags=(MagickStatusType) ReadBlobByte(image);
217     image->matte=flags & 0x04 ? MagickTrue : MagickFalse;
218     number_planes=1UL*ReadBlobByte(image);
219     bits_per_pixel=1UL*ReadBlobByte(image);
220     number_colormaps=1UL*ReadBlobByte(image);
221     one=1;
222     map_length=one << ReadBlobByte(image);
223     if ((number_planes == 0) || (number_planes == 2) || (bits_per_pixel != 8) ||
224         (image->columns == 0))
225       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
226     if (flags & 0x02)
227       {
228         /*
229           No background color-- initialize to black.
230         */
231         for (i=0; i < (ssize_t) number_planes; i++)
232           background_color[i]=0;
233         (void) ReadBlobByte(image);
234       }
235     else
236       {
237         /*
238           Initialize background color.
239         */
240         p=background_color;
241         for (i=0; i < (ssize_t) number_planes; i++)
242           *p++=(unsigned char) ReadBlobByte(image);
243       }
244     if ((number_planes & 0x01) == 0)
245       (void) ReadBlobByte(image);
246     colormap=(unsigned char *) NULL;
247     if (number_colormaps != 0)
248       {
249         /*
250           Read image colormaps.
251         */
252         colormap=(unsigned char *) AcquireQuantumMemory(number_colormaps,
253           map_length*sizeof(*colormap));
254         if (colormap == (unsigned char *) NULL)
255           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
256         p=colormap;
257         for (i=0; i < (ssize_t) number_colormaps; i++)
258           for (x=0; x < (ssize_t) map_length; x++)
259             *p++=(unsigned char) ScaleShortToQuantum(ReadBlobLSBShort(image));
260       }
261     if ((flags & 0x08) != 0)
262       {
263         char
264           *comment;
265
266         size_t
267           length;
268
269         /*
270           Read image comment.
271         */
272         length=ReadBlobLSBShort(image);
273         if (length != 0)
274           {
275             comment=(char *) AcquireQuantumMemory(length,sizeof(*comment));
276             if (comment == (char *) NULL)
277               ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
278             count=ReadBlob(image,length-1,(unsigned char *) comment);
279             comment[length-1]='\0';
280             (void) SetImageProperty(image,"comment",comment);
281             comment=DestroyString(comment);
282             if ((length & 0x01) == 0)
283               (void) ReadBlobByte(image);
284           }
285       }
286     if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
287       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
288         break;
289     /*
290       Allocate RLE pixels.
291     */
292     if (image->matte != MagickFalse)
293       number_planes++;
294     number_pixels=(MagickSizeType) image->columns*image->rows;
295     if ((number_pixels*number_planes) != (size_t) (number_pixels*number_planes))
296       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
297     rle_pixels=(unsigned char *) AcquireQuantumMemory(image->columns,
298       image->rows*number_planes*sizeof(*rle_pixels));
299     if (rle_pixels == (unsigned char *) NULL)
300       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
301     if ((flags & 0x01) && !(flags & 0x02))
302       {
303         ssize_t
304           j;
305
306         /*
307           Set background color.
308         */
309         p=rle_pixels;
310         for (i=0; i < (ssize_t) number_pixels; i++)
311         {
312           if (image->matte == MagickFalse)
313             for (j=0; j < (ssize_t) number_planes; j++)
314               *p++=background_color[j];
315           else
316             {
317               for (j=0; j < (ssize_t) (number_planes-1); j++)
318                 *p++=background_color[j];
319               *p++=0;  /* initialize matte channel */
320             }
321         }
322       }
323     /*
324       Read runlength-encoded image.
325     */
326     plane=0;
327     x=0;
328     y=0;
329     opcode=ReadBlobByte(image);
330     do
331     {
332       switch (opcode & 0x3f)
333       {
334         case SkipLinesOp:
335         {
336           operand=ReadBlobByte(image);
337           if (opcode & 0x40)
338             operand=(int) ReadBlobLSBShort(image);
339           x=0;
340           y+=operand;
341           break;
342         }
343         case SetColorOp:
344         {
345           operand=ReadBlobByte(image);
346           plane=(unsigned char) operand;
347           if (plane == 255)
348             plane=(unsigned char) (number_planes-1);
349           x=0;
350           break;
351         }
352         case SkipPixelsOp:
353         {
354           operand=ReadBlobByte(image);
355           if (opcode & 0x40)
356             operand=(int) ReadBlobLSBShort(image);
357           x+=operand;
358           break;
359         }
360         case ByteDataOp:
361         {
362           operand=ReadBlobByte(image);
363           if (opcode & 0x40)
364             operand=(int) ReadBlobLSBShort(image);
365           p=rle_pixels+((image->rows-y-1)*image->columns*number_planes)+
366             x*number_planes+plane;
367           operand++;
368           for (i=0; i < (ssize_t) operand; i++)
369           {
370             pixel=(unsigned char) ReadBlobByte(image);
371             if ((y < (ssize_t) image->rows) &&
372                 ((x+i) < (ssize_t) image->columns))
373               *p=pixel;
374             p+=number_planes;
375           }
376           if (operand & 0x01)
377             (void) ReadBlobByte(image);
378           x+=operand;
379           break;
380         }
381         case RunDataOp:
382         {
383           operand=ReadBlobByte(image);
384           if (opcode & 0x40)
385             operand=(int) ReadBlobLSBShort(image);
386           pixel=(unsigned char) ReadBlobByte(image);
387           (void) ReadBlobByte(image);
388           operand++;
389           p=rle_pixels+((image->rows-y-1)*image->columns*number_planes)+
390             x*number_planes+plane;
391           for (i=0; i < (ssize_t) operand; i++)
392           {
393             if ((y < (ssize_t) image->rows) &&
394                 ((x+i) < (ssize_t) image->columns))
395               *p=pixel;
396             p+=number_planes;
397           }
398           x+=operand;
399           break;
400         }
401         default:
402           break;
403       }
404       opcode=ReadBlobByte(image);
405     } while (((opcode & 0x3f) != EOFOp) && (opcode != EOF));
406     if (number_colormaps != 0)
407       {
408         MagickStatusType
409           mask;
410
411         /*
412           Apply colormap affineation to image.
413         */
414         mask=(MagickStatusType) (map_length-1);
415         p=rle_pixels;
416         if (number_colormaps == 1)
417           for (i=0; i < (ssize_t) number_pixels; i++)
418           {
419             *p=colormap[*p & mask];
420             p++;
421           }
422         else
423           if ((number_planes >= 3) && (number_colormaps >= 3))
424             for (i=0; i < (ssize_t) number_pixels; i++)
425               for (x=0; x < (ssize_t) number_planes; x++)
426               {
427                 *p=colormap[x*map_length+(*p & mask)];
428                 p++;
429               }
430       }
431     /*
432       Initialize image structure.
433     */
434     if (number_planes >= 3)
435       {
436         /*
437           Convert raster image to DirectClass pixel packets.
438         */
439         p=rle_pixels;
440         for (y=0; y < (ssize_t) image->rows; y++)
441         {
442           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
443           if (q == (PixelPacket *) NULL)
444             break;
445           for (x=0; x < (ssize_t) image->columns; x++)
446           {
447             SetRedPixelComponent(q,ScaleCharToQuantum(*p++));
448             SetGreenPixelComponent(q,ScaleCharToQuantum(*p++));
449             SetBluePixelComponent(q,ScaleCharToQuantum(*p++));
450             if (image->matte != MagickFalse)
451               SetOpacityPixelComponent(q,QuantumRange-ScaleCharToQuantum(*p++));
452             q++;
453           }
454           if (SyncAuthenticPixels(image,exception) == MagickFalse)
455             break;
456           if (image->previous == (Image *) NULL)
457             {
458               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
459                 image->rows);
460               if (status == MagickFalse)
461                 break;
462             }
463         }
464       }
465     else
466       {
467         /*
468           Create colormap.
469         */
470         if (number_colormaps == 0)
471           map_length=256;
472         if (AcquireImageColormap(image,map_length) == MagickFalse)
473           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
474         p=colormap;
475         if (number_colormaps == 1)
476           for (i=0; i < (ssize_t) image->colors; i++)
477           {
478             /*
479               Pseudocolor.
480             */
481             image->colormap[i].red=ScaleCharToQuantum((unsigned char) i);
482             image->colormap[i].green=ScaleCharToQuantum((unsigned char) i);
483             image->colormap[i].blue=ScaleCharToQuantum((unsigned char) i);
484           }
485         else
486           if (number_colormaps > 1)
487             for (i=0; i < (ssize_t) image->colors; i++)
488             {
489               image->colormap[i].red=ScaleCharToQuantum(*p);
490               image->colormap[i].green=ScaleCharToQuantum(*(p+map_length));
491               image->colormap[i].blue=ScaleCharToQuantum(*(p+map_length*2));
492               p++;
493             }
494         p=rle_pixels;
495         if (image->matte == MagickFalse)
496           {
497             /*
498               Convert raster image to PseudoClass pixel packets.
499             */
500             for (y=0; y < (ssize_t) image->rows; y++)
501             {
502               q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
503               if (q == (PixelPacket *) NULL)
504                 break;
505               indexes=GetAuthenticIndexQueue(image);
506               for (x=0; x < (ssize_t) image->columns; x++)
507                 SetIndexPixelComponent(indexes+x,*p++);
508               if (SyncAuthenticPixels(image,exception) == MagickFalse)
509                 break;
510               if (image->previous == (Image *) NULL)
511                 {
512                   status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
513                     y,image->rows);
514                   if (status == MagickFalse)
515                     break;
516                 }
517             }
518             (void) SyncImage(image);
519           }
520         else
521           {
522             /*
523               Image has a matte channel-- promote to DirectClass.
524             */
525             for (y=0; y < (ssize_t) image->rows; y++)
526             {
527               q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
528               if (q == (PixelPacket *) NULL)
529                 break;
530               for (x=0; x < (ssize_t) image->columns; x++)
531               {
532                 SetRedPixelComponent(q,image->colormap[*p++].red);
533                 SetGreenPixelComponent(q,image->colormap[*p++].green);
534                 SetBluePixelComponent(q,image->colormap[*p++].blue);
535                 SetOpacityPixelComponent(q,QuantumRange-
536                   ScaleCharToQuantum(*p++));
537                 q++;
538               }
539               if (SyncAuthenticPixels(image,exception) == MagickFalse)
540                 break;
541               if (image->previous == (Image *) NULL)
542                 {
543                   status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
544                     y,image->rows);
545                   if (status == MagickFalse)
546                     break;
547                 }
548             }
549             image->colormap=(PixelPacket *)
550               RelinquishMagickMemory(image->colormap);
551             image->storage_class=DirectClass;
552             image->colors=0;
553           }
554       }
555     if (number_colormaps != 0)
556       colormap=(unsigned char *) RelinquishMagickMemory(colormap);
557     rle_pixels=(unsigned char *) RelinquishMagickMemory(rle_pixels);
558     if (EOFBlob(image) != MagickFalse)
559       {
560         ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
561           image->filename);
562         break;
563       }
564     /*
565       Proceed to next image.
566     */
567     if (image_info->number_scenes != 0)
568       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
569         break;
570     (void) ReadBlobByte(image);
571     count=ReadBlob(image,2,(unsigned char *) magick);
572     if ((count != 0) && (memcmp(magick,"\122\314",2) == 0))
573       {
574         /*
575           Allocate next image structure.
576         */
577         AcquireNextImage(image_info,image);
578         if (GetNextImageInList(image) == (Image *) NULL)
579           {
580             image=DestroyImageList(image);
581             return((Image *) NULL);
582           }
583         image=SyncNextImageInList(image);
584         status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
585           GetBlobSize(image));
586         if (status == MagickFalse)
587           break;
588       }
589   } while ((count != 0) && (memcmp(magick,"\122\314",2) == 0));
590   (void) CloseBlob(image);
591   return(GetFirstImageInList(image));
592 }
593 \f
594 /*
595 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
596 %                                                                             %
597 %                                                                             %
598 %                                                                             %
599 %   R e g i s t e r R L E I m a g e                                           %
600 %                                                                             %
601 %                                                                             %
602 %                                                                             %
603 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
604 %
605 %  RegisterRLEImage() adds attributes for the RLE image format to
606 %  the list of supported formats.  The attributes include the image format
607 %  tag, a method to read and/or write the format, whether the format
608 %  supports the saving of more than one frame to the same file or blob,
609 %  whether the format supports native in-memory I/O, and a brief
610 %  description of the format.
611 %
612 %  The format of the RegisterRLEImage method is:
613 %
614 %      size_t RegisterRLEImage(void)
615 %
616 */
617 ModuleExport size_t RegisterRLEImage(void)
618 {
619   MagickInfo
620     *entry;
621
622   entry=SetMagickInfo("RLE");
623   entry->decoder=(DecodeImageHandler *) ReadRLEImage;
624   entry->magick=(IsImageFormatHandler *) IsRLE;
625   entry->adjoin=MagickFalse;
626   entry->description=ConstantString("Utah Run length encoded image");
627   entry->module=ConstantString("RLE");
628   (void) RegisterMagickInfo(entry);
629   return(MagickImageCoderSignature);
630 }
631 \f
632 /*
633 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
634 %                                                                             %
635 %                                                                             %
636 %                                                                             %
637 %   U n r e g i s t e r R L E I m a g e                                       %
638 %                                                                             %
639 %                                                                             %
640 %                                                                             %
641 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
642 %
643 %  UnregisterRLEImage() removes format registrations made by the
644 %  RLE module from the list of supported formats.
645 %
646 %  The format of the UnregisterRLEImage method is:
647 %
648 %      UnregisterRLEImage(void)
649 %
650 */
651 ModuleExport void UnregisterRLEImage(void)
652 {
653   (void) UnregisterMagickInfo("RLE");
654 }