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 "MagickCore/studio.h"
51 #include "MagickCore/attribute.h"
52 #include "MagickCore/blob.h"
53 #include "MagickCore/blob-private.h"
54 #include "MagickCore/cache.h"
55 #include "MagickCore/color.h"
56 #include "MagickCore/color-private.h"
57 #include "MagickCore/colormap.h"
58 #include "MagickCore/colormap-private.h"
59 #include "MagickCore/exception.h"
60 #include "MagickCore/exception-private.h"
61 #include "MagickCore/image.h"
62 #include "MagickCore/image-private.h"
63 #include "MagickCore/list.h"
64 #include "MagickCore/magick.h"
65 #include "MagickCore/memory_.h"
66 #include "MagickCore/pixel-accessor.h"
67 #include "MagickCore/quantum-private.h"
68 #include "MagickCore/static.h"
69 #include "MagickCore/string_.h"
70 #include "MagickCore/module.h"
71 #include "MagickCore/utility.h"
72 #include "MagickCore/utility-private.h"
89 unsigned GraphicsMode;
98 static void InsertRow(ssize_t depth,unsigned char *p,ssize_t y,Image *image)
103 size_t bit; ssize_t x;
108 exception=(&image->exception);
111 case 1: /* Convert bitmap scanline. */
113 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
114 if (q == (Quantum *) NULL)
116 for (x=0; x < ((ssize_t) image->columns-7); x+=8)
118 for (bit=0; bit < 8; bit++)
120 index=(Quantum) ((((*p) & (0x80 >> bit)) != 0) ? 0x01 : 0x00);
121 SetPixelIndex(image,index,q);
122 q+=GetPixelChannels(image);
126 if ((image->columns % 8) != 0)
128 for (bit=0; bit < (image->columns % 8); bit++)
130 index=(Quantum) ((((*p) & (0x80 >> bit)) != 0) ? 0x01 : 0x00);
131 SetPixelIndex(image,index,q);
132 q+=GetPixelChannels(image);
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 == (Quantum *) NULL)
145 for (x=0; x < ((ssize_t) image->columns-1); x+=2)
147 index=ConstrainColormapIndex(image,(*p >> 6) & 0x3);
148 SetPixelIndex(image,index,q);
149 q+=GetPixelChannels(image);
150 index=ConstrainColormapIndex(image,(*p >> 4) & 0x3);
151 SetPixelIndex(image,index,q);
152 q+=GetPixelChannels(image);
153 index=ConstrainColormapIndex(image,(*p >> 2) & 0x3);
154 SetPixelIndex(image,index,q);
155 q+=GetPixelChannels(image);
156 index=ConstrainColormapIndex(image,(*p) & 0x3);
157 SetPixelIndex(image,index,q);
158 q+=GetPixelChannels(image);
161 if ((image->columns % 4) != 0)
163 index=ConstrainColormapIndex(image,(*p >> 6) & 0x3);
164 SetPixelIndex(image,index,q);
165 q+=GetPixelChannels(image);
166 if ((image->columns % 4) >= 1)
169 index=ConstrainColormapIndex(image,(*p >> 4) & 0x3);
170 SetPixelIndex(image,index,q);
171 q+=GetPixelChannels(image);
172 if ((image->columns % 4) >= 2)
175 index=ConstrainColormapIndex(image,(*p >> 2) & 0x3);
176 SetPixelIndex(image,index,q);
177 q+=GetPixelChannels(image);
182 if (SyncAuthenticPixels(image,exception) == MagickFalse)
187 case 4: /* Convert PseudoColor scanline. */
189 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
190 if (q == (Quantum *) NULL)
192 for (x=0; x < ((ssize_t) image->columns-1); x+=2)
194 index=ConstrainColormapIndex(image,(*p >> 4) & 0xf);
195 SetPixelIndex(image,index,q);
196 q+=GetPixelChannels(image);
197 index=ConstrainColormapIndex(image,(*p) & 0xf);
198 SetPixelIndex(image,index,q);
199 q+=GetPixelChannels(image);
202 if ((image->columns % 2) != 0)
204 index=ConstrainColormapIndex(image,(*p >> 4) & 0xf);
205 SetPixelIndex(image,index,q);
206 q+=GetPixelChannels(image);
209 if (SyncAuthenticPixels(image,exception) == MagickFalse)
213 case 8: /* Convert PseudoColor scanline. */
215 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
216 if (q == (Quantum *) NULL) break;
217 for (x=0; x < (ssize_t) image->columns; x++)
219 index=ConstrainColormapIndex(image,*p);
220 SetPixelIndex(image,index,q);
222 q+=GetPixelChannels(image);
224 if (SyncAuthenticPixels(image,exception) == MagickFalse)
233 Compute the number of colors in Grayed R[i]=G[i]=B[i] image
235 static int GetCutColors(Image *image)
251 exception=(&image->exception);
253 scale_intensity=ScaleCharToQuantum(16);
254 for (y=0; y < (ssize_t) image->rows; y++)
256 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
257 for (x=0; x < (ssize_t) image->columns; x++)
259 if (intensity < GetPixelRed(image,q))
260 intensity=GetPixelRed(image,q);
261 if (intensity >= scale_intensity)
263 q+=GetPixelChannels(image);
266 if (intensity < ScaleCharToQuantum(2))
268 if (intensity < ScaleCharToQuantum(16))
270 return((int) intensity);
274 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
278 % R e a d C U T I m a g e %
282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
284 % ReadCUTImage() reads an CUT X image file and returns it. It
285 % allocates the memory necessary for the new Image structure and returns a
286 % pointer to the new image.
288 % The format of the ReadCUTImage method is:
290 % Image *ReadCUTImage(const ImageInfo *image_info,ExceptionInfo *exception)
292 % A description of each parameter follows:
294 % o image_info: the image info.
296 % o exception: return any errors or warnings in this structure.
299 static Image *ReadCUTImage(const ImageInfo *image_info,ExceptionInfo *exception)
301 Image *image,*palette;
302 ImageInfo *clone_info;
303 MagickBooleanType status;
309 unsigned char RunCount,RunValue,RunCountMasked;
311 CUTPalHeader PalHeader;
315 unsigned char *BImgBuff=NULL,*ptrB;
321 assert(image_info != (const ImageInfo *) NULL);
322 assert(image_info->signature == MagickSignature);
323 if (image_info->debug != MagickFalse)
324 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
325 image_info->filename);
326 assert(exception != (ExceptionInfo *) NULL);
327 assert(exception->signature == MagickSignature);
328 image=AcquireImage(image_info);
329 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
330 if (status == MagickFalse)
332 image=DestroyImageList(image);
333 return((Image *) NULL);
340 Header.Width=ReadBlobLSBShort(image);
341 Header.Height=ReadBlobLSBShort(image);
342 Header.Reserved=ReadBlobLSBShort(image);
344 if (Header.Width==0 || Header.Height==0 || Header.Reserved!=0)
345 CUT_KO: ThrowReaderException(CorruptImageError,"ImproperImageHeader");
347 /*---This code checks first line of image---*/
348 EncodedByte=ReadBlobLSBShort(image);
349 RunCount=(unsigned char) ReadBlobByte(image);
350 RunCountMasked=RunCount & 0x7F;
352 while((int) RunCountMasked!=0) /*end of line?*/
355 if((int) RunCount<0x80) i=(ssize_t) RunCountMasked;
356 offset=SeekBlob(image,TellBlob(image)+i,SEEK_SET);
358 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
359 if(EOFBlob(image) != MagickFalse) goto CUT_KO; /*wrong data*/
361 ldblk+=(ssize_t) RunCountMasked;
363 RunCount=(unsigned char) ReadBlobByte(image);
364 if(EOFBlob(image) != MagickFalse) goto CUT_KO; /*wrong data: unexpected eof in line*/
365 RunCountMasked=RunCount & 0x7F;
367 if(EncodedByte!=1) goto CUT_KO; /*wrong data: size incorrect*/
368 i=0; /*guess a number of bit planes*/
369 if(ldblk==(int) Header.Width) i=8;
370 if(2*ldblk==(int) Header.Width) i=4;
371 if(8*ldblk==(int) Header.Width) i=1;
372 if(i==0) goto CUT_KO; /*wrong data: incorrect bit planes*/
375 image->columns=Header.Width;
376 image->rows=Header.Height;
378 image->colors=(size_t) (GetQuantumRange(1UL*i)+1);
380 if (image_info->ping) goto Finish;
382 /* ----- Do something with palette ----- */
383 if ((clone_info=CloneImageInfo(image_info)) == NULL) goto NoPalette;
386 i=(ssize_t) strlen(clone_info->filename);
390 if(clone_info->filename[i]=='.')
394 if(clone_info->filename[i]=='/' || clone_info->filename[i]=='\\' ||
395 clone_info->filename[i]==':' )
402 (void) CopyMagickString(clone_info->filename+i,".PAL",(size_t)
404 if((clone_info->file=fopen_utf8(clone_info->filename,"rb"))==NULL)
406 (void) CopyMagickString(clone_info->filename+i,".pal",(size_t)
408 if((clone_info->file=fopen_utf8(clone_info->filename,"rb"))==NULL)
410 clone_info->filename[i]='\0';
411 if((clone_info->file=fopen_utf8(clone_info->filename,"rb"))==NULL)
413 clone_info=DestroyImageInfo(clone_info);
420 if( (palette=AcquireImage(clone_info))==NULL ) goto NoPalette;
421 status=OpenBlob(clone_info,palette,ReadBinaryBlobMode,exception);
422 if (status == MagickFalse)
425 palette=DestroyImage(palette);
433 (void) ReadBlob(palette,2,(unsigned char *) PalHeader.FileId);
434 if(strncmp(PalHeader.FileId,"AH",2) != 0) goto ErasePalette;
435 PalHeader.Version=ReadBlobLSBShort(palette);
436 PalHeader.Size=ReadBlobLSBShort(palette);
437 PalHeader.FileType=(char) ReadBlobByte(palette);
438 PalHeader.SubType=(char) ReadBlobByte(palette);
439 PalHeader.BoardID=ReadBlobLSBShort(palette);
440 PalHeader.GraphicsMode=ReadBlobLSBShort(palette);
441 PalHeader.MaxIndex=ReadBlobLSBShort(palette);
442 PalHeader.MaxRed=ReadBlobLSBShort(palette);
443 PalHeader.MaxGreen=ReadBlobLSBShort(palette);
444 PalHeader.MaxBlue=ReadBlobLSBShort(palette);
445 (void) ReadBlob(palette,20,(unsigned char *) PalHeader.PaletteId);
447 if(PalHeader.MaxIndex<1) goto ErasePalette;
448 image->colors=PalHeader.MaxIndex+1;
449 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse) goto NoMemory;
451 if(PalHeader.MaxRed==0) PalHeader.MaxRed=(unsigned int) QuantumRange; /*avoid division by 0*/
452 if(PalHeader.MaxGreen==0) PalHeader.MaxGreen=(unsigned int) QuantumRange;
453 if(PalHeader.MaxBlue==0) PalHeader.MaxBlue=(unsigned int) QuantumRange;
455 for(i=0;i<=(int) PalHeader.MaxIndex;i++)
456 { /*this may be wrong- I don't know why is palette such strange*/
457 j=(ssize_t) TellBlob(palette);
461 offset=SeekBlob(palette,j,SEEK_SET);
463 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
465 image->colormap[i].red=(Quantum) ReadBlobLSBShort(palette);
466 if (QuantumRange != (Quantum) PalHeader.MaxRed)
468 image->colormap[i].red=ClampToQuantum(((double)
469 image->colormap[i].red*QuantumRange+(PalHeader.MaxRed>>1))/
472 image->colormap[i].green=(Quantum) ReadBlobLSBShort(palette);
473 if (QuantumRange != (Quantum) PalHeader.MaxGreen)
475 image->colormap[i].green=ClampToQuantum
476 (((double) image->colormap[i].green*QuantumRange+(PalHeader.MaxGreen>>1))/PalHeader.MaxGreen);
478 image->colormap[i].blue=(Quantum) ReadBlobLSBShort(palette);
479 if (QuantumRange != (Quantum) PalHeader.MaxBlue)
481 image->colormap[i].blue=ClampToQuantum
482 (((double)image->colormap[i].blue*QuantumRange+(PalHeader.MaxBlue>>1))/PalHeader.MaxBlue);
495 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
498 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
501 for (i=0; i < (ssize_t)image->colors; i++)
503 image->colormap[i].red=ScaleCharToQuantum((unsigned char) i);
504 image->colormap[i].green=ScaleCharToQuantum((unsigned char) i);
505 image->colormap[i].blue=ScaleCharToQuantum((unsigned char) i);
510 /* ----- Load RLE compressed raster ----- */
511 BImgBuff=(unsigned char *) AcquireQuantumMemory((size_t) ldblk,
512 sizeof(*BImgBuff)); /*Ldblk was set in the check phase*/
513 if(BImgBuff==NULL) goto NoMemory;
515 offset=SeekBlob(image,6 /*sizeof(Header)*/,SEEK_SET);
517 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
518 for (i=0; i < (int) Header.Height; i++)
520 EncodedByte=ReadBlobLSBShort(image);
525 RunCount=(unsigned char) ReadBlobByte(image);
526 RunCountMasked=RunCount & 0x7F;
528 while ((int) RunCountMasked != 0)
530 if((ssize_t) RunCountMasked>j)
532 RunCountMasked=(unsigned char) j;
539 if((int) RunCount>0x80)
541 RunValue=(unsigned char) ReadBlobByte(image);
542 (void) ResetMagickMemory(ptrB,(int) RunValue,(size_t) RunCountMasked);
545 (void) ReadBlob(image,(size_t) RunCountMasked,ptrB);
548 ptrB+=(int) RunCountMasked;
549 j-=(int) RunCountMasked;
551 if (EOFBlob(image) != MagickFalse) goto Finish; /* wrong data: unexpected eof in line */
552 RunCount=(unsigned char) ReadBlobByte(image);
553 RunCountMasked=RunCount & 0x7F;
556 InsertRow(depth,BImgBuff,i,image);
558 (void) SyncImage(image);
561 /*detect monochrome image*/
564 { /*attempt to detect binary (black&white) images*/
565 if ((image->storage_class == PseudoClass) &&
566 (IsImageGray(image,&image->exception) != MagickFalse))
568 if(GetCutColors(image)==2)
570 for (i=0; i < (ssize_t)image->colors; i++)
574 sample=ScaleCharToQuantum((unsigned char) i);
575 if(image->colormap[i].red!=sample) goto Finish;
576 if(image->colormap[i].green!=sample) goto Finish;
577 if(image->colormap[i].blue!=sample) goto Finish;
580 image->colormap[1].red=image->colormap[1].green=
581 image->colormap[1].blue=(Quantum) QuantumRange;
582 for (i=0; i < (ssize_t)image->rows; i++)
584 q=QueueAuthenticPixels(image,0,i,image->columns,1,exception);
585 for (j=0; j < (ssize_t)image->columns; j++)
587 if (GetPixelRed(image,q) == ScaleCharToQuantum(1))
589 SetPixelRed(image,QuantumRange,q);
590 SetPixelGreen(image,QuantumRange,q);
591 SetPixelBlue(image,QuantumRange,q);
593 q+=GetPixelChannels(image);
595 if (SyncAuthenticPixels(image,exception) == MagickFalse) goto Finish;
602 if (BImgBuff != NULL)
603 BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
605 palette=DestroyImage(palette);
606 if (clone_info != NULL)
607 clone_info=DestroyImageInfo(clone_info);
608 if (EOFBlob(image) != MagickFalse)
609 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
611 (void) CloseBlob(image);
612 return(GetFirstImageInList(image));
616 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
620 % R e g i s t e r C U T I m a g e %
624 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
626 % RegisterCUTImage() adds attributes for the CUT image format to
627 % the list of supported formats. The attributes include the image format
628 % tag, a method to read and/or write the format, whether the format
629 % supports the saving of more than one frame to the same file or blob,
630 % whether the format supports native in-memory I/O, and a brief
631 % description of the format.
633 % The format of the RegisterCUTImage method is:
635 % size_t RegisterCUTImage(void)
638 ModuleExport size_t RegisterCUTImage(void)
643 entry=SetMagickInfo("CUT");
644 entry->decoder=(DecodeImageHandler *) ReadCUTImage;
645 entry->seekable_stream=MagickTrue;
646 entry->description=ConstantString("DR Halo");
647 entry->module=ConstantString("CUT");
648 (void) RegisterMagickInfo(entry);
649 return(MagickImageCoderSignature);
653 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
657 % U n r e g i s t e r C U T I m a g e %
661 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
663 % UnregisterCUTImage() removes format registrations made by the
664 % CUT module from the list of supported formats.
666 % The format of the UnregisterCUTImage method is:
668 % UnregisterCUTImage(void)
671 ModuleExport void UnregisterCUTImage(void)
673 (void) UnregisterMagickInfo("CUT");