2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read URT RLE Image Format %
20 % Copyright 1999-2010 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
165 register unsigned char
172 background_color[256],
188 assert(image_info != (const ImageInfo *) NULL);
189 assert(image_info->signature == MagickSignature);
190 if (image_info->debug != MagickFalse)
191 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
192 image_info->filename);
193 assert(exception != (ExceptionInfo *) NULL);
194 assert(exception->signature == MagickSignature);
195 image=AcquireImage(image_info);
196 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
197 if (status == MagickFalse)
199 image=DestroyImageList(image);
200 return((Image *) NULL);
203 Determine if this a RLE file.
205 count=ReadBlob(image,2,(unsigned char *) magick);
206 if ((count == 0) || (memcmp(magick,"\122\314",2) != 0))
207 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
213 (void) ReadBlobLSBShort(image);
214 (void) ReadBlobLSBShort(image);
215 image->columns=ReadBlobLSBShort(image);
216 image->rows=ReadBlobLSBShort(image);
217 flags=(MagickStatusType) ReadBlobByte(image);
218 image->matte=flags & 0x04 ? MagickTrue : MagickFalse;
219 number_planes=1UL*ReadBlobByte(image);
220 bits_per_pixel=1UL*ReadBlobByte(image);
221 number_colormaps=1UL*ReadBlobByte(image);
223 map_length=one << ReadBlobByte(image);
224 if ((number_planes == 0) || (number_planes == 2) || (bits_per_pixel != 8) ||
225 (image->columns == 0))
226 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
230 No background color-- initialize to black.
232 for (i=0; i < (ssize_t) number_planes; i++)
233 background_color[i]=0;
234 (void) ReadBlobByte(image);
239 Initialize background color.
242 for (i=0; i < (ssize_t) number_planes; i++)
243 *p++=(unsigned char) ReadBlobByte(image);
245 if ((number_planes & 0x01) == 0)
246 (void) ReadBlobByte(image);
247 colormap=(unsigned char *) NULL;
248 if (number_colormaps != 0)
251 Read image colormaps.
253 colormap=(unsigned char *) AcquireQuantumMemory(number_colormaps,
254 map_length*sizeof(*colormap));
255 if (colormap == (unsigned char *) NULL)
256 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
258 for (i=0; i < (ssize_t) number_colormaps; i++)
259 for (x=0; x < (ssize_t) map_length; x++)
260 *p++=(unsigned char) ScaleShortToQuantum(ReadBlobLSBShort(image));
262 if ((flags & 0x08) != 0)
273 length=ReadBlobLSBShort(image);
276 comment=(char *) AcquireQuantumMemory(length,sizeof(*comment));
277 if (comment == (char *) NULL)
278 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
279 count=ReadBlob(image,length-1,(unsigned char *) comment);
280 comment[length-1]='\0';
281 (void) SetImageProperty(image,"comment",comment);
282 comment=DestroyString(comment);
283 if ((length & 0x01) == 0)
284 (void) ReadBlobByte(image);
287 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
288 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
293 if (image->matte != MagickFalse)
295 number_pixels=(MagickSizeType) image->columns*image->rows;
296 if ((number_pixels*number_planes) != (size_t) (number_pixels*number_planes))
297 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
298 rle_pixels=(unsigned char *) AcquireQuantumMemory(image->columns,
299 image->rows*number_planes*sizeof(*rle_pixels));
300 if (rle_pixels == (unsigned char *) NULL)
301 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
302 if ((flags & 0x01) && !(flags & 0x02))
308 Set background color.
311 for (i=0; i < (ssize_t) number_pixels; i++)
313 if (image->matte == MagickFalse)
314 for (j=0; j < (ssize_t) number_planes; j++)
315 *p++=background_color[j];
318 for (j=0; j < (ssize_t) (number_planes-1); j++)
319 *p++=background_color[j];
320 *p++=0; /* initialize matte channel */
325 Read runlength-encoded image.
330 opcode=ReadBlobByte(image);
333 switch (opcode & 0x3f)
337 operand=ReadBlobByte(image);
339 operand=(int) ReadBlobLSBShort(image);
346 operand=ReadBlobByte(image);
347 plane=(unsigned char) operand;
349 plane=(unsigned char) (number_planes-1);
355 operand=ReadBlobByte(image);
357 operand=(int) ReadBlobLSBShort(image);
363 operand=ReadBlobByte(image);
365 operand=(int) ReadBlobLSBShort(image);
366 p=rle_pixels+((image->rows-y-1)*image->columns*number_planes)+
367 x*number_planes+plane;
369 for (i=0; i < (ssize_t) operand; i++)
371 pixel=(unsigned char) ReadBlobByte(image);
372 if ((y < (ssize_t) image->rows) && ((x+i) < (ssize_t) image->columns))
377 (void) ReadBlobByte(image);
383 operand=ReadBlobByte(image);
385 operand=(int) ReadBlobLSBShort(image);
386 pixel=(unsigned char) ReadBlobByte(image);
387 (void) ReadBlobByte(image);
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++)
393 if ((y < (ssize_t) image->rows) && ((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 q->red=ScaleCharToQuantum(*p++);
447 q->green=ScaleCharToQuantum(*p++);
448 q->blue=ScaleCharToQuantum(*p++);
449 if (image->matte != MagickFalse)
450 q->opacity=(Quantum) (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 indexes[x]=(IndexPacket) (*p++);
507 if (SyncAuthenticPixels(image,exception) == MagickFalse)
509 if (image->previous == (Image *) NULL)
511 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
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 q->red=image->colormap[*p++].red;
532 q->green=image->colormap[*p++].green;
533 q->blue=image->colormap[*p++].blue;
534 q->opacity=(Quantum) (QuantumRange-ScaleCharToQuantum(*p++));
537 if (SyncAuthenticPixels(image,exception) == MagickFalse)
539 if (image->previous == (Image *) NULL)
541 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
543 if (status == MagickFalse)
547 image->colormap=(PixelPacket *)
548 RelinquishMagickMemory(image->colormap);
549 image->storage_class=DirectClass;
553 if (number_colormaps != 0)
554 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
555 rle_pixels=(unsigned char *) RelinquishMagickMemory(rle_pixels);
556 if (EOFBlob(image) != MagickFalse)
558 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
563 Proceed to next image.
565 if (image_info->number_scenes != 0)
566 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
568 (void) ReadBlobByte(image);
569 count=ReadBlob(image,2,(unsigned char *) magick);
570 if ((count != 0) && (memcmp(magick,"\122\314",2) == 0))
573 Allocate next image structure.
575 AcquireNextImage(image_info,image);
576 if (GetNextImageInList(image) == (Image *) NULL)
578 image=DestroyImageList(image);
579 return((Image *) NULL);
581 image=SyncNextImageInList(image);
582 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
584 if (status == MagickFalse)
587 } while ((count != 0) && (memcmp(magick,"\122\314",2) == 0));
588 (void) CloseBlob(image);
589 return(GetFirstImageInList(image));
593 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
597 % R e g i s t e r R L E I m a g e %
601 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
603 % RegisterRLEImage() adds attributes for the RLE image format to
604 % the list of supported formats. The attributes include the image format
605 % tag, a method to read and/or write the format, whether the format
606 % supports the saving of more than one frame to the same file or blob,
607 % whether the format supports native in-memory I/O, and a brief
608 % description of the format.
610 % The format of the RegisterRLEImage method is:
612 % size_t RegisterRLEImage(void)
615 ModuleExport size_t RegisterRLEImage(void)
620 entry=SetMagickInfo("RLE");
621 entry->decoder=(DecodeImageHandler *) ReadRLEImage;
622 entry->magick=(IsImageFormatHandler *) IsRLE;
623 entry->adjoin=MagickFalse;
624 entry->description=ConstantString("Utah Run length encoded image");
625 entry->module=ConstantString("RLE");
626 (void) RegisterMagickInfo(entry);
627 return(MagickImageCoderSignature);
631 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
635 % U n r e g i s t e r R L E I m a g e %
639 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
641 % UnregisterRLEImage() removes format registrations made by the
642 % RLE module from the list of supported formats.
644 % The format of the UnregisterRLEImage method is:
646 % UnregisterRLEImage(void)
649 ModuleExport void UnregisterRLEImage(void)
651 (void) UnregisterMagickInfo("RLE");