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