2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read URT RLE Image Format %
20 % Copyright 1999-2011 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 "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/static.h"
59 #include "magick/string_.h"
60 #include "magick/module.h"
63 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
71 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
73 % IsRLE() returns MagickTrue if the image format type, identified by the
74 % magick string, is RLE.
76 % The format of the ReadRLEImage method is:
78 % MagickBooleanType IsRLE(const unsigned char *magick,const size_t length)
80 % A description of each parameter follows:
82 % o magick: compare image format pattern against these bytes.
84 % o length: Specifies the length of the magick string.
88 static MagickBooleanType IsRLE(const unsigned char *magick,const size_t length)
92 if (memcmp(magick,"\122\314",2) == 0)
98 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
102 % R e a d R L E I m a g e %
106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
108 % ReadRLEImage() reads a run-length encoded Utah Raster Toolkit
109 % image file and returns it. It allocates the memory necessary for the new
110 % Image structure and returns a pointer to the new image.
112 % The format of the ReadRLEImage method is:
114 % Image *ReadRLEImage(const ImageInfo *image_info,ExceptionInfo *exception)
116 % A description of each parameter follows:
118 % o image_info: the image info.
120 % o exception: return any errors or warnings in this structure.
124 static Image *ReadRLEImage(const ImageInfo *image_info,ExceptionInfo *exception)
126 #define SkipLinesOp 0x01
127 #define SetColorOp 0x02
128 #define SkipPixelsOp 0x03
129 #define ByteDataOp 0x05
130 #define RunDataOp 0x06
162 register unsigned char
177 background_color[256],
186 assert(image_info != (const ImageInfo *) NULL);
187 assert(image_info->signature == MagickSignature);
188 if (image_info->debug != MagickFalse)
189 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
190 image_info->filename);
191 assert(exception != (ExceptionInfo *) NULL);
192 assert(exception->signature == MagickSignature);
193 image=AcquireImage(image_info);
194 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
195 if (status == MagickFalse)
197 image=DestroyImageList(image);
198 return((Image *) NULL);
201 Determine if this a RLE file.
203 count=ReadBlob(image,2,(unsigned char *) magick);
204 if ((count == 0) || (memcmp(magick,"\122\314",2) != 0))
205 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
211 (void) ReadBlobLSBShort(image);
212 (void) ReadBlobLSBShort(image);
213 image->columns=ReadBlobLSBShort(image);
214 image->rows=ReadBlobLSBShort(image);
215 flags=(MagickStatusType) ReadBlobByte(image);
216 image->matte=flags & 0x04 ? MagickTrue : MagickFalse;
217 number_planes=1UL*ReadBlobByte(image);
218 bits_per_pixel=1UL*ReadBlobByte(image);
219 number_colormaps=1UL*ReadBlobByte(image);
221 map_length=one << ReadBlobByte(image);
222 if ((number_planes == 0) || (number_planes == 2) || (bits_per_pixel != 8) ||
223 (image->columns == 0))
224 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
228 No background color-- initialize to black.
230 for (i=0; i < (ssize_t) number_planes; i++)
231 background_color[i]=0;
232 (void) ReadBlobByte(image);
237 Initialize background color.
240 for (i=0; i < (ssize_t) number_planes; i++)
241 *p++=(unsigned char) ReadBlobByte(image);
243 if ((number_planes & 0x01) == 0)
244 (void) ReadBlobByte(image);
245 colormap=(unsigned char *) NULL;
246 if (number_colormaps != 0)
249 Read image colormaps.
251 colormap=(unsigned char *) AcquireQuantumMemory(number_colormaps,
252 map_length*sizeof(*colormap));
253 if (colormap == (unsigned char *) NULL)
254 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
256 for (i=0; i < (ssize_t) number_colormaps; i++)
257 for (x=0; x < (ssize_t) map_length; x++)
258 *p++=(unsigned char) ScaleShortToQuantum(ReadBlobLSBShort(image));
260 if ((flags & 0x08) != 0)
271 length=ReadBlobLSBShort(image);
274 comment=(char *) AcquireQuantumMemory(length,sizeof(*comment));
275 if (comment == (char *) NULL)
276 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
277 count=ReadBlob(image,length-1,(unsigned char *) comment);
278 comment[length-1]='\0';
279 (void) SetImageProperty(image,"comment",comment);
280 comment=DestroyString(comment);
281 if ((length & 0x01) == 0)
282 (void) ReadBlobByte(image);
285 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
286 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
291 if (image->matte != MagickFalse)
293 number_pixels=(MagickSizeType) image->columns*image->rows;
294 if ((number_pixels*number_planes) != (size_t) (number_pixels*number_planes))
295 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
296 rle_pixels=(unsigned char *) AcquireQuantumMemory(image->columns,
297 image->rows*number_planes*sizeof(*rle_pixels));
298 if (rle_pixels == (unsigned char *) NULL)
299 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
300 if ((flags & 0x01) && !(flags & 0x02))
306 Set background color.
309 for (i=0; i < (ssize_t) number_pixels; i++)
311 if (image->matte == MagickFalse)
312 for (j=0; j < (ssize_t) number_planes; j++)
313 *p++=background_color[j];
316 for (j=0; j < (ssize_t) (number_planes-1); j++)
317 *p++=background_color[j];
318 *p++=0; /* initialize matte channel */
323 Read runlength-encoded image.
328 opcode=ReadBlobByte(image);
331 switch (opcode & 0x3f)
335 operand=ReadBlobByte(image);
337 operand=(int) ReadBlobLSBShort(image);
344 operand=ReadBlobByte(image);
345 plane=(unsigned char) operand;
347 plane=(unsigned char) (number_planes-1);
353 operand=ReadBlobByte(image);
355 operand=(int) ReadBlobLSBShort(image);
361 operand=ReadBlobByte(image);
363 operand=(int) ReadBlobLSBShort(image);
364 p=rle_pixels+((image->rows-y-1)*image->columns*number_planes)+
365 x*number_planes+plane;
367 for (i=0; i < (ssize_t) operand; i++)
369 pixel=(unsigned char) ReadBlobByte(image);
370 if ((y < (ssize_t) image->rows) &&
371 ((x+i) < (ssize_t) image->columns))
376 (void) ReadBlobByte(image);
382 operand=ReadBlobByte(image);
384 operand=(int) ReadBlobLSBShort(image);
385 pixel=(unsigned char) ReadBlobByte(image);
386 (void) ReadBlobByte(image);
388 p=rle_pixels+((image->rows-y-1)*image->columns*number_planes)+
389 x*number_planes+plane;
390 for (i=0; i < (ssize_t) operand; i++)
392 if ((y < (ssize_t) image->rows) &&
393 ((x+i) < (ssize_t) image->columns))
403 opcode=ReadBlobByte(image);
404 } while (((opcode & 0x3f) != EOFOp) && (opcode != EOF));
405 if (number_colormaps != 0)
411 Apply colormap affineation to image.
413 mask=(MagickStatusType) (map_length-1);
415 if (number_colormaps == 1)
416 for (i=0; i < (ssize_t) number_pixels; i++)
418 *p=colormap[*p & mask];
422 if ((number_planes >= 3) && (number_colormaps >= 3))
423 for (i=0; i < (ssize_t) number_pixels; i++)
424 for (x=0; x < (ssize_t) number_planes; x++)
426 *p=colormap[x*map_length+(*p & mask)];
431 Initialize image structure.
433 if (number_planes >= 3)
436 Convert raster image to DirectClass pixel packets.
439 for (y=0; y < (ssize_t) image->rows; y++)
441 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
442 if (q == (PixelPacket *) NULL)
444 for (x=0; x < (ssize_t) image->columns; x++)
446 SetRedPixelComponent(q,ScaleCharToQuantum(*p++));
447 SetGreenPixelComponent(q,ScaleCharToQuantum(*p++));
448 SetBluePixelComponent(q,ScaleCharToQuantum(*p++));
449 if (image->matte != MagickFalse)
450 SetOpacityPixelComponent(q,QuantumRange-ScaleCharToQuantum(*p++));
453 if (SyncAuthenticPixels(image,exception) == MagickFalse)
455 if (image->previous == (Image *) NULL)
457 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
459 if (status == MagickFalse)
469 if (number_colormaps == 0)
471 if (AcquireImageColormap(image,map_length) == MagickFalse)
472 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
474 if (number_colormaps == 1)
475 for (i=0; i < (ssize_t) image->colors; i++)
480 image->colormap[i].red=ScaleCharToQuantum((unsigned char) i);
481 image->colormap[i].green=ScaleCharToQuantum((unsigned char) i);
482 image->colormap[i].blue=ScaleCharToQuantum((unsigned char) i);
485 if (number_colormaps > 1)
486 for (i=0; i < (ssize_t) image->colors; i++)
488 image->colormap[i].red=ScaleCharToQuantum(*p);
489 image->colormap[i].green=ScaleCharToQuantum(*(p+map_length));
490 image->colormap[i].blue=ScaleCharToQuantum(*(p+map_length*2));
494 if (image->matte == MagickFalse)
497 Convert raster image to PseudoClass pixel packets.
499 for (y=0; y < (ssize_t) image->rows; y++)
501 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
502 if (q == (PixelPacket *) NULL)
504 indexes=GetAuthenticIndexQueue(image);
505 for (x=0; x < (ssize_t) image->columns; x++)
506 SetIndexPixelComponent(indexes+x,*p++);
507 if (SyncAuthenticPixels(image,exception) == MagickFalse)
509 if (image->previous == (Image *) NULL)
511 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
513 if (status == MagickFalse)
517 (void) SyncImage(image);
522 Image has a matte channel-- promote to DirectClass.
524 for (y=0; y < (ssize_t) image->rows; y++)
526 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
527 if (q == (PixelPacket *) NULL)
529 for (x=0; x < (ssize_t) image->columns; x++)
531 SetRedPixelComponenet(q,image->colormap[*p++].red);
532 SetGreenPixelComponenet(q,image->colormap[*p++].green);
533 SetBluePixelComponenet(q,image->colormap[*p++].blue);
534 SetOpacityPixelComponent(q,QuantumRange-
535 ScaleCharToQuantum(*p++));
538 if (SyncAuthenticPixels(image,exception) == MagickFalse)
540 if (image->previous == (Image *) NULL)
542 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
544 if (status == MagickFalse)
548 image->colormap=(PixelPacket *)
549 RelinquishMagickMemory(image->colormap);
550 image->storage_class=DirectClass;
554 if (number_colormaps != 0)
555 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
556 rle_pixels=(unsigned char *) RelinquishMagickMemory(rle_pixels);
557 if (EOFBlob(image) != MagickFalse)
559 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
564 Proceed to next image.
566 if (image_info->number_scenes != 0)
567 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
569 (void) ReadBlobByte(image);
570 count=ReadBlob(image,2,(unsigned char *) magick);
571 if ((count != 0) && (memcmp(magick,"\122\314",2) == 0))
574 Allocate next image structure.
576 AcquireNextImage(image_info,image);
577 if (GetNextImageInList(image) == (Image *) NULL)
579 image=DestroyImageList(image);
580 return((Image *) NULL);
582 image=SyncNextImageInList(image);
583 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
585 if (status == MagickFalse)
588 } while ((count != 0) && (memcmp(magick,"\122\314",2) == 0));
589 (void) CloseBlob(image);
590 return(GetFirstImageInList(image));
594 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
598 % R e g i s t e r R L E I m a g e %
602 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
604 % RegisterRLEImage() adds attributes for the RLE image format to
605 % the list of supported formats. The attributes include the image format
606 % tag, a method to read and/or write the format, whether the format
607 % supports the saving of more than one frame to the same file or blob,
608 % whether the format supports native in-memory I/O, and a brief
609 % description of the format.
611 % The format of the RegisterRLEImage method is:
613 % size_t RegisterRLEImage(void)
616 ModuleExport size_t RegisterRLEImage(void)
621 entry=SetMagickInfo("RLE");
622 entry->decoder=(DecodeImageHandler *) ReadRLEImage;
623 entry->magick=(IsImageFormatHandler *) IsRLE;
624 entry->adjoin=MagickFalse;
625 entry->description=ConstantString("Utah Run length encoded image");
626 entry->module=ConstantString("RLE");
627 (void) RegisterMagickInfo(entry);
628 return(MagickImageCoderSignature);
632 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
636 % U n r e g i s t e r R L E I m a g e %
640 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
642 % UnregisterRLEImage() removes format registrations made by the
643 % RLE module from the list of supported formats.
645 % The format of the UnregisterRLEImage method is:
647 % UnregisterRLEImage(void)
650 ModuleExport void UnregisterRLEImage(void)
652 (void) UnregisterMagickInfo("RLE");