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],
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)
198 image=DestroyImageList(image);
199 return((Image *) NULL);
202 Determine if this a RLE file.
204 count=ReadBlob(image,2,(unsigned char *) magick);
205 if ((count == 0) || (memcmp(magick,"\122\314",2) != 0))
206 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
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 map_length=1UL << 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 < (long) number_planes; i++)
231 background_color[i]=0;
232 (void) ReadBlobByte(image);
237 Initialize background color.
240 for (i=0; i < (long) 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 < (long) number_colormaps; i++)
257 for (x=0; x < (long) 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 < (long) number_pixels; i++)
311 if (image->matte == MagickFalse)
312 for (j=0; j < (long) number_planes; j++)
313 *p++=background_color[j];
316 for (j=0; j < (long) (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 < (long) operand; i++)
369 pixel=(unsigned char) ReadBlobByte(image);
370 if ((y < (long) image->rows) && ((x+i) < (long) image->columns))
375 (void) ReadBlobByte(image);
381 operand=ReadBlobByte(image);
383 operand=(int) ReadBlobLSBShort(image);
384 pixel=(unsigned char) ReadBlobByte(image);
385 (void) ReadBlobByte(image);
387 p=rle_pixels+((image->rows-y-1)*image->columns*number_planes)+
388 x*number_planes+plane;
389 for (i=0; i < (long) operand; i++)
391 if ((y < (long) image->rows) && ((x+i) < (long) image->columns))
401 opcode=ReadBlobByte(image);
402 } while (((opcode & 0x3f) != EOFOp) && (opcode != EOF));
403 if (number_colormaps != 0)
409 Apply colormap affineation to image.
411 mask=(MagickStatusType) (map_length-1);
413 if (number_colormaps == 1)
414 for (i=0; i < (long) number_pixels; i++)
416 *p=colormap[*p & mask];
420 if ((number_planes >= 3) && (number_colormaps >= 3))
421 for (i=0; i < (long) number_pixels; i++)
422 for (x=0; x < (long) number_planes; x++)
424 *p=colormap[x*map_length+(*p & mask)];
429 Initialize image structure.
431 if (number_planes >= 3)
434 Convert raster image to DirectClass pixel packets.
437 for (y=0; y < (long) image->rows; y++)
439 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
440 if (q == (PixelPacket *) NULL)
442 for (x=0; x < (long) image->columns; x++)
444 q->red=ScaleCharToQuantum(*p++);
445 q->green=ScaleCharToQuantum(*p++);
446 q->blue=ScaleCharToQuantum(*p++);
447 if (image->matte != MagickFalse)
448 q->opacity=(Quantum) (QuantumRange-ScaleCharToQuantum(*p++));
451 if (SyncAuthenticPixels(image,exception) == MagickFalse)
453 if (image->previous == (Image *) NULL)
455 status=SetImageProgress(image,LoadImageTag,y,image->rows);
456 if (status == MagickFalse)
466 if (number_colormaps == 0)
468 if (AcquireImageColormap(image,map_length) == MagickFalse)
469 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
471 if (number_colormaps == 1)
472 for (i=0; i < (long) image->colors; i++)
477 image->colormap[i].red=ScaleCharToQuantum((unsigned char) i);
478 image->colormap[i].green=ScaleCharToQuantum((unsigned char) i);
479 image->colormap[i].blue=ScaleCharToQuantum((unsigned char) i);
482 if (number_colormaps > 1)
483 for (i=0; i < (long) image->colors; i++)
485 image->colormap[i].red=ScaleCharToQuantum(*p);
486 image->colormap[i].green=ScaleCharToQuantum(*(p+map_length));
487 image->colormap[i].blue=ScaleCharToQuantum(*(p+map_length*2));
491 if (image->matte == MagickFalse)
494 Convert raster image to PseudoClass pixel packets.
496 for (y=0; y < (long) image->rows; y++)
498 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
499 if (q == (PixelPacket *) NULL)
501 indexes=GetAuthenticIndexQueue(image);
502 for (x=0; x < (long) image->columns; x++)
503 indexes[x]=(IndexPacket) (*p++);
504 if (SyncAuthenticPixels(image,exception) == MagickFalse)
506 if (image->previous == (Image *) NULL)
508 status=SetImageProgress(image,LoadImageTag,y,image->rows);
509 if (status == MagickFalse)
513 (void) SyncImage(image);
518 Image has a matte channel-- promote to DirectClass.
520 for (y=0; y < (long) image->rows; y++)
522 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
523 if (q == (PixelPacket *) NULL)
525 for (x=0; x < (long) image->columns; x++)
527 q->red=image->colormap[*p++].red;
528 q->green=image->colormap[*p++].green;
529 q->blue=image->colormap[*p++].blue;
530 q->opacity=(Quantum) (QuantumRange-ScaleCharToQuantum(*p++));
533 if (SyncAuthenticPixels(image,exception) == MagickFalse)
535 if (image->previous == (Image *) NULL)
537 status=SetImageProgress(image,LoadImageTag,y,image->rows);
538 if (status == MagickFalse)
542 image->colormap=(PixelPacket *)
543 RelinquishMagickMemory(image->colormap);
544 image->storage_class=DirectClass;
548 if (number_colormaps != 0)
549 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
550 rle_pixels=(unsigned char *) RelinquishMagickMemory(rle_pixels);
551 if (EOFBlob(image) != MagickFalse)
553 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
558 Proceed to next image.
560 if (image_info->number_scenes != 0)
561 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
563 (void) ReadBlobByte(image);
564 count=ReadBlob(image,2,(unsigned char *) magick);
565 if ((count != 0) && (memcmp(magick,"\122\314",2) == 0))
568 Allocate next image structure.
570 AcquireNextImage(image_info,image);
571 if (GetNextImageInList(image) == (Image *) NULL)
573 image=DestroyImageList(image);
574 return((Image *) NULL);
576 image=SyncNextImageInList(image);
577 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
579 if (status == MagickFalse)
582 } while ((count != 0) && (memcmp(magick,"\122\314",2) == 0));
583 (void) CloseBlob(image);
584 return(GetFirstImageInList(image));
588 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
592 % R e g i s t e r R L E I m a g e %
596 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
598 % RegisterRLEImage() adds attributes for the RLE image format to
599 % the list of supported formats. The attributes include the image format
600 % tag, a method to read and/or write the format, whether the format
601 % supports the saving of more than one frame to the same file or blob,
602 % whether the format supports native in-memory I/O, and a brief
603 % description of the format.
605 % The format of the RegisterRLEImage method is:
607 % unsigned long RegisterRLEImage(void)
610 ModuleExport unsigned long RegisterRLEImage(void)
615 entry=SetMagickInfo("RLE");
616 entry->decoder=(DecodeImageHandler *) ReadRLEImage;
617 entry->magick=(IsImageFormatHandler *) IsRLE;
618 entry->adjoin=MagickFalse;
619 entry->description=ConstantString("Utah Run length encoded image");
620 entry->module=ConstantString("RLE");
621 (void) RegisterMagickInfo(entry);
622 return(MagickImageCoderSignature);
626 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
630 % U n r e g i s t e r R L E I m a g e %
634 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
636 % UnregisterRLEImage() removes format registrations made by the
637 % RLE module from the list of supported formats.
639 % The format of the UnregisterRLEImage method is:
641 % UnregisterRLEImage(void)
644 ModuleExport void UnregisterRLEImage(void)
646 (void) UnregisterMagickInfo("RLE");