2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12 % Read DR Halo Image Format %
19 % Permission is hereby granted, free of charge, to any person obtaining a %
20 % copy of this software and associated documentation files ("ImageMagick"), %
21 % to deal in ImageMagick without restriction, including without limitation %
22 % the rights to use, copy, modify, merge, publish, distribute, sublicense, %
23 % and/or sell copies of ImageMagick, and to permit persons to whom the %
24 % ImageMagick is furnished to do so, subject to the following conditions: %
26 % The above copyright notice and this permission notice shall be included in %
27 % all copies or substantial portions of ImageMagick. %
29 % The software is provided "as is", without warranty of any kind, express or %
30 % implied, including but not limited to the warranties of merchantability, %
31 % fitness for a particular purpose and noninfringement. In no event shall %
32 % ImageMagick Studio be liable for any claim, damages or other liability, %
33 % whether in an action of contract, tort or otherwise, arising from, out of %
34 % or in connection with ImageMagick or the use or other dealings in %
37 % Except as contained in this notice, the name of the ImageMagick Studio %
38 % shall not be used in advertising or otherwise to promote the sale, use or %
39 % other dealings in ImageMagick without prior written authorization from the %
40 % ImageMagick Studio. %
42 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
50 #include "magick/studio.h"
51 #include "magick/blob.h"
52 #include "magick/blob-private.h"
53 #include "magick/cache.h"
54 #include "magick/color.h"
55 #include "magick/color-private.h"
56 #include "magick/colormap.h"
57 #include "magick/colormap-private.h"
58 #include "magick/exception.h"
59 #include "magick/exception-private.h"
60 #include "magick/image.h"
61 #include "magick/image-private.h"
62 #include "magick/list.h"
63 #include "magick/magick.h"
64 #include "magick/memory_.h"
65 #include "magick/quantum-private.h"
66 #include "magick/static.h"
67 #include "magick/string_.h"
68 #include "magick/module.h"
69 #include "magick/utility.h"
86 unsigned GraphicsMode;
95 static void InsertRow(ssize_t depth,unsigned char *p,ssize_t y,Image *image)
100 size_t bit; ssize_t x;
101 register PixelPacket *q;
103 register IndexPacket *indexes;
106 index=(IndexPacket) 0;
107 exception=(&image->exception);
110 case 1: /* Convert bitmap scanline. */
112 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
113 if (q == (PixelPacket *) NULL)
115 indexes=GetAuthenticIndexQueue(image);
116 for (x=0; x < ((ssize_t) image->columns-7); x+=8)
118 for (bit=0; bit < 8; bit++)
120 index=(IndexPacket) ((((*p) & (0x80 >> bit)) != 0) ? 0x01 : 0x00);
121 indexes[x+bit]=index;
122 *q++=image->colormap[(ssize_t) index];
126 if ((image->columns % 8) != 0)
128 for (bit=0; bit < (image->columns % 8); bit++)
130 index=(IndexPacket) ((((*p) & (0x80 >> bit)) != 0) ? 0x01 : 0x00);
131 indexes[x+bit]=index;
132 *q++=image->colormap[(ssize_t) index];
136 if (SyncAuthenticPixels(image,exception) == MagickFalse)
140 case 2: /* Convert PseudoColor scanline. */
142 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
143 if (q == (PixelPacket *) NULL)
145 indexes=GetAuthenticIndexQueue(image);
146 for (x=0; x < ((ssize_t) image->columns-1); x+=2)
148 index=ConstrainColormapIndex(image,(*p >> 6) & 0x3);
150 *q++=image->colormap[(ssize_t) index];
151 index=ConstrainColormapIndex(image,(*p >> 4) & 0x3);
153 *q++=image->colormap[(ssize_t) index];
154 index=ConstrainColormapIndex(image,(*p >> 2) & 0x3);
156 *q++=image->colormap[(ssize_t) index];
157 index=ConstrainColormapIndex(image,(*p) & 0x3);
159 *q++=image->colormap[(ssize_t) index];
162 if ((image->columns % 4) != 0)
164 index=ConstrainColormapIndex(image,(*p >> 6) & 0x3);
166 *q++=image->colormap[(ssize_t) index];
167 if ((image->columns % 4) >= 1)
170 index=ConstrainColormapIndex(image,(*p >> 4) & 0x3);
172 *q++=image->colormap[(ssize_t) index];
173 if ((image->columns % 4) >= 2)
176 index=ConstrainColormapIndex(image,(*p >> 2) & 0x3);
178 *q++=image->colormap[(ssize_t) index];
183 if (SyncAuthenticPixels(image,exception) == MagickFalse)
188 case 4: /* Convert PseudoColor scanline. */
190 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
191 if (q == (PixelPacket *) NULL)
193 indexes=GetAuthenticIndexQueue(image);
194 for (x=0; x < ((ssize_t) image->columns-1); x+=2)
196 index=ConstrainColormapIndex(image,(*p >> 4) & 0xf);
198 *q++=image->colormap[(ssize_t) index];
199 index=ConstrainColormapIndex(image,(*p) & 0xf);
201 *q++=image->colormap[(ssize_t) index];
204 if ((image->columns % 2) != 0)
206 index=ConstrainColormapIndex(image,(*p >> 4) & 0xf);
208 *q++=image->colormap[(ssize_t) index];
211 if (SyncAuthenticPixels(image,exception) == MagickFalse)
215 case 8: /* Convert PseudoColor scanline. */
217 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
218 if (q == (PixelPacket *) NULL) break;
219 indexes=GetAuthenticIndexQueue(image);
221 for (x=0; x < (ssize_t) image->columns; x++)
223 index=ConstrainColormapIndex(image,*p);
225 *q++=image->colormap[(ssize_t) index];
228 if (SyncAuthenticPixels(image,exception) == MagickFalse)
237 Compute the number of colors in Grayed R[i]=G[i]=B[i] image
239 static int GetCutColors(Image *image)
255 exception=(&image->exception);
257 scale_intensity=ScaleCharToQuantum(16);
258 for (y=0; y < (ssize_t) image->rows; y++)
260 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
261 for (x=0; x < (ssize_t) image->columns; x++)
263 if (intensity < q->red)
265 if (intensity >= scale_intensity)
270 if (intensity < ScaleCharToQuantum(2))
272 if (intensity < ScaleCharToQuantum(16))
274 return((int) intensity);
278 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
282 % R e a d C U T I m a g e %
286 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
288 % ReadCUTImage() reads an CUT X image file and returns it. It
289 % allocates the memory necessary for the new Image structure and returns a
290 % pointer to the new image.
292 % The format of the ReadCUTImage method is:
294 % Image *ReadCUTImage(const ImageInfo *image_info,ExceptionInfo *exception)
296 % A description of each parameter follows:
298 % o image_info: the image info.
300 % o exception: return any errors or warnings in this structure.
303 static Image *ReadCUTImage(const ImageInfo *image_info,ExceptionInfo *exception)
305 Image *image,*palette;
306 ImageInfo *clone_info;
307 MagickBooleanType status;
313 unsigned char RunCount,RunValue,RunCountMasked;
315 CUTPalHeader PalHeader;
319 unsigned char *BImgBuff=NULL,*ptrB;
328 assert(image_info != (const ImageInfo *) NULL);
329 assert(image_info->signature == MagickSignature);
330 if (image_info->debug != MagickFalse)
331 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
332 image_info->filename);
333 assert(exception != (ExceptionInfo *) NULL);
334 assert(exception->signature == MagickSignature);
335 image=AcquireImage(image_info);
336 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
337 if (status == MagickFalse)
339 image=DestroyImageList(image);
340 return((Image *) NULL);
347 Header.Width=ReadBlobLSBShort(image);
348 Header.Height=ReadBlobLSBShort(image);
349 Header.Reserved=ReadBlobLSBShort(image);
351 if (Header.Width==0 || Header.Height==0 || Header.Reserved!=0)
352 CUT_KO: ThrowReaderException(CorruptImageError,"ImproperImageHeader");
354 /*---This code checks first line of image---*/
355 EncodedByte=ReadBlobLSBShort(image);
356 RunCount=(unsigned char) ReadBlobByte(image);
357 RunCountMasked=RunCount & 0x7F;
359 while((int) RunCountMasked!=0) /*end of line?*/
362 if((int) RunCount<0x80) i=(ssize_t) RunCountMasked;
363 offset=SeekBlob(image,TellBlob(image)+i,SEEK_SET);
365 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
366 if(EOFBlob(image) != MagickFalse) goto CUT_KO; /*wrong data*/
368 ldblk+=(ssize_t) RunCountMasked;
370 RunCount=(unsigned char) ReadBlobByte(image);
371 if(EOFBlob(image) != MagickFalse) goto CUT_KO; /*wrong data: unexpected eof in line*/
372 RunCountMasked=RunCount & 0x7F;
374 if(EncodedByte!=1) goto CUT_KO; /*wrong data: size incorrect*/
375 i=0; /*guess a number of bit planes*/
376 if(ldblk==(int) Header.Width) i=8;
377 if(2*ldblk==(int) Header.Width) i=4;
378 if(8*ldblk==(int) Header.Width) i=1;
379 if(i==0) goto CUT_KO; /*wrong data: incorrect bit planes*/
382 image->columns=Header.Width;
383 image->rows=Header.Height;
385 image->colors=(size_t) (GetQuantumRange(1UL*i)+1);
387 if (image_info->ping) goto Finish;
389 /* ----- Do something with palette ----- */
390 if ((clone_info=CloneImageInfo(image_info)) == NULL) goto NoPalette;
393 i=(ssize_t) strlen(clone_info->filename);
397 if(clone_info->filename[i]=='.')
401 if(clone_info->filename[i]=='/' || clone_info->filename[i]=='\\' ||
402 clone_info->filename[i]==':' )
409 (void) CopyMagickString(clone_info->filename+i,".PAL",(size_t)
411 if((clone_info->file=OpenMagickStream(clone_info->filename,"rb"))==NULL)
413 (void) CopyMagickString(clone_info->filename+i,".pal",(size_t)
415 if((clone_info->file=OpenMagickStream(clone_info->filename,"rb"))==NULL)
417 clone_info->filename[i]='\0';
418 if((clone_info->file=OpenMagickStream(clone_info->filename,"rb"))==NULL)
420 clone_info=DestroyImageInfo(clone_info);
427 if( (palette=AcquireImage(clone_info))==NULL ) goto NoPalette;
428 status=OpenBlob(clone_info,palette,ReadBinaryBlobMode,exception);
429 if (status == MagickFalse)
432 palette=DestroyImage(palette);
440 count=ReadBlob(palette,2,(unsigned char *) PalHeader.FileId);
441 if(strncmp(PalHeader.FileId,"AH",2) != 0) goto ErasePalette;
442 PalHeader.Version=ReadBlobLSBShort(palette);
443 PalHeader.Size=ReadBlobLSBShort(palette);
444 PalHeader.FileType=(char) ReadBlobByte(palette);
445 PalHeader.SubType=(char) ReadBlobByte(palette);
446 PalHeader.BoardID=ReadBlobLSBShort(palette);
447 PalHeader.GraphicsMode=ReadBlobLSBShort(palette);
448 PalHeader.MaxIndex=ReadBlobLSBShort(palette);
449 PalHeader.MaxRed=ReadBlobLSBShort(palette);
450 PalHeader.MaxGreen=ReadBlobLSBShort(palette);
451 PalHeader.MaxBlue=ReadBlobLSBShort(palette);
452 count=ReadBlob(palette,20,(unsigned char *) PalHeader.PaletteId);
454 if(PalHeader.MaxIndex<1) goto ErasePalette;
455 image->colors=PalHeader.MaxIndex+1;
456 if (AcquireImageColormap(image,image->colors) == MagickFalse) goto NoMemory;
458 if(PalHeader.MaxRed==0) PalHeader.MaxRed=(unsigned int) QuantumRange; /*avoid division by 0*/
459 if(PalHeader.MaxGreen==0) PalHeader.MaxGreen=(unsigned int) QuantumRange;
460 if(PalHeader.MaxBlue==0) PalHeader.MaxBlue=(unsigned int) QuantumRange;
462 for(i=0;i<=(int) PalHeader.MaxIndex;i++)
463 { /*this may be wrong- I don't know why is palette such strange*/
464 j=(ssize_t) TellBlob(palette);
468 offset=SeekBlob(palette,j,SEEK_SET);
470 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
472 image->colormap[i].red=(Quantum) ReadBlobLSBShort(palette);
473 if (QuantumRange != (Quantum) PalHeader.MaxRed)
475 image->colormap[i].red=ClampToQuantum(((double)
476 image->colormap[i].red*QuantumRange+(PalHeader.MaxRed>>1))/
479 image->colormap[i].green=(Quantum) ReadBlobLSBShort(palette);
480 if (QuantumRange != (Quantum) PalHeader.MaxGreen)
482 image->colormap[i].green=ClampToQuantum
483 (((double) image->colormap[i].green*QuantumRange+(PalHeader.MaxGreen>>1))/PalHeader.MaxGreen);
485 image->colormap[i].blue=(Quantum) ReadBlobLSBShort(palette);
486 if (QuantumRange != (Quantum) PalHeader.MaxBlue)
488 image->colormap[i].blue=ClampToQuantum
489 (((double)image->colormap[i].blue*QuantumRange+(PalHeader.MaxBlue>>1))/PalHeader.MaxBlue);
502 if (AcquireImageColormap(image,image->colors) == MagickFalse)
505 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
508 for (i=0; i < (ssize_t)image->colors; i++)
510 image->colormap[i].red=ScaleCharToQuantum((unsigned char) i);
511 image->colormap[i].green=ScaleCharToQuantum((unsigned char) i);
512 image->colormap[i].blue=ScaleCharToQuantum((unsigned char) i);
517 /* ----- Load RLE compressed raster ----- */
518 BImgBuff=(unsigned char *) AcquireQuantumMemory((size_t) ldblk,
519 sizeof(*BImgBuff)); /*Ldblk was set in the check phase*/
520 if(BImgBuff==NULL) goto NoMemory;
522 offset=SeekBlob(image,6 /*sizeof(Header)*/,SEEK_SET);
524 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
525 for (i=0; i < (int) Header.Height; i++)
527 EncodedByte=ReadBlobLSBShort(image);
532 RunCount=(unsigned char) ReadBlobByte(image);
533 RunCountMasked=RunCount & 0x7F;
535 while((int) RunCountMasked!=0)
537 if((ssize_t) RunCountMasked>j)
539 RunCountMasked=(unsigned char) j;
546 if((int) RunCount>0x80)
548 RunValue=(unsigned char) ReadBlobByte(image);
549 (void) ResetMagickMemory(ptrB,(int) RunValue,(size_t) RunCountMasked);
552 count=ReadBlob(image,(size_t) RunCountMasked,ptrB);
555 ptrB+=(int) RunCountMasked;
556 j-=(int) RunCountMasked;
558 if (EOFBlob(image) != MagickFalse) goto Finish; /* wrong data: unexpected eof in line */
559 RunCount=(unsigned char) ReadBlobByte(image);
560 RunCountMasked=RunCount & 0x7F;
563 InsertRow(depth,BImgBuff,i,image);
567 /*detect monochrome image*/
570 { /*attempt to detect binary (black&white) images*/
571 if ((image->storage_class == PseudoClass) &&
572 (IsGrayImage(image,&image->exception) != MagickFalse))
574 if(GetCutColors(image)==2)
576 for (i=0; i < (ssize_t)image->colors; i++)
580 sample=ScaleCharToQuantum((unsigned char) i);
581 if(image->colormap[i].red!=sample) goto Finish;
582 if(image->colormap[i].green!=sample) goto Finish;
583 if(image->colormap[i].blue!=sample) goto Finish;
586 image->colormap[1].red=image->colormap[1].green=image->colormap[1].blue=(Quantum) QuantumRange;
587 for (i=0; i < (ssize_t)image->rows; i++)
589 q=QueueAuthenticPixels(image,0,i,image->columns,1,exception);
590 for (j=0; j < (ssize_t)image->columns; j++)
592 if(q->red==ScaleCharToQuantum(1))
594 q->red=q->green=q->blue=(Quantum) QuantumRange;
598 if (SyncAuthenticPixels(image,exception) == MagickFalse) goto Finish;
605 if (BImgBuff != NULL)
606 BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
608 palette=DestroyImage(palette);
609 if (clone_info != NULL)
610 clone_info=DestroyImageInfo(clone_info);
611 if (EOFBlob(image) != MagickFalse)
612 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
614 (void) CloseBlob(image);
615 return(GetFirstImageInList(image));
619 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
623 % R e g i s t e r C U T I m a g e %
627 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
629 % RegisterCUTImage() adds attributes for the CUT image format to
630 % the list of supported formats. The attributes include the image format
631 % tag, a method to read and/or write the format, whether the format
632 % supports the saving of more than one frame to the same file or blob,
633 % whether the format supports native in-memory I/O, and a brief
634 % description of the format.
636 % The format of the RegisterCUTImage method is:
638 % size_t RegisterCUTImage(void)
641 ModuleExport size_t RegisterCUTImage(void)
646 entry=SetMagickInfo("CUT");
647 entry->decoder=(DecodeImageHandler *) ReadCUTImage;
648 entry->seekable_stream=MagickTrue;
649 entry->description=ConstantString("DR Halo");
650 entry->module=ConstantString("CUT");
651 (void) RegisterMagickInfo(entry);
652 return(MagickImageCoderSignature);
656 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
660 % U n r e g i s t e r C U T I m a g e %
664 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
666 % UnregisterCUTImage() removes format registrations made by the
667 % CUT module from the list of supported formats.
669 % The format of the UnregisterCUTImage method is:
671 % UnregisterCUTImage(void)
674 ModuleExport void UnregisterCUTImage(void)
676 (void) UnregisterMagickInfo("CUT");