1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % CCC U U TTTTT %
6 % C U U T %
7 % C U U T %
8 % C U U T %
9 % CCC UUU T %
10 % %
11 % %
12 % Read DR Halo Image Format %
13 % %
14 % Software Design %
15 % Jaroslav Fojtik %
16 % June 2000 %
17 % %
18 % %
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: %
25 % %
26 % The above copyright notice and this permission notice shall be included in %
27 % all copies or substantial portions of ImageMagick. %
28 % %
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 %
35 % ImageMagick. %
36 % %
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. %
41 % %
42 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 %
44 %
45 */
46
47 /*
48 Include declarations.
49 */
50 #include "magick/studio.h"
51 #include "magick/attribute.h"
52 #include "magick/blob.h"
53 #include "magick/blob-private.h"
54 #include "magick/cache.h"
55 #include "magick/color.h"
56 #include "magick/color-private.h"
57 #include "magick/colormap.h"
58 #include "magick/colormap-private.h"
59 #include "magick/exception.h"
60 #include "magick/exception-private.h"
61 #include "magick/image.h"
62 #include "magick/image-private.h"
63 #include "magick/list.h"
64 #include "magick/magick.h"
65 #include "magick/memory_.h"
66 #include "magick/pixel-accessor.h"
67 #include "magick/quantum-private.h"
68 #include "magick/static.h"
69 #include "magick/string_.h"
70 #include "magick/module.h"
71 #include "magick/utility.h"
72 #include "magick/utility-private.h"
73
74 typedef struct
75 {
76 unsigned Width;
77 unsigned Height;
78 unsigned Reserved;
79 } CUTHeader;
80
81 typedef struct
82 {
83 char FileId[2];
84 unsigned Version;
85 unsigned Size;
86 char FileType;
87 char SubType;
88 unsigned BoardID;
89 unsigned GraphicsMode;
90 unsigned MaxIndex;
91 unsigned MaxRed;
92 unsigned MaxGreen;
93 unsigned MaxBlue;
94 char PaletteId[20];
95 } CUTPalHeader;
96
97
InsertRow(int bpp,unsigned char * p,ssize_t y,Image * image)98 static MagickBooleanType InsertRow(int bpp,unsigned char *p,ssize_t y,
99 Image *image)
100 {
101 ExceptionInfo
102 *exception;
103
104 int
105 bit;
106
107 ssize_t
108 x;
109
110 PixelPacket
111 *q;
112
113 IndexPacket
114 index;
115
116 IndexPacket
117 *indexes;
118
119 exception=(&image->exception);
120 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
121 if (q == (PixelPacket *) NULL)
122 return(MagickFalse);
123 indexes=GetAuthenticIndexQueue(image);
124 switch (bpp)
125 {
126 case 1: /* Convert bitmap scanline. */
127 {
128 for (x=0; x < ((ssize_t) image->columns-7); x+=8)
129 {
130 for (bit=0; bit < 8; bit++)
131 {
132 index=((*p) & (0x80 >> bit) ? 0x01 : 0x00);
133 SetPixelIndex(indexes+x+bit,index);
134 if (index < image->colors)
135 SetPixelRGBO(q,image->colormap+(ssize_t) index);
136 q++;
137 }
138 p++;
139 }
140 if ((image->columns % 8) != 0)
141 {
142 for (bit=0; bit < (ssize_t) (image->columns % 8); bit++)
143 {
144 index=((*p) & (0x80 >> bit) ? 0x01 : 0x00);
145 SetPixelIndex(indexes+x+bit,index);
146 if (index < image->colors)
147 SetPixelRGBO(q,image->colormap+(ssize_t) index);
148 q++;
149 }
150 p++;
151 }
152 break;
153 }
154 case 2: /* Convert PseudoColor scanline. */
155 {
156 if ((image->storage_class != PseudoClass) ||
157 (indexes == (IndexPacket *) NULL))
158 break;
159 for (x=0; x < ((ssize_t) image->columns-3); x+=4)
160 {
161 index=ConstrainColormapIndex(image,(*p >> 6) & 0x3);
162 SetPixelIndex(indexes+x,index);
163 if (index < image->colors)
164 SetPixelRGBO(q,image->colormap+(ssize_t) index);
165 q++;
166 index=ConstrainColormapIndex(image,(*p >> 4) & 0x3);
167 SetPixelIndex(indexes+x,index);
168 if (index < image->colors)
169 SetPixelRGBO(q,image->colormap+(ssize_t) index);
170 q++;
171 index=ConstrainColormapIndex(image,(*p >> 2) & 0x3);
172 SetPixelIndex(indexes+x,index);
173 if (index < image->colors)
174 SetPixelRGBO(q,image->colormap+(ssize_t) index);
175 q++;
176 index=ConstrainColormapIndex(image,(*p) & 0x3);
177 SetPixelIndex(indexes+x+1,index);
178 if (index < image->colors)
179 SetPixelRGBO(q,image->colormap+(ssize_t) index);
180 q++;
181 p++;
182 }
183 if ((image->columns % 4) != 0)
184 {
185 index=ConstrainColormapIndex(image,(*p >> 6) & 0x3);
186 SetPixelIndex(indexes+x,index);
187 if (index < image->colors)
188 SetPixelRGBO(q,image->colormap+(ssize_t) index);
189 q++;
190 if ((image->columns % 4) > 1)
191 {
192 index=ConstrainColormapIndex(image,(*p >> 4) & 0x3);
193 SetPixelIndex(indexes+x,index);
194 if (index < image->colors)
195 SetPixelRGBO(q,image->colormap+(ssize_t) index);
196 q++;
197 if ((image->columns % 4) > 2)
198 {
199 index=ConstrainColormapIndex(image,(*p >> 2) & 0x3);
200 SetPixelIndex(indexes+x,index);
201 if (index < image->colors)
202 SetPixelRGBO(q,image->colormap+(ssize_t) index);
203 q++;
204 }
205 }
206 p++;
207 }
208 break;
209 }
210
211 case 4: /* Convert PseudoColor scanline. */
212 {
213 for (x=0; x < ((ssize_t) image->columns-1); x+=2)
214 {
215 index=ConstrainColormapIndex(image,(*p >> 4) & 0x0f);
216 SetPixelIndex(indexes+x,index);
217 if (index < image->colors)
218 SetPixelRGBO(q,image->colormap+(ssize_t) index);
219 q++;
220 index=ConstrainColormapIndex(image,(*p) & 0x0f);
221 SetPixelIndex(indexes+x+1,index);
222 if (index < image->colors)
223 SetPixelRGBO(q,image->colormap+(ssize_t) index);
224 p++;
225 q++;
226 }
227 if ((image->columns % 2) != 0)
228 {
229 index=ConstrainColormapIndex(image,(*p >> 4) & 0x0f);
230 SetPixelIndex(indexes+x,index);
231 if (index < image->colors)
232 SetPixelRGBO(q,image->colormap+(ssize_t) index);
233 p++;
234 q++;
235 }
236 break;
237 }
238 case 8: /* Convert PseudoColor scanline. */
239 {
240 for (x=0; x < (ssize_t) image->columns; x++)
241 {
242 index=ConstrainColormapIndex(image,*p);
243 SetPixelIndex(indexes+x,index);
244 if (index < image->colors)
245 SetPixelRGBO(q,image->colormap+(ssize_t) index);
246 p++;
247 q++;
248 }
249 }
250 break;
251
252 case 24: /* Convert DirectColor scanline. */
253 for (x=0; x < (ssize_t) image->columns; x++)
254 {
255 SetPixelRed(q,ScaleCharToQuantum(*p++));
256 SetPixelGreen(q,ScaleCharToQuantum(*p++));
257 SetPixelBlue(q,ScaleCharToQuantum(*p++));
258 q++;
259 }
260 break;
261 }
262 if (!SyncAuthenticPixels(image,exception))
263 return(MagickFalse);
264 return(MagickTrue);
265 }
266
267
268 /*
269 Compute the number of colors in Grayed R[i]=G[i]=B[i] image
270 */
GetCutColors(Image * image)271 static int GetCutColors(Image *image)
272 {
273 ExceptionInfo
274 *exception;
275
276 Quantum
277 intensity,
278 scale_intensity;
279
280 PixelPacket
281 *q;
282
283 ssize_t
284 x,
285 y;
286
287 exception=(&image->exception);
288 intensity=0;
289 scale_intensity=ScaleCharToQuantum(16);
290 for (y=0; y < (ssize_t) image->rows; y++)
291 {
292 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
293 if (q == (PixelPacket *) NULL)
294 break;
295 for (x=0; x < (ssize_t) image->columns; x++)
296 {
297 if (intensity < GetPixelRed(q))
298 intensity=GetPixelRed(q);
299 if (intensity >= scale_intensity)
300 return(255);
301 q++;
302 }
303 }
304 if (intensity < ScaleCharToQuantum(2))
305 return(2);
306 if (intensity < ScaleCharToQuantum(16))
307 return(16);
308 return((int) intensity);
309 }
310
311 /*
312 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
313 % %
314 % %
315 % %
316 % R e a d C U T I m a g e %
317 % %
318 % %
319 % %
320 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
321 %
322 % ReadCUTImage() reads an CUT X image file and returns it. It
323 % allocates the memory necessary for the new Image structure and returns a
324 % pointer to the new image.
325 %
326 % The format of the ReadCUTImage method is:
327 %
328 % Image *ReadCUTImage(const ImageInfo *image_info,ExceptionInfo *exception)
329 %
330 % A description of each parameter follows:
331 %
332 % o image_info: the image info.
333 %
334 % o exception: return any errors or warnings in this structure.
335 %
336 */
ReadCUTImage(const ImageInfo * image_info,ExceptionInfo * exception)337 static Image *ReadCUTImage(const ImageInfo *image_info,ExceptionInfo *exception)
338 {
339 #define ThrowCUTReaderException(severity,tag) \
340 { \
341 if (palette != NULL) \
342 palette=DestroyImage(palette); \
343 if (clone_info != NULL) \
344 clone_info=DestroyImageInfo(clone_info); \
345 ThrowReaderException(severity,tag); \
346 }
347
348 Image *image,*palette;
349 ImageInfo *clone_info;
350 MagickBooleanType status;
351
352 MagickOffsetType
353 offset;
354
355 size_t EncodedByte;
356 unsigned char RunCount,RunValue,RunCountMasked;
357 CUTHeader Header;
358 CUTPalHeader PalHeader;
359 ssize_t depth;
360 ssize_t i,j;
361 ssize_t ldblk;
362 unsigned char *BImgBuff=NULL,*ptrB;
363 PixelPacket *q;
364
365 /*
366 Open image file.
367 */
368 assert(image_info != (const ImageInfo *) NULL);
369 assert(image_info->signature == MagickCoreSignature);
370 if (image_info->debug != MagickFalse)
371 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
372 image_info->filename);
373 assert(exception != (ExceptionInfo *) NULL);
374 assert(exception->signature == MagickCoreSignature);
375 image=AcquireImage(image_info);
376 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
377 if (status == MagickFalse)
378 {
379 image=DestroyImageList(image);
380 return((Image *) NULL);
381 }
382 /*
383 Read CUT image.
384 */
385 palette=NULL;
386 clone_info=NULL;
387 Header.Width=ReadBlobLSBShort(image);
388 Header.Height=ReadBlobLSBShort(image);
389 Header.Reserved=ReadBlobLSBShort(image);
390
391 if (Header.Width==0 || Header.Height==0 || Header.Reserved!=0)
392 CUT_KO: ThrowCUTReaderException(CorruptImageError,"ImproperImageHeader");
393
394 /*---This code checks first line of image---*/
395 EncodedByte=ReadBlobLSBShort(image);
396 RunCount=(unsigned char) ReadBlobByte(image);
397 RunCountMasked=RunCount & 0x7F;
398 ldblk=0;
399 while((int) RunCountMasked!=0) /*end of line?*/
400 {
401 i=1;
402 if((int) RunCount<0x80) i=(ssize_t) RunCountMasked;
403 offset=SeekBlob(image,TellBlob(image)+i,SEEK_SET);
404 if (offset < 0)
405 ThrowCUTReaderException(CorruptImageError,"ImproperImageHeader");
406 if(EOFBlob(image) != MagickFalse) goto CUT_KO; /*wrong data*/
407 EncodedByte-=i+1;
408 ldblk+=(ssize_t) RunCountMasked;
409
410 RunCount=(unsigned char) ReadBlobByte(image);
411 if(EOFBlob(image) != MagickFalse) goto CUT_KO; /*wrong data: unexpected eof in line*/
412 RunCountMasked=RunCount & 0x7F;
413 }
414 if(EncodedByte!=1) goto CUT_KO; /*wrong data: size incorrect*/
415 i=0; /*guess a number of bit planes*/
416 if(ldblk==(int) Header.Width) i=8;
417 if(2*ldblk==(int) Header.Width) i=4;
418 if(8*ldblk==(int) Header.Width) i=1;
419 if(i==0) goto CUT_KO; /*wrong data: incorrect bit planes*/
420 depth=i;
421
422 image->columns=Header.Width;
423 image->rows=Header.Height;
424 image->depth=8;
425 image->colors=(size_t) (GetQuantumRange(1UL*i)+1);
426
427 if (image_info->ping != MagickFalse) goto Finish;
428 status=SetImageExtent(image,image->columns,image->rows);
429 if (status == MagickFalse)
430 {
431 InheritException(exception,&image->exception);
432 return(DestroyImageList(image));
433 }
434
435 /* ----- Do something with palette ----- */
436 if ((clone_info=CloneImageInfo(image_info)) == NULL) goto NoPalette;
437
438
439 i=(ssize_t) strlen(clone_info->filename);
440 j=i;
441 while(--i>0)
442 {
443 if(clone_info->filename[i]=='.')
444 {
445 break;
446 }
447 if(clone_info->filename[i]=='/' || clone_info->filename[i]=='\\' ||
448 clone_info->filename[i]==':' )
449 {
450 i=j;
451 break;
452 }
453 }
454
455 (void) CopyMagickString(clone_info->filename+i,".PAL",(size_t)
456 (MaxTextExtent-i));
457 if((clone_info->file=fopen_utf8(clone_info->filename,"rb"))==NULL)
458 {
459 (void) CopyMagickString(clone_info->filename+i,".pal",(size_t)
460 (MaxTextExtent-i));
461 if((clone_info->file=fopen_utf8(clone_info->filename,"rb"))==NULL)
462 {
463 clone_info->filename[i]='\0';
464 if((clone_info->file=fopen_utf8(clone_info->filename,"rb"))==NULL)
465 {
466 clone_info=DestroyImageInfo(clone_info);
467 clone_info=NULL;
468 goto NoPalette;
469 }
470 }
471 }
472
473 if( (palette=AcquireImage(clone_info))==NULL ) goto NoPalette;
474 status=OpenBlob(clone_info,palette,ReadBinaryBlobMode,exception);
475 if (status == MagickFalse)
476 {
477 ErasePalette:
478 palette=DestroyImage(palette);
479 palette=NULL;
480 goto NoPalette;
481 }
482
483
484 if(palette!=NULL)
485 {
486 (void) ReadBlob(palette,2,(unsigned char *) PalHeader.FileId);
487 if(strncmp(PalHeader.FileId,"AH",2) != 0) goto ErasePalette;
488 PalHeader.Version=ReadBlobLSBShort(palette);
489 PalHeader.Size=ReadBlobLSBShort(palette);
490 PalHeader.FileType=(char) ReadBlobByte(palette);
491 PalHeader.SubType=(char) ReadBlobByte(palette);
492 PalHeader.BoardID=ReadBlobLSBShort(palette);
493 PalHeader.GraphicsMode=ReadBlobLSBShort(palette);
494 PalHeader.MaxIndex=ReadBlobLSBShort(palette);
495 PalHeader.MaxRed=ReadBlobLSBShort(palette);
496 PalHeader.MaxGreen=ReadBlobLSBShort(palette);
497 PalHeader.MaxBlue=ReadBlobLSBShort(palette);
498 (void) ReadBlob(palette,20,(unsigned char *) PalHeader.PaletteId);
499 if (EOFBlob(image))
500 ThrowCUTReaderException(CorruptImageError,"UnexpectedEndOfFile");
501
502 if(PalHeader.MaxIndex<1) goto ErasePalette;
503 image->colors=PalHeader.MaxIndex+1;
504 if (AcquireImageColormap(image,image->colors) == MagickFalse) goto NoMemory;
505
506 if(PalHeader.MaxRed==0) PalHeader.MaxRed=(unsigned int) QuantumRange; /*avoid division by 0*/
507 if(PalHeader.MaxGreen==0) PalHeader.MaxGreen=(unsigned int) QuantumRange;
508 if(PalHeader.MaxBlue==0) PalHeader.MaxBlue=(unsigned int) QuantumRange;
509
510 for(i=0;i<=(int) PalHeader.MaxIndex;i++)
511 { /*this may be wrong- I don't know why is palette such strange*/
512 j=(ssize_t) TellBlob(palette);
513 if((j % 512)>512-6)
514 {
515 j=((j / 512)+1)*512;
516 offset=SeekBlob(palette,j,SEEK_SET);
517 if (offset < 0)
518 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
519 }
520 image->colormap[i].red=(Quantum) ReadBlobLSBShort(palette);
521 if (QuantumRange != (Quantum) PalHeader.MaxRed)
522 {
523 image->colormap[i].red=ClampToQuantum(((double)
524 image->colormap[i].red*QuantumRange+(PalHeader.MaxRed>>1))/
525 PalHeader.MaxRed);
526 }
527 image->colormap[i].green=(Quantum) ReadBlobLSBShort(palette);
528 if (QuantumRange != (Quantum) PalHeader.MaxGreen)
529 {
530 image->colormap[i].green=ClampToQuantum
531 (((double) image->colormap[i].green*QuantumRange+(PalHeader.MaxGreen>>1))/PalHeader.MaxGreen);
532 }
533 image->colormap[i].blue=(Quantum) ReadBlobLSBShort(palette);
534 if (QuantumRange != (Quantum) PalHeader.MaxBlue)
535 {
536 image->colormap[i].blue=ClampToQuantum
537 (((double)image->colormap[i].blue*QuantumRange+(PalHeader.MaxBlue>>1))/PalHeader.MaxBlue);
538 }
539
540 }
541 if (EOFBlob(image))
542 ThrowCUTReaderException(CorruptImageError,"UnexpectedEndOfFile");
543 }
544
545
546
547 NoPalette:
548 if(palette==NULL)
549 {
550
551 image->colors=256;
552 if (AcquireImageColormap(image,image->colors) == MagickFalse)
553 {
554 NoMemory:
555 ThrowCUTReaderException(ResourceLimitError,"MemoryAllocationFailed");
556 }
557
558 for (i=0; i < (ssize_t)image->colors; i++)
559 {
560 image->colormap[i].red=ScaleCharToQuantum((unsigned char) i);
561 image->colormap[i].green=ScaleCharToQuantum((unsigned char) i);
562 image->colormap[i].blue=ScaleCharToQuantum((unsigned char) i);
563 }
564 }
565
566
567 /* ----- Load RLE compressed raster ----- */
568 BImgBuff=(unsigned char *) AcquireQuantumMemory((size_t) ldblk,
569 sizeof(*BImgBuff)); /*Ldblk was set in the check phase*/
570 if(BImgBuff==NULL) goto NoMemory;
571 (void) memset(BImgBuff,0,(size_t) ldblk*sizeof(*BImgBuff));
572
573 offset=SeekBlob(image,6 /*sizeof(Header)*/,SEEK_SET);
574 if (offset < 0)
575 {
576 if (palette != NULL)
577 palette=DestroyImage(palette);
578 if (clone_info != NULL)
579 clone_info=DestroyImageInfo(clone_info);
580 BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
581 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
582 }
583 for (i=0; i < (int) Header.Height; i++)
584 {
585 EncodedByte=ReadBlobLSBShort(image);
586
587 ptrB=BImgBuff;
588 j=ldblk;
589
590 RunCount=(unsigned char) ReadBlobByte(image);
591 RunCountMasked=RunCount & 0x7F;
592
593 while ((int) RunCountMasked != 0)
594 {
595 if((ssize_t) RunCountMasked>j)
596 { /*Wrong Data*/
597 RunCountMasked=(unsigned char) j;
598 if(j==0)
599 {
600 break;
601 }
602 }
603
604 if((int) RunCount>0x80)
605 {
606 RunValue=(unsigned char) ReadBlobByte(image);
607 (void) memset(ptrB,(int) RunValue,(size_t) RunCountMasked);
608 }
609 else {
610 (void) ReadBlob(image,(size_t) RunCountMasked,ptrB);
611 }
612
613 ptrB+=(int) RunCountMasked;
614 j-=(int) RunCountMasked;
615
616 if (EOFBlob(image) != MagickFalse) goto Finish; /* wrong data: unexpected eof in line */
617 RunCount=(unsigned char) ReadBlobByte(image);
618 RunCountMasked=RunCount & 0x7F;
619 }
620
621 InsertRow(depth,BImgBuff,i,image);
622 }
623 (void) SyncImage(image);
624
625
626 /*detect monochrome image*/
627
628 if(palette==NULL)
629 { /*attempt to detect binary (black&white) images*/
630 if ((image->storage_class == PseudoClass) &&
631 (SetImageGray(image,&image->exception) != MagickFalse))
632 {
633 if(GetCutColors(image)==2)
634 {
635 for (i=0; i < (ssize_t)image->colors; i++)
636 {
637 Quantum
638 sample;
639 sample=ScaleCharToQuantum((unsigned char) i);
640 if(image->colormap[i].red!=sample) goto Finish;
641 if(image->colormap[i].green!=sample) goto Finish;
642 if(image->colormap[i].blue!=sample) goto Finish;
643 }
644
645 image->colormap[1].red=image->colormap[1].green=
646 image->colormap[1].blue=QuantumRange;
647 for (i=0; i < (ssize_t)image->rows; i++)
648 {
649 q=QueueAuthenticPixels(image,0,i,image->columns,1,exception);
650 if (q == (PixelPacket *) NULL)
651 break;
652 for (j=0; j < (ssize_t)image->columns; j++)
653 {
654 if (GetPixelRed(q) == ScaleCharToQuantum(1))
655 {
656 SetPixelRed(q,QuantumRange);
657 SetPixelGreen(q,QuantumRange);
658 SetPixelBlue(q,QuantumRange);
659 }
660 q++;
661 }
662 if (SyncAuthenticPixels(image,exception) == MagickFalse) goto Finish;
663 }
664 }
665 }
666 }
667
668 Finish:
669 if (BImgBuff != NULL)
670 BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
671 if (palette != NULL)
672 palette=DestroyImage(palette);
673 if (clone_info != NULL)
674 clone_info=DestroyImageInfo(clone_info);
675 if (EOFBlob(image) != MagickFalse)
676 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
677 image->filename);
678 (void) CloseBlob(image);
679 return(GetFirstImageInList(image));
680 }
681
682 /*
683 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
684 % %
685 % %
686 % %
687 % R e g i s t e r C U T I m a g e %
688 % %
689 % %
690 % %
691 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
692 %
693 % RegisterCUTImage() adds attributes for the CUT image format to
694 % the list of supported formats. The attributes include the image format
695 % tag, a method to read and/or write the format, whether the format
696 % supports the saving of more than one frame to the same file or blob,
697 % whether the format supports native in-memory I/O, and a brief
698 % description of the format.
699 %
700 % The format of the RegisterCUTImage method is:
701 %
702 % size_t RegisterCUTImage(void)
703 %
704 */
RegisterCUTImage(void)705 ModuleExport size_t RegisterCUTImage(void)
706 {
707 MagickInfo
708 *entry;
709
710 entry=SetMagickInfo("CUT");
711 entry->decoder=(DecodeImageHandler *) ReadCUTImage;
712 entry->seekable_stream=MagickTrue;
713 entry->description=ConstantString("DR Halo");
714 entry->magick_module=ConstantString("CUT");
715 (void) RegisterMagickInfo(entry);
716 return(MagickImageCoderSignature);
717 }
718
719 /*
720 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
721 % %
722 % %
723 % %
724 % U n r e g i s t e r C U T I m a g e %
725 % %
726 % %
727 % %
728 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
729 %
730 % UnregisterCUTImage() removes format registrations made by the
731 % CUT module from the list of supported formats.
732 %
733 % The format of the UnregisterCUTImage method is:
734 %
735 % UnregisterCUTImage(void)
736 %
737 */
UnregisterCUTImage(void)738 ModuleExport void UnregisterCUTImage(void)
739 {
740 (void) UnregisterMagickInfo("CUT");
741 }
742