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(Image *image,ssize_t depth,unsigned char *p,ssize_t y,
99 ExceptionInfo *exception)
101 size_t bit; ssize_t x;
108 case 1: /* Convert bitmap scanline. */
110 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
111 if (q == (Quantum *) NULL)
113 for (x=0; x < ((ssize_t) image->columns-7); x+=8)
115 for (bit=0; bit < 8; bit++)
117 index=(Quantum) ((((*p) & (0x80 >> bit)) != 0) ? 0x01 : 0x00);
118 SetPixelIndex(image,index,q);
119 q+=GetPixelChannels(image);
123 if ((image->columns % 8) != 0)
125 for (bit=0; bit < (image->columns % 8); bit++)
127 index=(Quantum) ((((*p) & (0x80 >> bit)) != 0) ? 0x01 : 0x00);
128 SetPixelIndex(image,index,q);
129 q+=GetPixelChannels(image);
133 if (SyncAuthenticPixels(image,exception) == MagickFalse)
137 case 2: /* Convert PseudoColor scanline. */
139 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
140 if (q == (Quantum *) NULL)
142 for (x=0; x < ((ssize_t) image->columns-1); x+=2)
144 index=ConstrainColormapIndex(image,(*p >> 6) & 0x3,exception);
145 SetPixelIndex(image,index,q);
146 q+=GetPixelChannels(image);
147 index=ConstrainColormapIndex(image,(*p >> 4) & 0x3,exception);
148 SetPixelIndex(image,index,q);
149 q+=GetPixelChannels(image);
150 index=ConstrainColormapIndex(image,(*p >> 2) & 0x3,exception);
151 SetPixelIndex(image,index,q);
152 q+=GetPixelChannels(image);
153 index=ConstrainColormapIndex(image,(*p) & 0x3,exception);
154 SetPixelIndex(image,index,q);
155 q+=GetPixelChannels(image);
158 if ((image->columns % 4) != 0)
160 index=ConstrainColormapIndex(image,(*p >> 6) & 0x3,exception);
161 SetPixelIndex(image,index,q);
162 q+=GetPixelChannels(image);
163 if ((image->columns % 4) >= 1)
166 index=ConstrainColormapIndex(image,(*p >> 4) & 0x3,exception);
167 SetPixelIndex(image,index,q);
168 q+=GetPixelChannels(image);
169 if ((image->columns % 4) >= 2)
172 index=ConstrainColormapIndex(image,(*p >> 2) & 0x3,
174 SetPixelIndex(image,index,q);
175 q+=GetPixelChannels(image);
180 if (SyncAuthenticPixels(image,exception) == MagickFalse)
185 case 4: /* Convert PseudoColor scanline. */
187 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
188 if (q == (Quantum *) NULL)
190 for (x=0; x < ((ssize_t) image->columns-1); x+=2)
192 index=ConstrainColormapIndex(image,(*p >> 4) & 0xf,exception);
193 SetPixelIndex(image,index,q);
194 q+=GetPixelChannels(image);
195 index=ConstrainColormapIndex(image,(*p) & 0xf,exception);
196 SetPixelIndex(image,index,q);
197 q+=GetPixelChannels(image);
200 if ((image->columns % 2) != 0)
202 index=ConstrainColormapIndex(image,(*p >> 4) & 0xf,exception);
203 SetPixelIndex(image,index,q);
204 q+=GetPixelChannels(image);
207 if (SyncAuthenticPixels(image,exception) == MagickFalse)
211 case 8: /* Convert PseudoColor scanline. */
213 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
214 if (q == (Quantum *) NULL) break;
215 for (x=0; x < (ssize_t) image->columns; x++)
217 index=ConstrainColormapIndex(image,*p,exception);
218 SetPixelIndex(image,index,q);
220 q+=GetPixelChannels(image);
222 if (SyncAuthenticPixels(image,exception) == MagickFalse)
231 Compute the number of colors in Grayed R[i]=G[i]=B[i] image
233 static int GetCutColors(Image *image,ExceptionInfo *exception)
247 scale_intensity=ScaleCharToQuantum(16);
248 for (y=0; y < (ssize_t) image->rows; y++)
250 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
251 if (q == (Quantum *) NULL)
253 for (x=0; x < (ssize_t) image->columns; x++)
255 if (intensity < GetPixelRed(image,q))
256 intensity=GetPixelRed(image,q);
257 if (intensity >= scale_intensity)
259 q+=GetPixelChannels(image);
262 if (intensity < ScaleCharToQuantum(2))
264 if (intensity < ScaleCharToQuantum(16))
266 return((int) intensity);
270 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
274 % R e a d C U T I m a g e %
278 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
280 % ReadCUTImage() reads an CUT X image file and returns it. It
281 % allocates the memory necessary for the new Image structure and returns a
282 % pointer to the new image.
284 % The format of the ReadCUTImage method is:
286 % Image *ReadCUTImage(const ImageInfo *image_info,ExceptionInfo *exception)
288 % A description of each parameter follows:
290 % o image_info: the image info.
292 % o exception: return any errors or warnings in this structure.
295 static Image *ReadCUTImage(const ImageInfo *image_info,ExceptionInfo *exception)
297 Image *image,*palette;
298 ImageInfo *clone_info;
299 MagickBooleanType status;
305 unsigned char RunCount,RunValue,RunCountMasked;
307 CUTPalHeader PalHeader;
311 unsigned char *BImgBuff=NULL,*ptrB;
317 assert(image_info != (const ImageInfo *) NULL);
318 assert(image_info->signature == MagickSignature);
319 if (image_info->debug != MagickFalse)
320 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
321 image_info->filename);
322 assert(exception != (ExceptionInfo *) NULL);
323 assert(exception->signature == MagickSignature);
324 image=AcquireImage(image_info,exception);
325 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
326 if (status == MagickFalse)
328 image=DestroyImageList(image);
329 return((Image *) NULL);
336 Header.Width=ReadBlobLSBShort(image);
337 Header.Height=ReadBlobLSBShort(image);
338 Header.Reserved=ReadBlobLSBShort(image);
340 if (Header.Width==0 || Header.Height==0 || Header.Reserved!=0)
341 CUT_KO: ThrowReaderException(CorruptImageError,"ImproperImageHeader");
343 /*---This code checks first line of image---*/
344 EncodedByte=ReadBlobLSBShort(image);
345 RunCount=(unsigned char) ReadBlobByte(image);
346 RunCountMasked=RunCount & 0x7F;
348 while((int) RunCountMasked!=0) /*end of line?*/
351 if((int) RunCount<0x80) i=(ssize_t) RunCountMasked;
352 offset=SeekBlob(image,TellBlob(image)+i,SEEK_SET);
354 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
355 if(EOFBlob(image) != MagickFalse) goto CUT_KO; /*wrong data*/
357 ldblk+=(ssize_t) RunCountMasked;
359 RunCount=(unsigned char) ReadBlobByte(image);
360 if(EOFBlob(image) != MagickFalse) goto CUT_KO; /*wrong data: unexpected eof in line*/
361 RunCountMasked=RunCount & 0x7F;
363 if(EncodedByte!=1) goto CUT_KO; /*wrong data: size incorrect*/
364 i=0; /*guess a number of bit planes*/
365 if(ldblk==(int) Header.Width) i=8;
366 if(2*ldblk==(int) Header.Width) i=4;
367 if(8*ldblk==(int) Header.Width) i=1;
368 if(i==0) goto CUT_KO; /*wrong data: incorrect bit planes*/
371 image->columns=Header.Width;
372 image->rows=Header.Height;
374 image->colors=(size_t) (GetQuantumRange(1UL*i)+1);
376 if (image_info->ping != MagickFalse) goto Finish;
377 status=SetImageExtent(image,image->columns,image->rows,exception);
378 if (status == MagickFalse)
379 return(DestroyImageList(image));
381 /* ----- Do something with palette ----- */
382 if ((clone_info=CloneImageInfo(image_info)) == NULL) goto NoPalette;
385 i=(ssize_t) strlen(clone_info->filename);
389 if(clone_info->filename[i]=='.')
393 if(clone_info->filename[i]=='/' || clone_info->filename[i]=='\\' ||
394 clone_info->filename[i]==':' )
401 (void) CopyMagickString(clone_info->filename+i,".PAL",(size_t)
403 if((clone_info->file=fopen_utf8(clone_info->filename,"rb"))==NULL)
405 (void) CopyMagickString(clone_info->filename+i,".pal",(size_t)
407 if((clone_info->file=fopen_utf8(clone_info->filename,"rb"))==NULL)
409 clone_info->filename[i]='\0';
410 if((clone_info->file=fopen_utf8(clone_info->filename,"rb"))==NULL)
412 clone_info=DestroyImageInfo(clone_info);
419 if( (palette=AcquireImage(clone_info,exception))==NULL ) goto NoPalette;
420 status=OpenBlob(clone_info,palette,ReadBinaryBlobMode,exception);
421 if (status == MagickFalse)
424 palette=DestroyImage(palette);
432 (void) ReadBlob(palette,2,(unsigned char *) PalHeader.FileId);
433 if(strncmp(PalHeader.FileId,"AH",2) != 0) goto ErasePalette;
434 PalHeader.Version=ReadBlobLSBShort(palette);
435 PalHeader.Size=ReadBlobLSBShort(palette);
436 PalHeader.FileType=(char) ReadBlobByte(palette);
437 PalHeader.SubType=(char) ReadBlobByte(palette);
438 PalHeader.BoardID=ReadBlobLSBShort(palette);
439 PalHeader.GraphicsMode=ReadBlobLSBShort(palette);
440 PalHeader.MaxIndex=ReadBlobLSBShort(palette);
441 PalHeader.MaxRed=ReadBlobLSBShort(palette);
442 PalHeader.MaxGreen=ReadBlobLSBShort(palette);
443 PalHeader.MaxBlue=ReadBlobLSBShort(palette);
444 (void) ReadBlob(palette,20,(unsigned char *) PalHeader.PaletteId);
446 if(PalHeader.MaxIndex<1) goto ErasePalette;
447 image->colors=PalHeader.MaxIndex+1;
448 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse) goto NoMemory;
450 if(PalHeader.MaxRed==0) PalHeader.MaxRed=(unsigned int) QuantumRange; /*avoid division by 0*/
451 if(PalHeader.MaxGreen==0) PalHeader.MaxGreen=(unsigned int) QuantumRange;
452 if(PalHeader.MaxBlue==0) PalHeader.MaxBlue=(unsigned int) QuantumRange;
454 for(i=0;i<=(int) PalHeader.MaxIndex;i++)
455 { /*this may be wrong- I don't know why is palette such strange*/
456 j=(ssize_t) TellBlob(palette);
460 offset=SeekBlob(palette,j,SEEK_SET);
462 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
464 image->colormap[i].red=(Quantum) ReadBlobLSBShort(palette);
465 if (QuantumRange != (Quantum) PalHeader.MaxRed)
467 image->colormap[i].red=ClampToQuantum(((double)
468 image->colormap[i].red*QuantumRange+(PalHeader.MaxRed>>1))/
471 image->colormap[i].green=(Quantum) ReadBlobLSBShort(palette);
472 if (QuantumRange != (Quantum) PalHeader.MaxGreen)
474 image->colormap[i].green=ClampToQuantum
475 (((double) image->colormap[i].green*QuantumRange+(PalHeader.MaxGreen>>1))/PalHeader.MaxGreen);
477 image->colormap[i].blue=(Quantum) ReadBlobLSBShort(palette);
478 if (QuantumRange != (Quantum) PalHeader.MaxBlue)
480 image->colormap[i].blue=ClampToQuantum
481 (((double)image->colormap[i].blue*QuantumRange+(PalHeader.MaxBlue>>1))/PalHeader.MaxBlue);
494 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
497 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
500 for (i=0; i < (ssize_t)image->colors; i++)
502 image->colormap[i].red=ScaleCharToQuantum((unsigned char) i);
503 image->colormap[i].green=ScaleCharToQuantum((unsigned char) i);
504 image->colormap[i].blue=ScaleCharToQuantum((unsigned char) i);
509 /* ----- Load RLE compressed raster ----- */
510 BImgBuff=(unsigned char *) AcquireQuantumMemory((size_t) ldblk,
511 sizeof(*BImgBuff)); /*Ldblk was set in the check phase*/
512 if(BImgBuff==NULL) goto NoMemory;
514 offset=SeekBlob(image,6 /*sizeof(Header)*/,SEEK_SET);
516 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
517 for (i=0; i < (int) Header.Height; i++)
519 EncodedByte=ReadBlobLSBShort(image);
524 RunCount=(unsigned char) ReadBlobByte(image);
525 RunCountMasked=RunCount & 0x7F;
527 while ((int) RunCountMasked != 0)
529 if((ssize_t) RunCountMasked>j)
531 RunCountMasked=(unsigned char) j;
538 if((int) RunCount>0x80)
540 RunValue=(unsigned char) ReadBlobByte(image);
541 (void) ResetMagickMemory(ptrB,(int) RunValue,(size_t) RunCountMasked);
544 (void) ReadBlob(image,(size_t) RunCountMasked,ptrB);
547 ptrB+=(int) RunCountMasked;
548 j-=(int) RunCountMasked;
550 if (EOFBlob(image) != MagickFalse) goto Finish; /* wrong data: unexpected eof in line */
551 RunCount=(unsigned char) ReadBlobByte(image);
552 RunCountMasked=RunCount & 0x7F;
555 InsertRow(image,depth,BImgBuff,i,exception);
557 (void) SyncImage(image,exception);
560 /*detect monochrome image*/
563 { /*attempt to detect binary (black&white) images*/
564 if ((image->storage_class == PseudoClass) &&
565 (IsImageGray(image,exception) != MagickFalse))
567 if(GetCutColors(image,exception)==2)
569 for (i=0; i < (ssize_t)image->colors; i++)
573 sample=ScaleCharToQuantum((unsigned char) i);
574 if(image->colormap[i].red!=sample) goto Finish;
575 if(image->colormap[i].green!=sample) goto Finish;
576 if(image->colormap[i].blue!=sample) goto Finish;
579 image->colormap[1].red=image->colormap[1].green=
580 image->colormap[1].blue=QuantumRange;
581 for (i=0; i < (ssize_t)image->rows; i++)
583 q=QueueAuthenticPixels(image,0,i,image->columns,1,exception);
584 for (j=0; j < (ssize_t)image->columns; j++)
586 if (GetPixelRed(image,q) == ScaleCharToQuantum(1))
588 SetPixelRed(image,QuantumRange,q);
589 SetPixelGreen(image,QuantumRange,q);
590 SetPixelBlue(image,QuantumRange,q);
592 q+=GetPixelChannels(image);
594 if (SyncAuthenticPixels(image,exception) == MagickFalse) goto Finish;
601 if (BImgBuff != NULL)
602 BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
604 palette=DestroyImage(palette);
605 if (clone_info != NULL)
606 clone_info=DestroyImageInfo(clone_info);
607 if (EOFBlob(image) != MagickFalse)
608 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
610 (void) CloseBlob(image);
611 return(GetFirstImageInList(image));
615 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
619 % R e g i s t e r C U T I m a g e %
623 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
625 % RegisterCUTImage() adds attributes for the CUT image format to
626 % the list of supported formats. The attributes include the image format
627 % tag, a method to read and/or write the format, whether the format
628 % supports the saving of more than one frame to the same file or blob,
629 % whether the format supports native in-memory I/O, and a brief
630 % description of the format.
632 % The format of the RegisterCUTImage method is:
634 % size_t RegisterCUTImage(void)
637 ModuleExport size_t RegisterCUTImage(void)
642 entry=SetMagickInfo("CUT");
643 entry->decoder=(DecodeImageHandler *) ReadCUTImage;
644 entry->flags|=CoderSeekableStreamFlag;
645 entry->description=ConstantString("DR Halo");
646 entry->module=ConstantString("CUT");
647 (void) RegisterMagickInfo(entry);
648 return(MagickImageCoderSignature);
652 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
656 % U n r e g i s t e r C U T I m a g e %
660 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
662 % UnregisterCUTImage() removes format registrations made by the
663 % CUT module from the list of supported formats.
665 % The format of the UnregisterCUTImage method is:
667 % UnregisterCUTImage(void)
670 ModuleExport void UnregisterCUTImage(void)
672 (void) UnregisterMagickInfo("CUT");