Home | History | Annotate | Download | only in coders
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                  M   M   AAA   TTTTT  L       AAA   BBBB                    %
      6 %                  MM MM  A   A    T    L      A   A  B   B                   %
      7 %                  M M M  AAAAA    T    L      AAAAA  BBBB                    %
      8 %                  M   M  A   A    T    L      A   A  B   B                   %
      9 %                  M   M  A   A    T    LLLLL  A   A  BBBB                    %
     10 %                                                                             %
     11 %                                                                             %
     12 %                        Read MATLAB Image Format                             %
     13 %                                                                             %
     14 %                              Software Design                                %
     15 %                              Jaroslav Fojtik                                %
     16 %                                2001-2008                                    %
     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-private.h"
     57 #include "MagickCore/colormap.h"
     58 #include "MagickCore/colorspace-private.h"
     59 #include "MagickCore/distort.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/monitor.h"
     68 #include "MagickCore/monitor-private.h"
     69 #include "MagickCore/pixel-accessor.h"
     70 #include "MagickCore/quantum.h"
     71 #include "MagickCore/quantum-private.h"
     72 #include "MagickCore/option.h"
     73 #include "MagickCore/pixel.h"
     74 #include "MagickCore/resource_.h"
     75 #include "MagickCore/static.h"
     76 #include "MagickCore/string_.h"
     77 #include "MagickCore/module.h"
     78 #include "MagickCore/transform.h"
     79 #include "MagickCore/utility-private.h"
     80 #if defined(MAGICKCORE_ZLIB_DELEGATE)
     81  #include "zlib.h"
     82 #endif
     83 
     84 /*
     86   Forward declaration.
     87 */
     88 static MagickBooleanType
     89   WriteMATImage(const ImageInfo *,Image *,ExceptionInfo *);
     90 
     91 
     92 /* Auto coloring method, sorry this creates some artefact inside data
     93 MinReal+j*MaxComplex = red  MaxReal+j*MaxComplex = black
     94 MinReal+j*0 = white          MaxReal+j*0 = black
     95 MinReal+j*MinComplex = blue  MaxReal+j*MinComplex = black
     96 */
     97 
     98 typedef struct
     99 {
    100   char identific[124];
    101   unsigned short Version;
    102   char EndianIndicator[2];
    103   unsigned long DataType;
    104   unsigned long ObjectSize;
    105   unsigned long unknown1;
    106   unsigned long unknown2;
    107 
    108   unsigned short unknown5;
    109   unsigned char StructureFlag;
    110   unsigned char StructureClass;
    111   unsigned long unknown3;
    112   unsigned long unknown4;
    113   unsigned long DimFlag;
    114 
    115   unsigned long SizeX;
    116   unsigned long SizeY;
    117   unsigned short Flag1;
    118   unsigned short NameFlag;
    119 }
    120 MATHeader;
    121 
    122 static const char *MonthsTab[12]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
    123 static const char *DayOfWTab[7]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
    124 static const char *OsDesc=
    125 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
    126     "PCWIN";
    127 #else
    128  #ifdef __APPLE__
    129     "MAC";
    130  #else
    131     "LNX86";
    132  #endif
    133 #endif
    134 
    135 typedef enum
    136   {
    137     miINT8 = 1,      /* 8 bit signed */
    138     miUINT8,      /* 8 bit unsigned */
    139     miINT16,      /* 16 bit signed */
    140     miUINT16,      /* 16 bit unsigned */
    141     miINT32,      /* 32 bit signed */
    142     miUINT32,      /* 32 bit unsigned */
    143     miSINGLE,      /* IEEE 754 single precision float */
    144     miRESERVE1,
    145     miDOUBLE,      /* IEEE 754 double precision float */
    146     miRESERVE2,
    147     miRESERVE3,
    148     miINT64,      /* 64 bit signed */
    149     miUINT64,      /* 64 bit unsigned */
    150     miMATRIX,            /* MATLAB array */
    151     miCOMPRESSED,          /* Compressed Data */
    152     miUTF8,            /* Unicode UTF-8 Encoded Character Data */
    153     miUTF16,            /* Unicode UTF-16 Encoded Character Data */
    154     miUTF32      /* Unicode UTF-32 Encoded Character Data */
    155   } mat5_data_type;
    156 
    157 typedef enum
    158   {
    159     mxCELL_CLASS=1,    /* cell array */
    160     mxSTRUCT_CLASS,    /* structure */
    161     mxOBJECT_CLASS,    /* object */
    162     mxCHAR_CLASS,    /* character array */
    163     mxSPARSE_CLASS,    /* sparse array */
    164     mxDOUBLE_CLASS,    /* double precision array */
    165     mxSINGLE_CLASS,    /* single precision floating point */
    166     mxINT8_CLASS,    /* 8 bit signed integer */
    167     mxUINT8_CLASS,    /* 8 bit unsigned integer */
    168     mxINT16_CLASS,    /* 16 bit signed integer */
    169     mxUINT16_CLASS,    /* 16 bit unsigned integer */
    170     mxINT32_CLASS,    /* 32 bit signed integer */
    171     mxUINT32_CLASS,    /* 32 bit unsigned integer */
    172     mxINT64_CLASS,    /* 64 bit signed integer */
    173     mxUINT64_CLASS,    /* 64 bit unsigned integer */
    174     mxFUNCTION_CLASS            /* Function handle */
    175   } arrayclasstype;
    176 
    177 #define FLAG_COMPLEX 0x8
    178 #define FLAG_GLOBAL  0x4
    179 #define FLAG_LOGICAL 0x2
    180 
    181 static const QuantumType z2qtype[4] = {GrayQuantum, BlueQuantum, GreenQuantum, RedQuantum};
    182 
    183 
    184 static void InsertComplexDoubleRow(Image *image,double *p,int y,double MinVal,
    185   double MaxVal,ExceptionInfo *exception)
    186 {
    187 
    188   double f;
    189   int x;
    190   register Quantum *q;
    191 
    192   if (MinVal == 0)
    193     MinVal = -1;
    194   if (MaxVal == 0)
    195     MaxVal = 1;
    196 
    197   q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
    198   if (q == (Quantum *) NULL)
    199     return;
    200   for (x = 0; x < (ssize_t) image->columns; x++)
    201   {
    202     if (*p > 0)
    203     {
    204       f = (*p / MaxVal) * (QuantumRange-GetPixelRed(image,q));
    205       if (f + GetPixelRed(image,q) > QuantumRange)
    206         SetPixelRed(image,QuantumRange,q);
    207       else
    208         SetPixelRed(image,GetPixelRed(image,q)+(int) f,q);
    209       if ((int) f / 2.0 > GetPixelGreen(image,q))
    210         {
    211           SetPixelGreen(image,0,q);
    212           SetPixelBlue(image,0,q);
    213         }
    214       else
    215         {
    216           SetPixelBlue(image,GetPixelBlue(image,q)-(int) (f/2.0),q);
    217           SetPixelGreen(image,GetPixelBlue(image,q),q);
    218         }
    219     }
    220     if (*p < 0)
    221     {
    222       f = (*p / MaxVal) * (QuantumRange-GetPixelBlue(image,q));
    223       if (f+GetPixelBlue(image,q) > QuantumRange)
    224         SetPixelBlue(image,QuantumRange,q);
    225       else
    226         SetPixelBlue(image,GetPixelBlue(image,q)+(int) f,q);
    227       if ((int) f / 2.0 > GetPixelGreen(image,q))
    228         {
    229           SetPixelRed(image,0,q);
    230           SetPixelGreen(image,0,q);
    231         }
    232       else
    233         {
    234           SetPixelRed(image,GetPixelRed(image,q)-(int) (f/2.0),q);
    235           SetPixelGreen(image,GetPixelRed(image,q),q);
    236         }
    237     }
    238     p++;
    239     q+=GetPixelChannels(image);
    240   }
    241   if (!SyncAuthenticPixels(image,exception))
    242     return;
    243   return;
    244 }
    245 
    246 
    247 static void InsertComplexFloatRow(Image *image,float *p,int y,double MinVal,
    248   double MaxVal,ExceptionInfo *exception)
    249 {
    250   double f;
    251   int x;
    252   register Quantum *q;
    253 
    254   if (MinVal == 0)
    255     MinVal = -1;
    256   if (MaxVal == 0)
    257     MaxVal = 1;
    258 
    259   q = QueueAuthenticPixels(image, 0, y, image->columns, 1,exception);
    260   if (q == (Quantum *) NULL)
    261     return;
    262   for (x = 0; x < (ssize_t) image->columns; x++)
    263   {
    264     if (*p > 0)
    265     {
    266       f = (*p / MaxVal) * (QuantumRange-GetPixelRed(image,q));
    267       if (f+GetPixelRed(image,q) > QuantumRange)
    268         SetPixelRed(image,QuantumRange,q);
    269       else
    270         SetPixelRed(image,GetPixelRed(image,q)+(int) f,q);
    271       if ((int) f / 2.0 > GetPixelGreen(image,q))
    272         {
    273           SetPixelGreen(image,0,q);
    274           SetPixelBlue(image,0,q);
    275         }
    276       else
    277         {
    278           SetPixelBlue(image,GetPixelBlue(image,q)-(int) (f/2.0),q);
    279           SetPixelGreen(image,GetPixelBlue(image,q),q);
    280         }
    281     }
    282     if (*p < 0)
    283     {
    284       f = (*p / MaxVal) * (QuantumRange - GetPixelBlue(image,q));
    285       if (f + GetPixelBlue(image,q) > QuantumRange)
    286         SetPixelBlue(image,QuantumRange,q);
    287       else
    288         SetPixelBlue(image,GetPixelBlue(image,q)+
    289           (int) f,q);
    290       if ((int) f / 2.0 > GetPixelGreen(image,q))
    291         {
    292           SetPixelGreen(image,0,q);
    293           SetPixelRed(image,0,q);
    294         }
    295       else
    296         {
    297           SetPixelRed(image,GetPixelRed(image,q)-(int) (f/2.0),q);
    298           SetPixelGreen(image,GetPixelRed(image,q),q);
    299         }
    300     }
    301     p++;
    302     q++;
    303   }
    304   if (!SyncAuthenticPixels(image,exception))
    305     return;
    306   return;
    307 }
    308 
    309 
    310 /************** READERS ******************/
    311 
    312 /* This function reads one block of floats*/
    313 static void ReadBlobFloatsLSB(Image * image, size_t len, float *data)
    314 {
    315   while (len >= 4)
    316   {
    317     *data++ = ReadBlobFloat(image);
    318     len -= sizeof(float);
    319   }
    320   if (len > 0)
    321     (void) SeekBlob(image, len, SEEK_CUR);
    322 }
    323 
    324 static void ReadBlobFloatsMSB(Image * image, size_t len, float *data)
    325 {
    326   while (len >= 4)
    327   {
    328     *data++ = ReadBlobFloat(image);
    329     len -= sizeof(float);
    330   }
    331   if (len > 0)
    332     (void) SeekBlob(image, len, SEEK_CUR);
    333 }
    334 
    335 /* This function reads one block of doubles*/
    336 static void ReadBlobDoublesLSB(Image * image, size_t len, double *data)
    337 {
    338   while (len >= 8)
    339   {
    340     *data++ = ReadBlobDouble(image);
    341     len -= sizeof(double);
    342   }
    343   if (len > 0)
    344     (void) SeekBlob(image, len, SEEK_CUR);
    345 }
    346 
    347 static void ReadBlobDoublesMSB(Image * image, size_t len, double *data)
    348 {
    349   while (len >= 8)
    350   {
    351     *data++ = ReadBlobDouble(image);
    352     len -= sizeof(double);
    353   }
    354   if (len > 0)
    355     (void) SeekBlob(image, len, SEEK_CUR);
    356 }
    357 
    358 /* Calculate minimum and maximum from a given block of data */
    359 static void CalcMinMax(Image *image, int endian_indicator, int SizeX, int SizeY, size_t CellType, unsigned ldblk, void *BImgBuff, double *Min, double *Max)
    360 {
    361 MagickOffsetType filepos;
    362 int i, x;
    363 void (*ReadBlobDoublesXXX)(Image * image, size_t len, double *data);
    364 void (*ReadBlobFloatsXXX)(Image * image, size_t len, float *data);
    365 double *dblrow;
    366 float *fltrow;
    367 
    368   if (endian_indicator == LSBEndian)
    369   {
    370     ReadBlobDoublesXXX = ReadBlobDoublesLSB;
    371     ReadBlobFloatsXXX = ReadBlobFloatsLSB;
    372   }
    373   else    /* MI */
    374   {
    375     ReadBlobDoublesXXX = ReadBlobDoublesMSB;
    376     ReadBlobFloatsXXX = ReadBlobFloatsMSB;
    377   }
    378 
    379   filepos = TellBlob(image);     /* Please note that file seeking occurs only in the case of doubles */
    380   for (i = 0; i < SizeY; i++)
    381   {
    382     if (CellType==miDOUBLE)
    383     {
    384       ReadBlobDoublesXXX(image, ldblk, (double *)BImgBuff);
    385       dblrow = (double *)BImgBuff;
    386       if (i == 0)
    387       {
    388         *Min = *Max = *dblrow;
    389       }
    390       for (x = 0; x < SizeX; x++)
    391       {
    392         if (*Min > *dblrow)
    393           *Min = *dblrow;
    394         if (*Max < *dblrow)
    395           *Max = *dblrow;
    396         dblrow++;
    397       }
    398     }
    399     if (CellType==miSINGLE)
    400     {
    401       ReadBlobFloatsXXX(image, ldblk, (float *)BImgBuff);
    402       fltrow = (float *)BImgBuff;
    403       if (i == 0)
    404       {
    405         *Min = *Max = *fltrow;
    406       }
    407     for (x = 0; x < (ssize_t) SizeX; x++)
    408       {
    409         if (*Min > *fltrow)
    410           *Min = *fltrow;
    411         if (*Max < *fltrow)
    412           *Max = *fltrow;
    413         fltrow++;
    414       }
    415     }
    416   }
    417   (void) SeekBlob(image, filepos, SEEK_SET);
    418 }
    419 
    420 
    421 static void FixSignedValues(const Image *image,Quantum *q, int y)
    422 {
    423   while(y-->0)
    424   {
    425      /* Please note that negative values will overflow
    426         Q=8; QuantumRange=255: <0;127> + 127+1 = <128; 255>
    427            <-1;-128> + 127+1 = <0; 127> */
    428     SetPixelRed(image,GetPixelRed(image,q)+QuantumRange/2+1,q);
    429     SetPixelGreen(image,GetPixelGreen(image,q)+QuantumRange/2+1,q);
    430     SetPixelBlue(image,GetPixelBlue(image,q)+QuantumRange/2+1,q);
    431     q++;
    432   }
    433 }
    434 
    435 
    436 /** Fix whole row of logical/binary data. It means pack it. */
    437 static void FixLogical(unsigned char *Buff,int ldblk)
    438 {
    439 unsigned char mask=128;
    440 unsigned char *BuffL = Buff;
    441 unsigned char val = 0;
    442 
    443   while(ldblk-->0)
    444   {
    445     if(*Buff++ != 0)
    446       val |= mask;
    447 
    448     mask >>= 1;
    449     if(mask==0)
    450     {
    451       *BuffL++ = val;
    452       val = 0;
    453       mask = 128;
    454     }
    455 
    456   }
    457   *BuffL = val;
    458 }
    459 
    460 #if defined(MAGICKCORE_ZLIB_DELEGATE)
    461 static voidpf AcquireZIPMemory(voidpf context,unsigned int items,
    462   unsigned int size)
    463 {
    464   (void) context;
    465   return((voidpf) AcquireQuantumMemory(items,size));
    466 }
    467 
    468 static void RelinquishZIPMemory(voidpf context,voidpf memory)
    469 {
    470   (void) context;
    471   memory=RelinquishMagickMemory(memory);
    472 }
    473 #endif
    474 
    475 #if defined(MAGICKCORE_ZLIB_DELEGATE)
    476 /** This procedure decompreses an image block for a new MATLAB format. */
    477 static Image *DecompressBlock(Image *orig, MagickOffsetType Size, ImageInfo *clone_info, ExceptionInfo *exception)
    478 {
    479 
    480 Image *image2;
    481 void *CacheBlock, *DecompressBlock;
    482 z_stream zip_info;
    483 FILE *mat_file;
    484 size_t magick_size;
    485 size_t extent;
    486 int file;
    487 
    488 int status;
    489 int zip_status;
    490 
    491   if(clone_info==NULL) return NULL;
    492   if(clone_info->file)    /* Close file opened from previous transaction. */
    493   {
    494     fclose(clone_info->file);
    495     clone_info->file = NULL;
    496     (void) remove_utf8(clone_info->filename);
    497   }
    498 
    499   CacheBlock = AcquireQuantumMemory((size_t)((Size<16384)?Size:16384),sizeof(unsigned char *));
    500   if(CacheBlock==NULL) return NULL;
    501   DecompressBlock = AcquireQuantumMemory((size_t)(4096),sizeof(unsigned char *));
    502   if(DecompressBlock==NULL)
    503   {
    504     RelinquishMagickMemory(CacheBlock);
    505     return NULL;
    506   }
    507 
    508   mat_file=0;
    509   file = AcquireUniqueFileResource(clone_info->filename);
    510   if (file != -1)
    511     mat_file = fdopen(file,"w");
    512   if(!mat_file)
    513   {
    514     RelinquishMagickMemory(CacheBlock);
    515     RelinquishMagickMemory(DecompressBlock);
    516     (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Cannot create file stream for decompressed image");
    517     return NULL;
    518   }
    519 
    520   zip_info.zalloc=AcquireZIPMemory;
    521   zip_info.zfree=RelinquishZIPMemory;
    522   zip_info.opaque = (voidpf) NULL;
    523   zip_status = inflateInit(&zip_info);
    524   if (zip_status != Z_OK)
    525     {
    526       RelinquishMagickMemory(CacheBlock);
    527       RelinquishMagickMemory(DecompressBlock);
    528       (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
    529         "UnableToUncompressImage","`%s'",clone_info->filename);
    530       (void) fclose(mat_file);
    531       RelinquishUniqueFileResource(clone_info->filename);
    532       return NULL;
    533     }
    534   /* zip_info.next_out = 8*4;*/
    535 
    536   zip_info.avail_in = 0;
    537   zip_info.total_out = 0;
    538   while(Size>0 && !EOFBlob(orig))
    539   {
    540     magick_size = ReadBlob(orig, (Size<16384)?Size:16384, (unsigned char *) CacheBlock);
    541     zip_info.next_in = (Bytef *) CacheBlock;
    542     zip_info.avail_in = (uInt) magick_size;
    543 
    544     while(zip_info.avail_in>0)
    545     {
    546       zip_info.avail_out = 4096;
    547       zip_info.next_out = (Bytef *) DecompressBlock;
    548       zip_status = inflate(&zip_info,Z_NO_FLUSH);
    549       if ((zip_status != Z_OK) && (zip_status != Z_STREAM_END))
    550         break;
    551       extent=fwrite(DecompressBlock, 4096-zip_info.avail_out, 1, mat_file);
    552       (void) extent;
    553 
    554       if(zip_status == Z_STREAM_END) goto DblBreak;
    555     }
    556     if ((zip_status != Z_OK) && (zip_status != Z_STREAM_END))
    557       break;
    558 
    559     Size -= magick_size;
    560   }
    561 DblBreak:
    562 
    563   inflateEnd(&zip_info);
    564   (void)fclose(mat_file);
    565   RelinquishMagickMemory(CacheBlock);
    566   RelinquishMagickMemory(DecompressBlock);
    567 
    568   if((clone_info->file=fopen(clone_info->filename,"rb"))==NULL) goto UnlinkFile;
    569   if( (image2 = AcquireImage(clone_info,exception))==NULL ) goto EraseFile;
    570   status = OpenBlob(clone_info,image2,ReadBinaryBlobMode,exception);
    571   if (status == MagickFalse)
    572   {
    573     DeleteImageFromList(&image2);
    574 EraseFile:
    575     fclose(clone_info->file);
    576     clone_info->file = NULL;
    577 UnlinkFile:
    578     RelinquishUniqueFileResource(clone_info->filename);
    579     return NULL;
    580   }
    581 
    582   return image2;
    583 }
    584 #endif
    585 
    586 static Image *ReadMATImageV4(const ImageInfo *image_info,Image *image,
    587   ExceptionInfo *exception)
    588 {
    589   typedef struct {
    590     unsigned char Type[4];
    591     unsigned int nRows;
    592     unsigned int nCols;
    593     unsigned int imagf;
    594     unsigned int nameLen;
    595   } MAT4_HDR;
    596 
    597   long
    598     ldblk;
    599 
    600   EndianType
    601     endian;
    602 
    603   Image
    604     *rotate_image;
    605 
    606   MagickBooleanType
    607     status;
    608 
    609   MAT4_HDR
    610     HDR;
    611 
    612   QuantumInfo
    613     *quantum_info;
    614 
    615   QuantumFormatType
    616     format_type;
    617 
    618   register ssize_t
    619     i;
    620 
    621   ssize_t
    622     count,
    623     y;
    624 
    625   unsigned char
    626     *pixels;
    627 
    628   unsigned int
    629     depth;
    630 
    631   (void) SeekBlob(image,0,SEEK_SET);
    632   ldblk=ReadBlobLSBLong(image);
    633   if ((ldblk > 9999) || (ldblk < 0))
    634     return((Image *) NULL);
    635   HDR.Type[3]=ldblk % 10; ldblk /= 10;  /* T digit */
    636   HDR.Type[2]=ldblk % 10; ldblk /= 10;  /* P digit */
    637   HDR.Type[1]=ldblk % 10; ldblk /= 10;  /* O digit */
    638   HDR.Type[0]=ldblk;        /* M digit */
    639   if (HDR.Type[3] != 0) return((Image *) NULL);    /* Data format */
    640   if (HDR.Type[2] != 0) return((Image *) NULL);    /* Always 0 */
    641   if (HDR.Type[0] == 0)
    642     {
    643       HDR.nRows=ReadBlobLSBLong(image);
    644       HDR.nCols=ReadBlobLSBLong(image);
    645       HDR.imagf=ReadBlobLSBLong(image);
    646       HDR.nameLen=ReadBlobLSBLong(image);
    647       endian=LSBEndian;
    648     }
    649   else
    650     {
    651       HDR.nRows=ReadBlobMSBLong(image);
    652       HDR.nCols=ReadBlobMSBLong(image);
    653       HDR.imagf=ReadBlobMSBLong(image);
    654       HDR.nameLen=ReadBlobMSBLong(image);
    655       endian=MSBEndian;
    656     }
    657   if (HDR.nameLen > 0xFFFF)
    658     return((Image *) NULL);
    659   for (i=0; i < (ssize_t) HDR.nameLen; i++)
    660   {
    661     int
    662       byte;
    663 
    664     /*
    665       Skip matrix name.
    666     */
    667     byte=ReadBlobByte(image);
    668     if (byte == EOF)
    669       return((Image *) NULL);
    670   }
    671   image->columns=(size_t) HDR.nRows;
    672   image->rows=(size_t) HDR.nCols;
    673   SetImageColorspace(image,GRAYColorspace,exception);
    674   if (image_info->ping != MagickFalse)
    675     {
    676       Swap(image->columns,image->rows);
    677       return(image);
    678     }
    679   status=SetImageExtent(image,image->columns,image->rows,exception);
    680   if (status == MagickFalse)
    681     return((Image *) NULL);
    682   quantum_info=AcquireQuantumInfo(image_info,image);
    683   if (quantum_info == (QuantumInfo *) NULL)
    684     return((Image *) NULL);
    685   switch(HDR.Type[1])
    686   {
    687     case 0:
    688       format_type=FloatingPointQuantumFormat;
    689       depth=64;
    690       break;
    691     case 1:
    692       format_type=FloatingPointQuantumFormat;
    693       depth=32;
    694       break;
    695     case 2:
    696       format_type=UnsignedQuantumFormat;
    697       depth=16;
    698       break;
    699     case 3:
    700       format_type=SignedQuantumFormat;
    701       depth=16;
    702     case 4:
    703       format_type=UnsignedQuantumFormat;
    704       depth=8;
    705       break;
    706     default:
    707       format_type=UnsignedQuantumFormat;
    708       depth=8;
    709       break;
    710   }
    711   image->depth=depth;
    712   if (HDR.Type[0] != 0)
    713     SetQuantumEndian(image,quantum_info,MSBEndian);
    714   status=SetQuantumFormat(image,quantum_info,format_type);
    715   status=SetQuantumDepth(image,quantum_info,depth);
    716   status=SetQuantumEndian(image,quantum_info,endian);
    717   SetQuantumScale(quantum_info,1.0);
    718   pixels=(unsigned char *) GetQuantumPixels(quantum_info);
    719   for (y=0; y < (ssize_t) image->rows; y++)
    720   {
    721     int
    722       status;
    723 
    724     register Quantum
    725       *magick_restrict q;
    726 
    727     count=ReadBlob(image,depth/8*image->columns,(char *) pixels);
    728     if (count == -1)
    729       break;
    730     q=QueueAuthenticPixels(image,0,image->rows-y-1,image->columns,1,exception);
    731     if (q == (Quantum *) NULL)
    732       break;
    733     (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
    734       GrayQuantum,pixels,exception);
    735     if ((HDR.Type[1] == 2) || (HDR.Type[1] == 3))
    736       FixSignedValues(image,q,image->columns);
    737     if (SyncAuthenticPixels(image,exception) == MagickFalse)
    738       break;
    739     if (image->previous == (Image *) NULL)
    740       {
    741         status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
    742           image->rows);
    743         if (status == MagickFalse)
    744           break;
    745       }
    746   }
    747   if (HDR.imagf == 1)
    748     for (y=0; y < (ssize_t) image->rows; y++)
    749     {
    750       /*
    751         Read complex pixels.
    752       */
    753       count=ReadBlob(image,depth/8*image->columns,(char *) pixels);
    754       if (count == -1)
    755         break;
    756       if (HDR.Type[1] == 0)
    757         InsertComplexDoubleRow(image,(double *) pixels,y,0,0,exception);
    758       else
    759         InsertComplexFloatRow(image,(float *) pixels,y,0,0,exception);
    760     }
    761   quantum_info=DestroyQuantumInfo(quantum_info);
    762   rotate_image=RotateImage(image,90.0,exception);
    763   if (rotate_image != (Image *) NULL)
    764     {
    765       image=DestroyImage(image);
    766       image=rotate_image;
    767     }
    768   return(image);
    769 }
    770 
    771 /*
    773 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    774 %                                                                             %
    775 %                                                                             %
    776 %                                                                             %
    777 %   R e a d M A T L A B i m a g e                                             %
    778 %                                                                             %
    779 %                                                                             %
    780 %                                                                             %
    781 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    782 %
    783 %  ReadMATImage() reads an MAT X image file and returns it.  It
    784 %  allocates the memory necessary for the new Image structure and returns a
    785 %  pointer to the new image.
    786 %
    787 %  The format of the ReadMATImage method is:
    788 %
    789 %      Image *ReadMATImage(const ImageInfo *image_info,ExceptionInfo *exception)
    790 %
    791 %  A description of each parameter follows:
    792 %
    793 %    o image:  Method ReadMATImage returns a pointer to the image after
    794 %      reading. A null image is returned if there is a memory shortage or if
    795 %      the image cannot be read.
    796 %
    797 %    o image_info: Specifies a pointer to a ImageInfo structure.
    798 %
    799 %    o exception: return any errors or warnings in this structure.
    800 %
    801 */
    802 static Image *ReadMATImage(const ImageInfo *image_info,ExceptionInfo *exception)
    803 {
    804   Image *image, *image2=NULL,
    805    *rotated_image;
    806   register Quantum *q;
    807 
    808   unsigned int status;
    809   MATHeader MATLAB_HDR;
    810   size_t size;
    811   size_t CellType;
    812   QuantumInfo *quantum_info;
    813   ImageInfo *clone_info;
    814   int i;
    815   ssize_t ldblk;
    816   unsigned char *BImgBuff = NULL;
    817   double MinVal, MaxVal;
    818   unsigned z, z2;
    819   unsigned Frames;
    820   int logging;
    821   int sample_size;
    822   MagickOffsetType filepos=0x80;
    823   BlobInfo *blob;
    824   size_t one;
    825 
    826   unsigned int (*ReadBlobXXXLong)(Image *image);
    827   unsigned short (*ReadBlobXXXShort)(Image *image);
    828   void (*ReadBlobDoublesXXX)(Image * image, size_t len, double *data);
    829   void (*ReadBlobFloatsXXX)(Image * image, size_t len, float *data);
    830 
    831 
    832   assert(image_info != (const ImageInfo *) NULL);
    833   assert(image_info->signature == MagickCoreSignature);
    834   assert(exception != (ExceptionInfo *) NULL);
    835   assert(exception->signature == MagickCoreSignature);
    836   logging = LogMagickEvent(CoderEvent,GetMagickModule(),"enter");
    837 
    838   /*
    839      Open image file.
    840    */
    841   image = AcquireImage(image_info,exception);
    842 
    843   status = OpenBlob(image_info, image, ReadBinaryBlobMode, exception);
    844   if (status == MagickFalse)
    845     {
    846       image=DestroyImageList(image);
    847       return((Image *) NULL);
    848     }
    849   /*
    850      Read MATLAB image.
    851    */
    852   clone_info=CloneImageInfo(image_info);
    853   if (ReadBlob(image,124,(unsigned char *) &MATLAB_HDR.identific) != 124)
    854     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    855   if (strncmp(MATLAB_HDR.identific,"MATLAB",6) != 0)
    856     {
    857       image2=ReadMATImageV4(image_info,image,exception);
    858       if (image2  == NULL)
    859         goto MATLAB_KO;
    860       image=image2;
    861       goto END_OF_READING;
    862     }
    863   MATLAB_HDR.Version = ReadBlobLSBShort(image);
    864   if(ReadBlob(image,2,(unsigned char *) &MATLAB_HDR.EndianIndicator) != 2)
    865     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    866 
    867   if (logging)
    868     (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  Endian %c%c",
    869       MATLAB_HDR.EndianIndicator[0],MATLAB_HDR.EndianIndicator[1]);
    870   if (!strncmp(MATLAB_HDR.EndianIndicator, "IM", 2))
    871   {
    872     ReadBlobXXXLong = ReadBlobLSBLong;
    873     ReadBlobXXXShort = ReadBlobLSBShort;
    874     ReadBlobDoublesXXX = ReadBlobDoublesLSB;
    875     ReadBlobFloatsXXX = ReadBlobFloatsLSB;
    876     image->endian = LSBEndian;
    877   }
    878   else if (!strncmp(MATLAB_HDR.EndianIndicator, "MI", 2))
    879   {
    880     ReadBlobXXXLong = ReadBlobMSBLong;
    881     ReadBlobXXXShort = ReadBlobMSBShort;
    882     ReadBlobDoublesXXX = ReadBlobDoublesMSB;
    883     ReadBlobFloatsXXX = ReadBlobFloatsMSB;
    884     image->endian = MSBEndian;
    885   }
    886   else
    887     goto MATLAB_KO;    /* unsupported endian */
    888 
    889   if (strncmp(MATLAB_HDR.identific, "MATLAB", 6))
    890 MATLAB_KO: ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    891 
    892   filepos = TellBlob(image);
    893   while(!EOFBlob(image)) /* object parser loop */
    894   {
    895     Frames = 1;
    896     (void) SeekBlob(image,filepos,SEEK_SET);
    897     /* printf("pos=%X\n",TellBlob(image)); */
    898 
    899     MATLAB_HDR.DataType = ReadBlobXXXLong(image);
    900     if(EOFBlob(image)) break;
    901     MATLAB_HDR.ObjectSize = ReadBlobXXXLong(image);
    902     if(EOFBlob(image)) break;
    903     filepos += MATLAB_HDR.ObjectSize + 4 + 4;
    904 
    905     image2 = image;
    906 #if defined(MAGICKCORE_ZLIB_DELEGATE)
    907     if(MATLAB_HDR.DataType == miCOMPRESSED)
    908     {
    909       image2 = DecompressBlock(image,MATLAB_HDR.ObjectSize,clone_info,exception);
    910       if(image2==NULL) continue;
    911       MATLAB_HDR.DataType = ReadBlobXXXLong(image2); /* replace compressed object type. */
    912     }
    913 #endif
    914 
    915     if(MATLAB_HDR.DataType!=miMATRIX) continue;  /* skip another objects. */
    916 
    917     MATLAB_HDR.unknown1 = ReadBlobXXXLong(image2);
    918     MATLAB_HDR.unknown2 = ReadBlobXXXLong(image2);
    919 
    920     MATLAB_HDR.unknown5 = ReadBlobXXXLong(image2);
    921     MATLAB_HDR.StructureClass = MATLAB_HDR.unknown5 & 0xFF;
    922     MATLAB_HDR.StructureFlag = (MATLAB_HDR.unknown5>>8) & 0xFF;
    923 
    924     MATLAB_HDR.unknown3 = ReadBlobXXXLong(image2);
    925     if(image!=image2)
    926       MATLAB_HDR.unknown4 = ReadBlobXXXLong(image2);  /* ??? don't understand why ?? */
    927     MATLAB_HDR.unknown4 = ReadBlobXXXLong(image2);
    928     MATLAB_HDR.DimFlag = ReadBlobXXXLong(image2);
    929     MATLAB_HDR.SizeX = ReadBlobXXXLong(image2);
    930     MATLAB_HDR.SizeY = ReadBlobXXXLong(image2);
    931 
    932 
    933     switch(MATLAB_HDR.DimFlag)
    934     {
    935       case  8: z2=z=1; break;      /* 2D matrix*/
    936       case 12: z2=z = ReadBlobXXXLong(image2);  /* 3D matrix RGB*/
    937            (void) ReadBlobXXXLong(image2);
    938          if(z!=3) ThrowReaderException(CoderError, "MultidimensionalMatricesAreNotSupported");
    939          break;
    940       case 16: z2=z = ReadBlobXXXLong(image2);  /* 4D matrix animation */
    941          if(z!=3 && z!=1)
    942             ThrowReaderException(CoderError, "MultidimensionalMatricesAreNotSupported");
    943          Frames = ReadBlobXXXLong(image2);
    944          if (Frames == 0)
    945            ThrowReaderException(CorruptImageError,"ImproperImageHeader");
    946          break;
    947       default: ThrowReaderException(CoderError, "MultidimensionalMatricesAreNotSupported");
    948     }
    949 
    950     MATLAB_HDR.Flag1 = ReadBlobXXXShort(image2);
    951     MATLAB_HDR.NameFlag = ReadBlobXXXShort(image2);
    952 
    953     if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),
    954           "MATLAB_HDR.StructureClass %d",MATLAB_HDR.StructureClass);
    955     if (MATLAB_HDR.StructureClass != mxCHAR_CLASS &&
    956         MATLAB_HDR.StructureClass != mxSINGLE_CLASS &&    /* float + complex float */
    957         MATLAB_HDR.StructureClass != mxDOUBLE_CLASS &&    /* double + complex double */
    958         MATLAB_HDR.StructureClass != mxINT8_CLASS &&
    959         MATLAB_HDR.StructureClass != mxUINT8_CLASS &&    /* uint8 + uint8 3D */
    960         MATLAB_HDR.StructureClass != mxINT16_CLASS &&
    961         MATLAB_HDR.StructureClass != mxUINT16_CLASS &&    /* uint16 + uint16 3D */
    962         MATLAB_HDR.StructureClass != mxINT32_CLASS &&
    963         MATLAB_HDR.StructureClass != mxUINT32_CLASS &&    /* uint32 + uint32 3D */
    964         MATLAB_HDR.StructureClass != mxINT64_CLASS &&
    965         MATLAB_HDR.StructureClass != mxUINT64_CLASS)    /* uint64 + uint64 3D */
    966       ThrowReaderException(CoderError,"UnsupportedCellTypeInTheMatrix");
    967 
    968     switch (MATLAB_HDR.NameFlag)
    969     {
    970       case 0:
    971         size = ReadBlobXXXLong(image2);  /* Object name string size */
    972         size = 4 * (ssize_t) ((size + 3 + 1) / 4);
    973         (void) SeekBlob(image2, size, SEEK_CUR);
    974         break;
    975       case 1:
    976       case 2:
    977       case 3:
    978       case 4:
    979         (void) ReadBlob(image2, 4, (unsigned char *) &size); /* Object name string */
    980         break;
    981       default:
    982         goto MATLAB_KO;
    983     }
    984 
    985     CellType = ReadBlobXXXLong(image2);    /* Additional object type */
    986     if (logging)
    987       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
    988         "MATLAB_HDR.CellType: %.20g",(double) CellType);
    989 
    990     (void) ReadBlob(image2, 4, (unsigned char *) &size);     /* data size */
    991 
    992     NEXT_FRAME:
    993     switch (CellType)
    994     {
    995       case miINT8:
    996       case miUINT8:
    997         sample_size = 8;
    998         if(MATLAB_HDR.StructureFlag & FLAG_LOGICAL)
    999           image->depth = 1;
   1000         else
   1001           image->depth = 8;         /* Byte type cell */
   1002         ldblk = (ssize_t) MATLAB_HDR.SizeX;
   1003         break;
   1004       case miINT16:
   1005       case miUINT16:
   1006         sample_size = 16;
   1007         image->depth = 16;        /* Word type cell */
   1008         ldblk = (ssize_t) (2 * MATLAB_HDR.SizeX);
   1009         break;
   1010       case miINT32:
   1011       case miUINT32:
   1012         sample_size = 32;
   1013         image->depth = 32;        /* Dword type cell */
   1014         ldblk = (ssize_t) (4 * MATLAB_HDR.SizeX);
   1015         break;
   1016       case miINT64:
   1017       case miUINT64:
   1018         sample_size = 64;
   1019         image->depth = 64;        /* Qword type cell */
   1020         ldblk = (ssize_t) (8 * MATLAB_HDR.SizeX);
   1021         break;
   1022       case miSINGLE:
   1023         sample_size = 32;
   1024         image->depth = 32;        /* double type cell */
   1025         (void) SetImageOption(clone_info,"quantum:format","floating-point");
   1026         if (MATLAB_HDR.StructureFlag & FLAG_COMPLEX)
   1027   {              /* complex float type cell */
   1028   }
   1029         ldblk = (ssize_t) (4 * MATLAB_HDR.SizeX);
   1030         break;
   1031       case miDOUBLE:
   1032         sample_size = 64;
   1033         image->depth = 64;        /* double type cell */
   1034         (void) SetImageOption(clone_info,"quantum:format","floating-point");
   1035 DisableMSCWarning(4127)
   1036         if (sizeof(double) != 8)
   1037 RestoreMSCWarning
   1038           ThrowReaderException(CoderError, "IncompatibleSizeOfDouble");
   1039         if (MATLAB_HDR.StructureFlag & FLAG_COMPLEX)
   1040   {                         /* complex double type cell */
   1041   }
   1042         ldblk = (ssize_t) (8 * MATLAB_HDR.SizeX);
   1043         break;
   1044       default:
   1045         ThrowReaderException(CoderError, "UnsupportedCellTypeInTheMatrix");
   1046     }
   1047     (void) sample_size;
   1048     image->columns = MATLAB_HDR.SizeX;
   1049     image->rows = MATLAB_HDR.SizeY;
   1050     quantum_info=AcquireQuantumInfo(clone_info,image);
   1051     if (quantum_info == (QuantumInfo *) NULL)
   1052       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
   1053     one=1;
   1054     image->colors = one << image->depth;
   1055     if (image->columns == 0 || image->rows == 0)
   1056       goto MATLAB_KO;
   1057     /* Image is gray when no complex flag is set and 2D Matrix */
   1058     if ((MATLAB_HDR.DimFlag == 8) &&
   1059         ((MATLAB_HDR.StructureFlag & FLAG_COMPLEX) == 0))
   1060       {
   1061         image->type=GrayscaleType;
   1062         SetImageColorspace(image,GRAYColorspace,exception);
   1063       }
   1064 
   1065 
   1066     /*
   1067       If ping is true, then only set image size and colors without
   1068       reading any image data.
   1069     */
   1070     if (image_info->ping)
   1071     {
   1072       size_t temp = image->columns;
   1073       image->columns = image->rows;
   1074       image->rows = temp;
   1075       goto done_reading; /* !!!!!! BAD  !!!! */
   1076     }
   1077     status=SetImageExtent(image,image->columns,image->rows,exception);
   1078     if (status == MagickFalse)
   1079       return(DestroyImageList(image));
   1080 
   1081   /* ----- Load raster data ----- */
   1082     BImgBuff = (unsigned char *) AcquireQuantumMemory((size_t) (ldblk),sizeof(double));    /* Ldblk was set in the check phase */
   1083     if (BImgBuff == NULL)
   1084       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
   1085 
   1086     MinVal = 0;
   1087     MaxVal = 0;
   1088     if (CellType==miDOUBLE || CellType==miSINGLE)        /* Find Min and Max Values for floats */
   1089     {
   1090       CalcMinMax(image2, image_info->endian,  MATLAB_HDR.SizeX, MATLAB_HDR.SizeY, CellType, ldblk, BImgBuff, &quantum_info->minimum, &quantum_info->maximum);
   1091     }
   1092 
   1093     /* Main loop for reading all scanlines */
   1094     if(z==1) z=0; /* read grey scanlines */
   1095     /* else read color scanlines */
   1096     do
   1097     {
   1098       for (i = 0; i < (ssize_t) MATLAB_HDR.SizeY; i++)
   1099       {
   1100         q=GetAuthenticPixels(image,0,MATLAB_HDR.SizeY-i-1,image->columns,1,exception);
   1101         if (q == (Quantum *) NULL)
   1102   {
   1103     if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),
   1104               "  MAT set image pixels returns unexpected NULL on a row %u.", (unsigned)(MATLAB_HDR.SizeY-i-1));
   1105     goto done_reading;    /* Skip image rotation, when cannot set image pixels    */
   1106   }
   1107         if(ReadBlob(image2,ldblk,(unsigned char *)BImgBuff) != (ssize_t) ldblk)
   1108   {
   1109     if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),
   1110              "  MAT cannot read scanrow %u from a file.", (unsigned)(MATLAB_HDR.SizeY-i-1));
   1111     goto ExitLoop;
   1112   }
   1113         if((CellType==miINT8 || CellType==miUINT8) && (MATLAB_HDR.StructureFlag & FLAG_LOGICAL))
   1114         {
   1115           FixLogical((unsigned char *)BImgBuff,ldblk);
   1116           if(ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,z2qtype[z],BImgBuff,exception) <= 0)
   1117     {
   1118 ImportQuantumPixelsFailed:
   1119       if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),
   1120               "  MAT failed to ImportQuantumPixels for a row %u", (unsigned)(MATLAB_HDR.SizeY-i-1));
   1121       break;
   1122     }
   1123         }
   1124         else
   1125         {
   1126           if(ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,z2qtype[z],BImgBuff,exception) <= 0)
   1127       goto ImportQuantumPixelsFailed;
   1128 
   1129 
   1130           if (z<=1 &&       /* fix only during a last pass z==0 || z==1 */
   1131           (CellType==miINT8 || CellType==miINT16 || CellType==miINT32 || CellType==miINT64))
   1132       FixSignedValues(image,q,MATLAB_HDR.SizeX);
   1133         }
   1134 
   1135         if (!SyncAuthenticPixels(image,exception))
   1136   {
   1137     if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),
   1138             "  MAT failed to sync image pixels for a row %u", (unsigned)(MATLAB_HDR.SizeY-i-1));
   1139     goto ExitLoop;
   1140   }
   1141       }
   1142     } while(z-- >= 2);
   1143     quantum_info=DestroyQuantumInfo(quantum_info);
   1144 ExitLoop:
   1145 
   1146 
   1147     /* Read complex part of numbers here */
   1148     if (MATLAB_HDR.StructureFlag & FLAG_COMPLEX)
   1149     {        /* Find Min and Max Values for complex parts of floats */
   1150       CellType = ReadBlobXXXLong(image2);    /* Additional object type */
   1151       i = ReadBlobXXXLong(image2);           /* size of a complex part - toss away*/
   1152 
   1153       if (CellType==miDOUBLE || CellType==miSINGLE)
   1154       {
   1155         CalcMinMax(image2,  image_info->endian, MATLAB_HDR.SizeX, MATLAB_HDR.SizeY, CellType, ldblk, BImgBuff, &MinVal, &MaxVal);
   1156       }
   1157 
   1158       if (CellType==miDOUBLE)
   1159         for (i = 0; i < (ssize_t) MATLAB_HDR.SizeY; i++)
   1160   {
   1161           ReadBlobDoublesXXX(image2, ldblk, (double *)BImgBuff);
   1162           InsertComplexDoubleRow(image, (double *)BImgBuff, i, MinVal, MaxVal,
   1163             exception);
   1164   }
   1165 
   1166       if (CellType==miSINGLE)
   1167         for (i = 0; i < (ssize_t) MATLAB_HDR.SizeY; i++)
   1168   {
   1169           ReadBlobFloatsXXX(image2, ldblk, (float *)BImgBuff);
   1170           InsertComplexFloatRow(image,(float *)BImgBuff,i,MinVal,MaxVal,
   1171             exception);
   1172   }
   1173     }
   1174 
   1175       /* Image is gray when no complex flag is set and 2D Matrix AGAIN!!! */
   1176     if ((MATLAB_HDR.DimFlag == 8) &&
   1177         ((MATLAB_HDR.StructureFlag & FLAG_COMPLEX) == 0))
   1178       image->type=GrayscaleType;
   1179     if (image->depth == 1)
   1180       image->type=BilevelType;
   1181 
   1182     if(image2==image)
   1183         image2 = NULL;    /* Remove shadow copy to an image before rotation. */
   1184 
   1185       /*  Rotate image. */
   1186     rotated_image = RotateImage(image, 90.0, exception);
   1187     if (rotated_image != (Image *) NULL)
   1188     {
   1189         /* Remove page offsets added by RotateImage */
   1190       rotated_image->page.x=0;
   1191       rotated_image->page.y=0;
   1192 
   1193       blob = rotated_image->blob;
   1194       rotated_image->blob = image->blob;
   1195       rotated_image->colors = image->colors;
   1196       image->blob = blob;
   1197       AppendImageToList(&image,rotated_image);
   1198       DeleteImageFromList(&image);
   1199     }
   1200 
   1201 done_reading:
   1202 
   1203     if(image2!=NULL)
   1204       if(image2!=image)
   1205       {
   1206         DeleteImageFromList(&image2);
   1207   if(clone_info)
   1208   {
   1209           if(clone_info->file)
   1210     {
   1211             fclose(clone_info->file);
   1212             clone_info->file = NULL;
   1213             (void) remove_utf8(clone_info->filename);
   1214     }
   1215         }
   1216       }
   1217 
   1218       /* Allocate next image structure. */
   1219     AcquireNextImage(image_info,image,exception);
   1220     if (image->next == (Image *) NULL) break;
   1221     image=SyncNextImageInList(image);
   1222     image->columns=image->rows=0;
   1223     image->colors=0;
   1224 
   1225       /* row scan buffer is no longer needed */
   1226     RelinquishMagickMemory(BImgBuff);
   1227     BImgBuff = NULL;
   1228 
   1229     if(--Frames>0)
   1230     {
   1231       z = z2;
   1232       if(image2==NULL) image2 = image;
   1233       goto NEXT_FRAME;
   1234     }
   1235     if ((image2!=NULL) && (image2!=image))   /* Does shadow temporary decompressed image exist? */
   1236       {
   1237 /*  CloseBlob(image2); */
   1238         DeleteImageFromList(&image2);
   1239         if(clone_info)
   1240         {
   1241           if(clone_info->file)
   1242           {
   1243             fclose(clone_info->file);
   1244             clone_info->file = NULL;
   1245             (void) remove_utf8(clone_info->filename);
   1246           }
   1247         }
   1248         }
   1249   }
   1250 
   1251   RelinquishMagickMemory(BImgBuff);
   1252 END_OF_READING:
   1253   clone_info=DestroyImageInfo(clone_info);
   1254   CloseBlob(image);
   1255 
   1256 
   1257   {
   1258     Image *p;
   1259     ssize_t scene=0;
   1260 
   1261     /*
   1262       Rewind list, removing any empty images while rewinding.
   1263     */
   1264     p=image;
   1265     image=NULL;
   1266     while (p != (Image *) NULL)
   1267       {
   1268         Image *tmp=p;
   1269         if ((p->rows == 0) || (p->columns == 0)) {
   1270           p=p->previous;
   1271           DeleteImageFromList(&tmp);
   1272         } else {
   1273           image=p;
   1274           p=p->previous;
   1275         }
   1276       }
   1277 
   1278     /*
   1279       Fix scene numbers
   1280     */
   1281     for (p=image; p != (Image *) NULL; p=p->next)
   1282       p->scene=scene++;
   1283   }
   1284 
   1285   if(clone_info != NULL)  /* cleanup garbage file from compression */
   1286   {
   1287     if(clone_info->file)
   1288     {
   1289       fclose(clone_info->file);
   1290       clone_info->file = NULL;
   1291       (void) remove_utf8(clone_info->filename);
   1292     }
   1293     DestroyImageInfo(clone_info);
   1294     clone_info = NULL;
   1295   }
   1296   if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),"return");
   1297   if(image==NULL)
   1298     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
   1299   return (image);
   1300 }
   1301 
   1302 /*
   1304 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1305 %                                                                             %
   1306 %                                                                             %
   1307 %                                                                             %
   1308 %   R e g i s t e r M A T I m a g e                                           %
   1309 %                                                                             %
   1310 %                                                                             %
   1311 %                                                                             %
   1312 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1313 %
   1314 %  Method RegisterMATImage adds attributes for the MAT image format to
   1315 %  the list of supported formats.  The attributes include the image format
   1316 %  tag, a method to read and/or write the format, whether the format
   1317 %  supports the saving of more than one frame to the same file or blob,
   1318 %  whether the format supports native in-memory I/O, and a brief
   1319 %  description of the format.
   1320 %
   1321 %  The format of the RegisterMATImage method is:
   1322 %
   1323 %      size_t RegisterMATImage(void)
   1324 %
   1325 */
   1326 ModuleExport size_t RegisterMATImage(void)
   1327 {
   1328   MagickInfo
   1329     *entry;
   1330 
   1331   entry=AcquireMagickInfo("MAT","MAT","MATLAB level 5 image format");
   1332   entry->decoder=(DecodeImageHandler *) ReadMATImage;
   1333   entry->encoder=(EncodeImageHandler *) WriteMATImage;
   1334   entry->flags^=CoderBlobSupportFlag;
   1335   entry->flags|=CoderSeekableStreamFlag;
   1336   (void) RegisterMagickInfo(entry);
   1337   return(MagickImageCoderSignature);
   1338 }
   1339 
   1340 /*
   1342 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1343 %                                                                             %
   1344 %                                                                             %
   1345 %                                                                             %
   1346 %   U n r e g i s t e r M A T I m a g e                                       %
   1347 %                                                                             %
   1348 %                                                                             %
   1349 %                                                                             %
   1350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1351 %
   1352 %  Method UnregisterMATImage removes format registrations made by the
   1353 %  MAT module from the list of supported formats.
   1354 %
   1355 %  The format of the UnregisterMATImage method is:
   1356 %
   1357 %      UnregisterMATImage(void)
   1358 %
   1359 */
   1360 ModuleExport void UnregisterMATImage(void)
   1361 {
   1362   (void) UnregisterMagickInfo("MAT");
   1363 }
   1364 
   1365 /*
   1367 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1368 %                                                                             %
   1369 %                                                                             %
   1370 %                                                                             %
   1371 %   W r i t e M A T L A B I m a g e                                           %
   1372 %                                                                             %
   1373 %                                                                             %
   1374 %                                                                             %
   1375 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1376 %
   1377 %  Function WriteMATImage writes an Matlab matrix to a file.
   1378 %
   1379 %  The format of the WriteMATImage method is:
   1380 %
   1381 %      MagickBooleanType WriteMATImage(const ImageInfo *image_info,
   1382 %        Image *image,ExceptionInfo *exception)
   1383 %
   1384 %  A description of each parameter follows.
   1385 %
   1386 %    o image_info: Specifies a pointer to a ImageInfo structure.
   1387 %
   1388 %    o image:  A pointer to an Image structure.
   1389 %
   1390 %    o exception: return any errors or warnings in this structure.
   1391 %
   1392 */
   1393 static MagickBooleanType WriteMATImage(const ImageInfo *image_info,Image *image,
   1394   ExceptionInfo *exception)
   1395 {
   1396   ssize_t y;
   1397   unsigned z;
   1398   register const Quantum *p;
   1399 
   1400   unsigned int status;
   1401   int logging;
   1402   size_t DataSize;
   1403   char padding;
   1404   char MATLAB_HDR[0x80];
   1405   time_t current_time;
   1406   struct tm local_time;
   1407   unsigned char *pixels;
   1408   int is_gray;
   1409 
   1410   MagickOffsetType
   1411     scene;
   1412 
   1413   QuantumInfo
   1414     *quantum_info;
   1415 
   1416   /*
   1417     Open output image file.
   1418   */
   1419   assert(image_info != (const ImageInfo *) NULL);
   1420   assert(image_info->signature == MagickCoreSignature);
   1421   assert(image != (Image *) NULL);
   1422   assert(image->signature == MagickCoreSignature);
   1423   logging=LogMagickEvent(CoderEvent,GetMagickModule(),"enter MAT");
   1424   (void) logging;
   1425   assert(exception != (ExceptionInfo *) NULL);
   1426   assert(exception->signature == MagickCoreSignature);
   1427   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
   1428   if (status == MagickFalse)
   1429     return(MagickFalse);
   1430   image->depth=8;
   1431 
   1432   current_time=time((time_t *) NULL);
   1433 #if defined(MAGICKCORE_HAVE_LOCALTIME_R)
   1434   (void) localtime_r(&current_time,&local_time);
   1435 #else
   1436   (void) memcpy(&local_time,localtime(&current_time),sizeof(local_time));
   1437 #endif
   1438   (void) memset(MATLAB_HDR,' ',MagickMin(sizeof(MATLAB_HDR),124));
   1439   FormatLocaleString(MATLAB_HDR,sizeof(MATLAB_HDR),
   1440     "MATLAB 5.0 MAT-file, Platform: %s, Created on: %s %s %2d %2d:%2d:%2d %d",
   1441     OsDesc,DayOfWTab[local_time.tm_wday],MonthsTab[local_time.tm_mon],
   1442     local_time.tm_mday,local_time.tm_hour,local_time.tm_min,
   1443     local_time.tm_sec,local_time.tm_year+1900);
   1444   MATLAB_HDR[0x7C]=0;
   1445   MATLAB_HDR[0x7D]=1;
   1446   MATLAB_HDR[0x7E]='I';
   1447   MATLAB_HDR[0x7F]='M';
   1448   (void) WriteBlob(image,sizeof(MATLAB_HDR),(unsigned char *) MATLAB_HDR);
   1449   scene=0;
   1450   do
   1451   {
   1452     (void) TransformImageColorspace(image,sRGBColorspace,exception);
   1453     is_gray = SetImageGray(image,exception);
   1454     z = is_gray ? 0 : 3;
   1455 
   1456     /*
   1457       Store MAT header.
   1458     */
   1459     DataSize = image->rows /*Y*/ * image->columns /*X*/;
   1460     if(!is_gray) DataSize *= 3 /*Z*/;
   1461     padding=((unsigned char)(DataSize-1) & 0x7) ^ 0x7;
   1462 
   1463     (void) WriteBlobLSBLong(image, miMATRIX);
   1464     (void) WriteBlobLSBLong(image, (unsigned int) DataSize+padding+(is_gray ? 48 : 56));
   1465     (void) WriteBlobLSBLong(image, 0x6); /* 0x88 */
   1466     (void) WriteBlobLSBLong(image, 0x8); /* 0x8C */
   1467     (void) WriteBlobLSBLong(image, 0x6); /* 0x90 */
   1468     (void) WriteBlobLSBLong(image, 0);
   1469     (void) WriteBlobLSBLong(image, 0x5); /* 0x98 */
   1470     (void) WriteBlobLSBLong(image, is_gray ? 0x8 : 0xC); /* 0x9C - DimFlag */
   1471     (void) WriteBlobLSBLong(image, (unsigned int) image->rows);    /* x: 0xA0 */
   1472     (void) WriteBlobLSBLong(image, (unsigned int) image->columns); /* y: 0xA4 */
   1473     if(!is_gray)
   1474     {
   1475       (void) WriteBlobLSBLong(image, 3); /* z: 0xA8 */
   1476       (void) WriteBlobLSBLong(image, 0);
   1477     }
   1478     (void) WriteBlobLSBShort(image, 1);  /* 0xB0 */
   1479     (void) WriteBlobLSBShort(image, 1);  /* 0xB2 */
   1480     (void) WriteBlobLSBLong(image, 'M'); /* 0xB4 */
   1481     (void) WriteBlobLSBLong(image, 0x2); /* 0xB8 */
   1482     (void) WriteBlobLSBLong(image, (unsigned int) DataSize); /* 0xBC */
   1483 
   1484     /*
   1485       Store image data.
   1486     */
   1487     quantum_info=AcquireQuantumInfo(image_info,image);
   1488     if (quantum_info == (QuantumInfo *) NULL)
   1489       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
   1490     pixels=(unsigned char *) GetQuantumPixels(quantum_info);
   1491     do
   1492     {
   1493       for (y=0; y < (ssize_t)image->columns; y++)
   1494       {
   1495         p=GetVirtualPixels(image,y,0,1,image->rows,exception);
   1496         if (p == (const Quantum *) NULL)
   1497           break;
   1498         (void) ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
   1499           z2qtype[z],pixels,exception);
   1500         (void) WriteBlob(image,image->rows,pixels);
   1501       }
   1502       if (SyncAuthenticPixels(image,exception) == MagickFalse)
   1503         break;
   1504     } while(z-- >= 2);
   1505     while(padding-->0) (void) WriteBlobByte(image,0);
   1506     quantum_info=DestroyQuantumInfo(quantum_info);
   1507     if (GetNextImageInList(image) == (Image *) NULL)
   1508       break;
   1509     image=SyncNextImageInList(image);
   1510     status=SetImageProgress(image,SaveImagesTag,scene++,
   1511       GetImageListLength(image));
   1512     if (status == MagickFalse)
   1513       break;
   1514   } while (image_info->adjoin != MagickFalse);
   1515   (void) CloseBlob(image);
   1516   return(MagickTrue);
   1517 }
   1518