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