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