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/pixel.h"
59 #include "magick/static.h"
60 #include "magick/string_.h"
61 #include "magick/module.h"
64 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
72 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
74 % IsRLE() returns MagickTrue if the image format type, identified by the
75 % magick string, is RLE.
77 % The format of the ReadRLEImage method is:
79 % MagickBooleanType IsRLE(const unsigned char *magick,const size_t length)
81 % A description of each parameter follows:
83 % o magick: compare image format pattern against these bytes.
85 % o length: Specifies the length of the magick string.
89 static MagickBooleanType IsRLE(const unsigned char *magick,const size_t length)
93 if (memcmp(magick,"\122\314",2) == 0)
99 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
103 % R e a d R L E I m a g e %
107 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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.
113 % The format of the ReadRLEImage method is:
115 % Image *ReadRLEImage(const ImageInfo *image_info,ExceptionInfo *exception)
117 % A description of each parameter follows:
119 % o image_info: the image info.
121 % o exception: return any errors or warnings in this structure.
125 static Image *ReadRLEImage(const ImageInfo *image_info,ExceptionInfo *exception)
127 #define SkipLinesOp 0x01
128 #define SetColorOp 0x02
129 #define SkipPixelsOp 0x03
130 #define ByteDataOp 0x05
131 #define RunDataOp 0x06
163 register unsigned char
178 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);
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");
229 No background color-- initialize to black.
231 for (i=0; i < (ssize_t) number_planes; i++)
232 background_color[i]=0;
233 (void) ReadBlobByte(image);
238 Initialize background color.
241 for (i=0; i < (ssize_t) number_planes; i++)
242 *p++=(unsigned char) ReadBlobByte(image);
244 if ((number_planes & 0x01) == 0)
245 (void) ReadBlobByte(image);
246 colormap=(unsigned char *) NULL;
247 if (number_colormaps != 0)
250 Read image colormaps.
252 colormap=(unsigned char *) AcquireQuantumMemory(number_colormaps,
253 map_length*sizeof(*colormap));
254 if (colormap == (unsigned char *) NULL)
255 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
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));
261 if ((flags & 0x08) != 0)
272 length=ReadBlobLSBShort(image);
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);
286 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
287 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
292 if (image->matte != MagickFalse)
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))
307 Set background color.
310 for (i=0; i < (ssize_t) number_pixels; i++)
312 if (image->matte == MagickFalse)
313 for (j=0; j < (ssize_t) number_planes; j++)
314 *p++=background_color[j];
317 for (j=0; j < (ssize_t) (number_planes-1); j++)
318 *p++=background_color[j];
319 *p++=0; /* initialize matte channel */
324 Read runlength-encoded image.
329 opcode=ReadBlobByte(image);
332 switch (opcode & 0x3f)
336 operand=ReadBlobByte(image);
338 operand=(int) ReadBlobLSBShort(image);
345 operand=ReadBlobByte(image);
346 plane=(unsigned char) operand;
348 plane=(unsigned char) (number_planes-1);
354 operand=ReadBlobByte(image);
356 operand=(int) ReadBlobLSBShort(image);
362 operand=ReadBlobByte(image);
364 operand=(int) ReadBlobLSBShort(image);
365 p=rle_pixels+((image->rows-y-1)*image->columns*number_planes)+
366 x*number_planes+plane;
368 for (i=0; i < (ssize_t) operand; i++)
370 pixel=(unsigned char) ReadBlobByte(image);
371 if ((y < (ssize_t) image->rows) &&
372 ((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) &&
394 ((x+i) < (ssize_t) image->columns))
404 opcode=ReadBlobByte(image);
405 } while (((opcode & 0x3f) != EOFOp) && (opcode != EOF));
406 if (number_colormaps != 0)
412 Apply colormap affineation to image.
414 mask=(MagickStatusType) (map_length-1);
416 if (number_colormaps == 1)
417 for (i=0; i < (ssize_t) number_pixels; i++)
419 *p=colormap[*p & mask];
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++)
427 *p=colormap[x*map_length+(*p & mask)];
432 Initialize image structure.
434 if (number_planes >= 3)
437 Convert raster image to DirectClass pixel packets.
440 for (y=0; y < (ssize_t) image->rows; y++)
442 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
443 if (q == (PixelPacket *) NULL)
445 for (x=0; x < (ssize_t) image->columns; x++)
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++));
454 if (SyncAuthenticPixels(image,exception) == MagickFalse)
456 if (image->previous == (Image *) NULL)
458 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
460 if (status == MagickFalse)
470 if (number_colormaps == 0)
472 if (AcquireImageColormap(image,map_length) == MagickFalse)
473 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
475 if (number_colormaps == 1)
476 for (i=0; i < (ssize_t) image->colors; i++)
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);
486 if (number_colormaps > 1)
487 for (i=0; i < (ssize_t) image->colors; i++)
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));
495 if (image->matte == MagickFalse)
498 Convert raster image to PseudoClass pixel packets.
500 for (y=0; y < (ssize_t) image->rows; y++)
502 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
503 if (q == (PixelPacket *) NULL)
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)
510 if (image->previous == (Image *) NULL)
512 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
514 if (status == MagickFalse)
518 (void) SyncImage(image);
523 Image has a matte channel-- promote to DirectClass.
525 for (y=0; y < (ssize_t) image->rows; y++)
527 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
528 if (q == (PixelPacket *) NULL)
530 for (x=0; x < (ssize_t) image->columns; x++)
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++));
539 if (SyncAuthenticPixels(image,exception) == MagickFalse)
541 if (image->previous == (Image *) NULL)
543 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
545 if (status == MagickFalse)
549 image->colormap=(PixelPacket *)
550 RelinquishMagickMemory(image->colormap);
551 image->storage_class=DirectClass;
555 if (number_colormaps != 0)
556 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
557 rle_pixels=(unsigned char *) RelinquishMagickMemory(rle_pixels);
558 if (EOFBlob(image) != MagickFalse)
560 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
565 Proceed to next image.
567 if (image_info->number_scenes != 0)
568 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
570 (void) ReadBlobByte(image);
571 count=ReadBlob(image,2,(unsigned char *) magick);
572 if ((count != 0) && (memcmp(magick,"\122\314",2) == 0))
575 Allocate next image structure.
577 AcquireNextImage(image_info,image);
578 if (GetNextImageInList(image) == (Image *) NULL)
580 image=DestroyImageList(image);
581 return((Image *) NULL);
583 image=SyncNextImageInList(image);
584 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
586 if (status == MagickFalse)
589 } while ((count != 0) && (memcmp(magick,"\122\314",2) == 0));
590 (void) CloseBlob(image);
591 return(GetFirstImageInList(image));
595 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
599 % R e g i s t e r R L E I m a g e %
603 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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.
612 % The format of the RegisterRLEImage method is:
614 % size_t RegisterRLEImage(void)
617 ModuleExport size_t RegisterRLEImage(void)
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);
633 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
637 % U n r e g i s t e r R L E I m a g e %
641 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
643 % UnregisterRLEImage() removes format registrations made by the
644 % RLE module from the list of supported formats.
646 % The format of the UnregisterRLEImage method is:
648 % UnregisterRLEImage(void)
651 ModuleExport void UnregisterRLEImage(void)
653 (void) UnregisterMagickInfo("RLE");