2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read URT RLE Image Format %
20 % Copyright 1999-2017 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
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. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
42 #include "MagickCore/studio.h"
43 #include "MagickCore/blob.h"
44 #include "MagickCore/blob-private.h"
45 #include "MagickCore/cache.h"
46 #include "MagickCore/colormap.h"
47 #include "MagickCore/colormap-private.h"
48 #include "MagickCore/exception.h"
49 #include "MagickCore/exception-private.h"
50 #include "MagickCore/image.h"
51 #include "MagickCore/image-private.h"
52 #include "MagickCore/list.h"
53 #include "MagickCore/magick.h"
54 #include "MagickCore/memory_.h"
55 #include "MagickCore/monitor.h"
56 #include "MagickCore/monitor-private.h"
57 #include "MagickCore/pixel-accessor.h"
58 #include "MagickCore/pixel.h"
59 #include "MagickCore/property.h"
60 #include "MagickCore/quantum-private.h"
61 #include "MagickCore/static.h"
62 #include "MagickCore/string_.h"
63 #include "MagickCore/module.h"
66 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
74 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
76 % IsRLE() returns MagickTrue if the image format type, identified by the
77 % magick string, is RLE.
79 % The format of the ReadRLEImage method is:
81 % MagickBooleanType IsRLE(const unsigned char *magick,const size_t length)
83 % A description of each parameter follows:
85 % o magick: compare image format pattern against these bytes.
87 % o length: Specifies the length of the magick string.
91 static MagickBooleanType IsRLE(const unsigned char *magick,const size_t length)
95 if (memcmp(magick,"\122\314",2) == 0)
101 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
105 % R e a d R L E I m a g e %
109 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
111 % ReadRLEImage() reads a run-length encoded Utah Raster Toolkit
112 % image file and returns it. It allocates the memory necessary for the new
113 % Image structure and returns a pointer to the new image.
115 % The format of the ReadRLEImage method is:
117 % Image *ReadRLEImage(const ImageInfo *image_info,ExceptionInfo *exception)
119 % A description of each parameter follows:
121 % o image_info: the image info.
123 % o exception: return any errors or warnings in this structure.
127 static Image *ReadRLEImage(const ImageInfo *image_info,ExceptionInfo *exception)
129 #define SkipLinesOp 0x01
130 #define SetColorOp 0x02
131 #define SkipPixelsOp 0x03
132 #define ByteDataOp 0x05
133 #define RunDataOp 0x06
168 register unsigned char
176 number_planes_filled,
186 background_color[256],
195 assert(image_info != (const ImageInfo *) NULL);
196 assert(image_info->signature == MagickCoreSignature);
197 if (image_info->debug != MagickFalse)
198 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
199 image_info->filename);
200 assert(exception != (ExceptionInfo *) NULL);
201 assert(exception->signature == MagickCoreSignature);
202 image=AcquireImage(image_info,exception);
203 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
204 if (status == MagickFalse)
205 return(DestroyImageList(image));
207 Determine if this a RLE file.
209 count=ReadBlob(image,2,(unsigned char *) magick);
210 if ((count != 2) || (memcmp(magick,"\122\314",2) != 0))
211 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
217 image->page.x=ReadBlobLSBShort(image);
218 image->page.y=ReadBlobLSBShort(image);
219 image->columns=ReadBlobLSBShort(image);
220 image->rows=ReadBlobLSBShort(image);
221 flags=(MagickStatusType) ReadBlobByte(image);
222 image->alpha_trait=flags & 0x04 ? BlendPixelTrait : UndefinedPixelTrait;
223 number_planes=(size_t) ReadBlobByte(image);
224 bits_per_pixel=(size_t) ReadBlobByte(image);
225 number_colormaps=(size_t) ReadBlobByte(image);
226 map_length=(unsigned char) ReadBlobByte(image);
227 if (map_length >= 22)
228 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
230 map_length=one << map_length;
231 if ((number_planes == 0) || (number_planes == 2) ||
232 ((flags & 0x04) && (number_colormaps > 254)) || (bits_per_pixel != 8) ||
233 (image->columns == 0))
234 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
238 No background color-- initialize to black.
240 for (i=0; i < (ssize_t) number_planes; i++)
241 background_color[i]=0;
242 (void) ReadBlobByte(image);
247 Initialize background color.
250 for (i=0; i < (ssize_t) number_planes; i++)
251 *p++=(unsigned char) ReadBlobByte(image);
253 if ((number_planes & 0x01) == 0)
254 (void) ReadBlobByte(image);
255 if (EOFBlob(image) != MagickFalse)
257 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
261 colormap=(unsigned char *) NULL;
262 if (number_colormaps != 0)
265 Read image colormaps.
267 colormap=(unsigned char *) AcquireQuantumMemory(number_colormaps,
268 3*map_length*sizeof(*colormap));
269 if (colormap == (unsigned char *) NULL)
270 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
272 for (i=0; i < (ssize_t) number_colormaps; i++)
273 for (x=0; x < (ssize_t) map_length; x++)
274 *p++=(unsigned char) ScaleShortToQuantum(ReadBlobLSBShort(image));
276 if ((flags & 0x08) != 0)
287 length=ReadBlobLSBShort(image);
290 comment=(char *) AcquireQuantumMemory(length,sizeof(*comment));
291 if (comment == (char *) NULL)
292 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
293 count=ReadBlob(image,length-1,(unsigned char *) comment);
294 comment[length-1]='\0';
295 (void) SetImageProperty(image,"comment",comment,exception);
296 comment=DestroyString(comment);
297 if ((length & 0x01) == 0)
298 (void) ReadBlobByte(image);
301 if (EOFBlob(image) != MagickFalse)
303 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
307 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
308 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
310 status=SetImageExtent(image,image->columns,image->rows,exception);
311 if (status == MagickFalse)
312 return(DestroyImageList(image));
316 if (image->alpha_trait != UndefinedPixelTrait)
318 number_pixels=(MagickSizeType) image->columns*image->rows;
319 number_planes_filled=(number_planes % 2 == 0) ? number_planes :
321 if ((number_pixels*number_planes_filled) != (size_t) (number_pixels*
322 number_planes_filled))
323 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
324 pixel_info=AcquireVirtualMemory(image->columns,image->rows*
325 MagickMax(number_planes_filled,4)*sizeof(*pixels));
326 if (pixel_info == (MemoryInfo *) NULL)
327 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
328 pixel_info_length=image->columns*image->rows*
329 MagickMax(number_planes_filled,4);
330 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
331 if ((flags & 0x01) && !(flags & 0x02))
337 Set background color.
340 for (i=0; i < (ssize_t) number_pixels; i++)
342 if (image->alpha_trait == UndefinedPixelTrait)
343 for (j=0; j < (ssize_t) number_planes; j++)
344 *p++=background_color[j];
347 for (j=0; j < (ssize_t) (number_planes-1); j++)
348 *p++=background_color[j];
349 *p++=0; /* initialize matte channel */
354 Read runlength-encoded image.
359 opcode=ReadBlobByte(image);
362 switch (opcode & 0x3f)
366 operand=ReadBlobByte(image);
368 operand=ReadBlobLSBSignedShort(image);
375 operand=ReadBlobByte(image);
376 plane=(unsigned char) operand;
378 plane=(unsigned char) (number_planes-1);
384 operand=ReadBlobByte(image);
386 operand=ReadBlobLSBSignedShort(image);
392 operand=ReadBlobByte(image);
394 operand=ReadBlobLSBSignedShort(image);
395 offset=((image->rows-y-1)*image->columns*number_planes)+x*
399 (offset+((size_t) operand*number_planes) > pixel_info_length))
401 if (number_colormaps != 0)
402 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
403 pixel_info=RelinquishVirtualMemory(pixel_info);
404 ThrowReaderException(CorruptImageError,"UnableToReadImageData");
407 for (i=0; i < (ssize_t) operand; i++)
409 pixel=(unsigned char) ReadBlobByte(image);
410 if ((y < (ssize_t) image->rows) &&
411 ((x+i) < (ssize_t) image->columns))
416 (void) ReadBlobByte(image);
422 operand=ReadBlobByte(image);
424 operand=ReadBlobLSBSignedShort(image);
425 pixel=(unsigned char) ReadBlobByte(image);
426 (void) ReadBlobByte(image);
427 offset=((image->rows-y-1)*image->columns*number_planes)+x*
431 (offset+((size_t) operand*number_planes) > pixel_info_length))
433 if (number_colormaps != 0)
434 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
435 pixel_info=RelinquishVirtualMemory(pixel_info);
436 ThrowReaderException(CorruptImageError,"UnableToReadImageData");
439 for (i=0; i < (ssize_t) operand; i++)
441 if ((y < (ssize_t) image->rows) &&
442 ((x+i) < (ssize_t) image->columns))
452 opcode=ReadBlobByte(image);
453 } while (((opcode & 0x3f) != EOFOp) && (opcode != EOF));
454 if (number_colormaps != 0)
460 Apply colormap affineation to image.
462 mask=(MagickStatusType) (map_length-1);
464 x=(ssize_t) number_planes;
465 if (number_colormaps == 1)
466 for (i=0; i < (ssize_t) number_pixels; i++)
468 ValidateColormapValue(image,*p & mask,&index,exception);
469 *p=colormap[(ssize_t) index];
473 if ((number_planes >= 3) && (number_colormaps >= 3))
474 for (i=0; i < (ssize_t) number_pixels; i++)
475 for (x=0; x < (ssize_t) number_planes; x++)
477 ValidateColormapValue(image,(size_t) (x*map_length+
478 (*p & mask)),&index,exception);
479 *p=colormap[(ssize_t) index];
482 if ((i < (ssize_t) number_pixels) || (x < (ssize_t) number_planes))
484 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
485 pixel_info=RelinquishVirtualMemory(pixel_info);
486 ThrowReaderException(CorruptImageError,"UnableToReadImageData");
490 Initialize image structure.
492 if (number_planes >= 3)
495 Convert raster image to DirectClass pixel packets.
498 for (y=0; y < (ssize_t) image->rows; y++)
500 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
501 if (q == (Quantum *) NULL)
503 for (x=0; x < (ssize_t) image->columns; x++)
505 SetPixelRed(image,ScaleCharToQuantum(*p++),q);
506 SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
507 SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
508 if (image->alpha_trait != UndefinedPixelTrait)
509 SetPixelAlpha(image,ScaleCharToQuantum(*p++),q);
510 q+=GetPixelChannels(image);
512 if (SyncAuthenticPixels(image,exception) == MagickFalse)
514 if (image->previous == (Image *) NULL)
516 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
518 if (status == MagickFalse)
528 if (number_colormaps == 0)
530 if (AcquireImageColormap(image,map_length,exception) == MagickFalse)
531 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
533 if (number_colormaps == 1)
534 for (i=0; i < (ssize_t) image->colors; i++)
539 image->colormap[i].red=(MagickRealType)
540 ScaleCharToQuantum((unsigned char) i);
541 image->colormap[i].green=(MagickRealType)
542 ScaleCharToQuantum((unsigned char) i);
543 image->colormap[i].blue=(MagickRealType)
544 ScaleCharToQuantum((unsigned char) i);
547 if (number_colormaps > 1)
548 for (i=0; i < (ssize_t) image->colors; i++)
550 image->colormap[i].red=(MagickRealType)
551 ScaleCharToQuantum(*p);
552 image->colormap[i].green=(MagickRealType)
553 ScaleCharToQuantum(*(p+map_length));
554 image->colormap[i].blue=(MagickRealType)
555 ScaleCharToQuantum(*(p+map_length*2));
559 if (image->alpha_trait == UndefinedPixelTrait)
562 Convert raster image to PseudoClass pixel packets.
564 for (y=0; y < (ssize_t) image->rows; y++)
566 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
567 if (q == (Quantum *) NULL)
569 for (x=0; x < (ssize_t) image->columns; x++)
571 SetPixelIndex(image,*p++,q);
572 q+=GetPixelChannels(image);
574 if (SyncAuthenticPixels(image,exception) == MagickFalse)
576 if (image->previous == (Image *) NULL)
578 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
580 if (status == MagickFalse)
584 (void) SyncImage(image,exception);
589 Image has a matte channel-- promote to DirectClass.
591 for (y=0; y < (ssize_t) image->rows; y++)
593 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
594 if (q == (Quantum *) NULL)
596 for (x=0; x < (ssize_t) image->columns; x++)
598 ValidateColormapValue(image,(ssize_t) *p++,&index,exception);
599 SetPixelRed(image,ClampToQuantum(image->colormap[(ssize_t)
601 ValidateColormapValue(image,(ssize_t) *p++,&index,exception);
602 SetPixelGreen(image,ClampToQuantum(image->colormap[(ssize_t)
604 ValidateColormapValue(image,(ssize_t) *p++,&index,exception);
605 SetPixelBlue(image,ClampToQuantum(image->colormap[(ssize_t)
607 SetPixelAlpha(image,ScaleCharToQuantum(*p++),q);
608 q+=GetPixelChannels(image);
610 if (x < (ssize_t) image->columns)
612 if (SyncAuthenticPixels(image,exception) == MagickFalse)
614 if (image->previous == (Image *) NULL)
616 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
618 if (status == MagickFalse)
622 image->colormap=(PixelInfo *) RelinquishMagickMemory(
624 image->storage_class=DirectClass;
628 if (number_colormaps != 0)
629 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
630 pixel_info=RelinquishVirtualMemory(pixel_info);
631 if (EOFBlob(image) != MagickFalse)
633 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
638 Proceed to next image.
640 if (image_info->number_scenes != 0)
641 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
643 (void) ReadBlobByte(image);
644 count=ReadBlob(image,2,(unsigned char *) magick);
645 if ((count != 0) && (memcmp(magick,"\122\314",2) == 0))
648 Allocate next image structure.
650 AcquireNextImage(image_info,image,exception);
651 if (GetNextImageInList(image) == (Image *) NULL)
653 image=DestroyImageList(image);
654 return((Image *) NULL);
656 image=SyncNextImageInList(image);
657 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
659 if (status == MagickFalse)
662 } while ((count != 0) && (memcmp(magick,"\122\314",2) == 0));
663 (void) CloseBlob(image);
664 return(GetFirstImageInList(image));
668 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
672 % R e g i s t e r R L E I m a g e %
676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
678 % RegisterRLEImage() adds attributes for the RLE image format to
679 % the list of supported formats. The attributes include the image format
680 % tag, a method to read and/or write the format, whether the format
681 % supports the saving of more than one frame to the same file or blob,
682 % whether the format supports native in-memory I/O, and a brief
683 % description of the format.
685 % The format of the RegisterRLEImage method is:
687 % size_t RegisterRLEImage(void)
690 ModuleExport size_t RegisterRLEImage(void)
695 entry=AcquireMagickInfo("RLE","RLE","Utah Run length encoded image");
696 entry->decoder=(DecodeImageHandler *) ReadRLEImage;
697 entry->magick=(IsImageFormatHandler *) IsRLE;
698 entry->flags^=CoderAdjoinFlag;
699 (void) RegisterMagickInfo(entry);
700 return(MagickImageCoderSignature);
704 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
708 % U n r e g i s t e r R L E I m a g e %
712 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
714 % UnregisterRLEImage() removes format registrations made by the
715 % RLE module from the list of supported formats.
717 % The format of the UnregisterRLEImage method is:
719 % UnregisterRLEImage(void)
722 ModuleExport void UnregisterRLEImage(void)
724 (void) UnregisterMagickInfo("RLE");