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