Coverage Report

Created: 2026-02-14 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/imagemagick/coders/mat.c
Line
Count
Source
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
%  Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization         %
20
%  dedicated to making software imaging solutions freely available.           %
21
%                                                                             %
22
%  You may not use this file except in compliance with the License.  You may  %
23
%  obtain a copy of the License at                                            %
24
%                                                                             %
25
%    https://imagemagick.org/license/                                         %
26
%                                                                             %
27
%  Unless required by applicable law or agreed to in writing, software        %
28
%  distributed under the License is distributed on an "AS IS" BASIS,          %
29
%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
30
%  See the License for the specific language governing permissions and        %
31
%  limitations under the License.                                             %
32
%                                                                             %
33
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
34
%
35
%
36
*/
37

38
/*
39
  Include declarations.
40
*/
41
#include "MagickCore/studio.h"
42
#include "MagickCore/attribute.h"
43
#include "MagickCore/blob.h"
44
#include "MagickCore/blob-private.h"
45
#include "MagickCore/cache.h"
46
#include "MagickCore/color-private.h"
47
#include "MagickCore/colormap.h"
48
#include "MagickCore/colorspace-private.h"
49
#include "MagickCore/distort.h"
50
#include "MagickCore/exception.h"
51
#include "MagickCore/exception-private.h"
52
#include "MagickCore/image.h"
53
#include "MagickCore/image-private.h"
54
#include "MagickCore/list.h"
55
#include "MagickCore/magick.h"
56
#include "MagickCore/memory_.h"
57
#include "MagickCore/monitor.h"
58
#include "MagickCore/monitor-private.h"
59
#include "MagickCore/pixel-accessor.h"
60
#include "MagickCore/quantum.h"
61
#include "MagickCore/quantum-private.h"
62
#include "MagickCore/option.h"
63
#include "MagickCore/pixel.h"
64
#include "MagickCore/resource_.h"
65
#include "MagickCore/static.h"
66
#include "MagickCore/string_.h"
67
#include "MagickCore/module.h"
68
#include "MagickCore/timer-private.h"
69
#include "MagickCore/transform.h"
70
#include "MagickCore/utility-private.h"
71
#include "coders/coders-private.h"
72
#if defined(MAGICKCORE_ZLIB_DELEGATE)
73
 #include "zlib.h"
74
#endif
75

76
/*
77
  Forward declaration.
78
*/
79
static MagickBooleanType
80
  WriteMATImage(const ImageInfo *,Image *,ExceptionInfo *);
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 int DataType;
95
  unsigned int ObjectSize;
96
  unsigned int unknown1;
97
  unsigned int unknown2;
98
99
  unsigned short unknown5;
100
  unsigned char StructureFlag;
101
  unsigned char StructureClass;
102
  unsigned int unknown3;
103
  unsigned int unknown4;
104
  unsigned int DimFlag;
105
106
  unsigned int SizeX;
107
  unsigned int SizeY;
108
  unsigned short Flag1;
109
  unsigned short NameFlag;
110
}
111
MATHeader;
112
113
static const char
114
  MonthsTab[12][4] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
115
116
static const char
117
   DayOfWTab[7][4] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
118
119
static const char
120
  OsDesc[] =
121
#if defined(MAGICKCORE_WINDOWS_SUPPORT)
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
7.96k
#define FLAG_COMPLEX 0x8
174
#define FLAG_GLOBAL  0x4
175
29.0k
#define FLAG_LOGICAL 0x2
176
177
static const QuantumType z2qtype[4] = {GrayQuantum, BlueQuantum, GreenQuantum, RedQuantum};
178
179
static void InsertComplexDoubleRow(Image *image,double *p,int y,double MinVal,
180
  double MaxVal,ExceptionInfo *exception)
181
15.3k
{
182
15.3k
  double f;
183
15.3k
  int x;
184
15.3k
  Quantum *q;
185
186
15.3k
  if (MinVal >= 0)
187
14.8k
    MinVal = -1;
188
15.3k
  if (MaxVal <= 0)
189
13.7k
    MaxVal = 1;
190
191
15.3k
  q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
192
15.3k
  if (q == (Quantum *) NULL)
193
0
    return;
194
6.17M
  for (x = 0; x < (ssize_t) image->columns; x++)
195
6.16M
  {
196
6.16M
    if (*p > 0)
197
68.8k
      {
198
68.8k
        f=(*p/MaxVal)*((double) QuantumRange-(double) GetPixelRed(image,q));
199
68.8k
        if (IsNaN(f) != 0)      
200
2.69k
          f=0.0;
201
68.8k
        if ((f+(double) GetPixelRed(image,q)) >= (double) QuantumRange)
202
4.12k
          SetPixelRed(image,QuantumRange,q);
203
64.7k
        else
204
64.7k
          SetPixelRed(image,GetPixelRed(image,q)+ClampToQuantum(f),q);
205
68.8k
        f=(double) GetPixelGreen(image,q)-f/2.0;
206
68.8k
        if (IsNaN(f) != 0)      
207
6.63k
          f=0.0;
208
68.8k
        if (f <= 0.0)
209
64.3k
          {
210
64.3k
            SetPixelGreen(image,0,q);
211
64.3k
            SetPixelBlue(image,0,q);
212
64.3k
          }
213
4.52k
        else
214
4.52k
          {
215
4.52k
            SetPixelBlue(image,ClampToQuantum(f),q);
216
4.52k
            SetPixelGreen(image,ClampToQuantum(f),q);
217
4.52k
          }
218
68.8k
      }
219
6.16M
    if (*p < 0)
220
16.5k
      {
221
16.5k
        f=(*p/MinVal)*(Quantum) (QuantumRange-GetPixelBlue(image,q));
222
16.5k
        if (IsNaN(f) != 0)      
223
502
          f=0.0;
224
16.5k
        if ((f+(double) GetPixelBlue(image,q)) >= (double) QuantumRange)
225
3.96k
          SetPixelBlue(image,QuantumRange,q);
226
12.5k
        else
227
12.5k
          SetPixelBlue(image,GetPixelBlue(image,q)+ClampToQuantum(f),q);
228
16.5k
        f=GetPixelGreen(image,q)-f/2.0;
229
16.5k
        if (f <= 0.0)
230
7.87k
          {
231
7.87k
            SetPixelRed(image,0,q);
232
7.87k
            SetPixelGreen(image,0,q);
233
7.87k
          }
234
8.65k
        else
235
8.65k
          {
236
8.65k
            SetPixelRed(image,ClampToQuantum(f),q);
237
8.65k
            SetPixelGreen(image,ClampToQuantum(f),q);
238
8.65k
          }
239
16.5k
      }
240
6.16M
    p++;
241
6.16M
    q++;
242
6.16M
  }
243
15.3k
  if (!SyncAuthenticPixels(image,exception))
244
0
    return;
245
15.3k
  return;
246
15.3k
}
247
248
static void InsertComplexFloatRow(Image *image,float *p,int y,double MinVal,
249
  double MaxVal,ExceptionInfo *exception)
250
37.4k
{
251
37.4k
  double f;
252
37.4k
  int x;
253
37.4k
  Quantum *q;
254
255
37.4k
  if (MinVal >= 0)
256
37.0k
    MinVal = -1;
257
37.4k
  if (MaxVal <= 0)
258
36.1k
    MaxVal = 1;
259
260
37.4k
  q = QueueAuthenticPixels(image, 0, y, image->columns, 1,exception);
261
37.4k
  if (q == (Quantum *) NULL)
262
0
    return;
263
29.1M
  for (x = 0; x < (ssize_t) image->columns; x++)
264
29.1M
  {
265
29.1M
    if (*p > 0)
266
242k
      {
267
242k
        f=((double) *p/MaxVal)*((double) QuantumRange-(double)
268
242k
          GetPixelRed(image,q));
269
242k
        if (IsNaN(f) != 0)      
270
1.37k
          f=0.0;
271
242k
        if ((f+GetPixelRed(image,q)) < QuantumRange)
272
85.7k
          SetPixelRed(image,GetPixelRed(image,q)+ClampToQuantum(f),q);
273
156k
        else
274
156k
          SetPixelRed(image,QuantumRange,q);
275
242k
        f/=2.0;
276
242k
        if (f < GetPixelGreen(image,q))
277
189k
          {
278
189k
            SetPixelBlue(image,GetPixelBlue(image,q)-ClampToQuantum(f),q);
279
189k
            SetPixelGreen(image,GetPixelBlue(image,q),q);
280
189k
          }
281
53.6k
        else
282
53.6k
          {
283
53.6k
            SetPixelGreen(image,0,q);
284
53.6k
            SetPixelBlue(image,0,q);
285
53.6k
          }
286
242k
      }
287
29.1M
    if (*p < 0)
288
143k
      {
289
143k
        f=(*p/MaxVal)*(Quantum) (QuantumRange-GetPixelBlue(image,q));
290
143k
        if (IsNaN(f) != 0)      
291
1.32k
          f=0.0;
292
143k
        if ((f+GetPixelBlue(image,q)) < QuantumRange)
293
32.0k
          SetPixelBlue(image,GetPixelBlue(image,q)+ClampToQuantum(f),q);
294
111k
        else
295
111k
          SetPixelBlue(image,QuantumRange,q);
296
143k
        f/=2.0;
297
143k
        if (f < GetPixelGreen(image,q))
298
102k
          {
299
102k
            SetPixelRed(image,GetPixelRed(image,q)-ClampToQuantum(f),q);
300
102k
            SetPixelGreen(image,GetPixelRed(image,q),q);
301
102k
          }
302
41.2k
        else
303
41.2k
          {
304
41.2k
            SetPixelGreen(image,0,q);
305
41.2k
            SetPixelRed(image,0,q);
306
41.2k
          }
307
143k
      }
308
29.1M
    p++;
309
29.1M
    q++;
310
29.1M
  }
311
37.4k
  if (!SyncAuthenticPixels(image,exception))
312
0
    return;
313
37.4k
  return;
314
37.4k
}
315
316
317
/************** READERS ******************/
318
319
/* This function reads one block of floats*/
320
static void ReadBlobFloatsLSB(Image * image, size_t len, float *data)
321
1.56k
{
322
2.59k
  while (len >= 4)
323
1.02k
  {
324
1.02k
    *data++ = ReadBlobFloat(image);
325
1.02k
    len -= sizeof(float);
326
1.02k
  }
327
1.56k
  if (len > 0)
328
1.07k
    (void) SeekBlob(image, (MagickOffsetType) len, SEEK_CUR);
329
1.56k
}
330
331
static void ReadBlobFloatsMSB(Image * image, size_t len, float *data)
332
5.59k
{
333
14.2k
  while (len >= 4)
334
8.67k
  {
335
8.67k
    *data++ = ReadBlobFloat(image);
336
8.67k
    len -= sizeof(float);
337
8.67k
  }
338
5.59k
  if (len > 0)
339
2.04k
    (void) SeekBlob(image, (MagickOffsetType) len, SEEK_CUR);
340
5.59k
}
341
342
/* This function reads one block of doubles*/
343
static void ReadBlobDoublesLSB(Image * image, size_t len, double *data)
344
1.65k
{
345
2.50k
  while (len >= 8)
346
852
  {
347
852
    *data++ = ReadBlobDouble(image);
348
852
    len -= sizeof(double);
349
852
  }
350
1.65k
  if (len > 0)
351
1.08k
    (void) SeekBlob(image, (MagickOffsetType) len, SEEK_CUR);
352
1.65k
}
353
354
static void ReadBlobDoublesMSB(Image * image, size_t len, double *data)
355
4.36k
{
356
9.01k
  while (len >= 8)
357
4.64k
  {
358
4.64k
    *data++ = ReadBlobDouble(image);
359
4.64k
    len -= sizeof(double);
360
4.64k
  }
361
4.36k
  if (len > 0)
362
2.27k
    (void) SeekBlob(image, (MagickOffsetType) len, SEEK_CUR);
363
4.36k
}
364
365
/* Calculate minimum and maximum from a given block of data */
366
static void CalcMinMax(Image *image, int endian_indicator, ssize_t SizeX, ssize_t SizeY, size_t CellType, unsigned ldblk, void *BImgBuff, double *Min, double *Max)
367
1.69k
{
368
1.69k
MagickOffsetType filepos;
369
1.69k
ssize_t i, x;
370
1.69k
void (*ReadBlobDoublesXXX)(Image * image, size_t len, double *data);
371
1.69k
void (*ReadBlobFloatsXXX)(Image * image, size_t len, float *data);
372
1.69k
double *dblrow;
373
1.69k
float *fltrow;
374
375
1.69k
  if (endian_indicator == LSBEndian)
376
0
  {
377
0
    ReadBlobDoublesXXX = ReadBlobDoublesLSB;
378
0
    ReadBlobFloatsXXX = ReadBlobFloatsLSB;
379
0
  }
380
1.69k
  else    /* MI */
381
1.69k
  {
382
1.69k
    ReadBlobDoublesXXX = ReadBlobDoublesMSB;
383
1.69k
    ReadBlobFloatsXXX = ReadBlobFloatsMSB;
384
1.69k
  }
385
386
1.69k
  filepos = TellBlob(image);     /* Please note that file seeking occurs only in the case of doubles */
387
10.4k
  for (i = 0; i < SizeY; i++)
388
8.76k
  {
389
8.76k
    if (CellType==miDOUBLE)
390
3.70k
    {
391
3.70k
      ReadBlobDoublesXXX(image, ldblk, (double *)BImgBuff);
392
3.70k
      dblrow = (double *)BImgBuff;
393
3.70k
      if (i == 0)
394
587
      {
395
587
        *Min = *Max = *dblrow;
396
587
      }
397
10.6k
      for (x = 0; x < SizeX; x++)
398
6.93k
      {
399
6.93k
        if (*Min > *dblrow)
400
861
          *Min = *dblrow;
401
6.93k
        if (*Max < *dblrow)
402
394
          *Max = *dblrow;
403
6.93k
        dblrow++;
404
6.93k
      }
405
3.70k
    }
406
8.76k
    if (CellType==miSINGLE)
407
5.06k
    {
408
5.06k
      ReadBlobFloatsXXX(image, ldblk, (float *)BImgBuff);
409
5.06k
      fltrow = (float *)BImgBuff;
410
5.06k
      if (i == 0)
411
1.11k
      {
412
1.11k
        *Min = *Max = *fltrow;
413
1.11k
      }
414
16.4k
    for (x = 0; x < (ssize_t) SizeX; x++)
415
11.3k
      {
416
11.3k
        if (*Min > *fltrow)
417
486
          *Min = *fltrow;
418
11.3k
        if (*Max < *fltrow)
419
468
          *Max = *fltrow;
420
11.3k
        fltrow++;
421
11.3k
      }
422
5.06k
    }
423
8.76k
  }
424
1.69k
  (void) SeekBlob(image, (MagickOffsetType) filepos, SEEK_SET);
425
1.69k
}
426
427
428
static void FixSignedValues(const Image *image,Quantum *q, ssize_t y)
429
70.8k
{
430
35.5M
  while(y-->0)
431
35.5M
  {
432
     /* Please note that negative values will overflow
433
        Q=8; QuantumRange=255: <0;127> + 127+1 = <128; 255>
434
           <-1;-128> + 127+1 = <0; 127> */
435
35.5M
    SetPixelRed(image,GetPixelRed(image,q)+QuantumRange/2+1,q);
436
35.5M
    SetPixelGreen(image,GetPixelGreen(image,q)+QuantumRange/2+1,q);
437
35.5M
    SetPixelBlue(image,GetPixelBlue(image,q)+QuantumRange/2+1,q);
438
35.5M
    q++;
439
35.5M
  }
440
70.8k
}
441
442
443
/** Fix whole row of logical/binary data. It means pack it. */
444
static void FixLogical(unsigned char *Buff,ssize_t ldblk)
445
8.79k
{
446
8.79k
unsigned char mask=128;
447
8.79k
unsigned char *BuffL = Buff;
448
8.79k
unsigned char val = 0;
449
450
8.79k
  if (ldblk == 0)
451
0
    return;
452
453
46.6k
  while(ldblk-->0)
454
37.8k
  {
455
37.8k
    if(*Buff++ != 0)
456
22.0k
      val |= mask;
457
458
37.8k
    mask >>= 1;
459
37.8k
    if(mask==0)
460
3.53k
    {
461
3.53k
      *BuffL++ = val;
462
3.53k
      val = 0;
463
3.53k
      mask = 128;
464
3.53k
    }
465
466
37.8k
  }
467
8.79k
  *BuffL = val;
468
8.79k
}
469
470
#if defined(MAGICKCORE_ZLIB_DELEGATE)
471
static voidpf AcquireZIPMemory(voidpf context,unsigned int items,
472
  unsigned int size)
473
1.21k
{
474
1.21k
  (void) context;
475
1.21k
  return((voidpf) AcquireQuantumMemory(items,size));
476
1.21k
}
477
478
static void RelinquishZIPMemory(voidpf context,voidpf memory)
479
1.21k
{
480
1.21k
  (void) context;
481
1.21k
  memory=RelinquishMagickMemory(memory);
482
1.21k
}
483
#endif
484
485
#if defined(MAGICKCORE_ZLIB_DELEGATE)
486
/** This procedure decompreses an image block for a new MATLAB format. */
487
static Image *decompress_block(Image *orig, unsigned int *Size, ImageInfo *clone_info, ExceptionInfo *exception)
488
23.6k
{
489
490
23.6k
Image *image2;
491
23.6k
void *cache_block, *decompress_block;
492
23.6k
z_stream zip_info;
493
23.6k
FILE *mat_file;
494
23.6k
ssize_t magick_size;
495
23.6k
size_t extent;
496
23.6k
int file;
497
498
23.6k
MagickBooleanType status;
499
23.6k
int zip_status;
500
23.6k
ssize_t total_size = 0;
501
502
23.6k
  if(clone_info==NULL) return NULL;
503
23.6k
  if(clone_info->file)    /* Close file opened from previous transaction. */
504
0
  {
505
0
    fclose(clone_info->file);
506
0
    clone_info->file = NULL;
507
0
    (void) remove_utf8(clone_info->filename);
508
0
  }
509
510
23.6k
  cache_block = AcquireQuantumMemory((size_t)(*Size < MagickMinBufferExtent) ? *Size: MagickMinBufferExtent,sizeof(unsigned char *));
511
23.6k
  if(cache_block==NULL) return NULL;
512
23.1k
  decompress_block = AcquireQuantumMemory((size_t)(4096),sizeof(unsigned char *));
513
23.1k
  if(decompress_block==NULL)
514
0
  {
515
0
    RelinquishMagickMemory(cache_block);
516
0
    return NULL;
517
0
  }
518
519
23.1k
  mat_file=0;
520
23.1k
  file = AcquireUniqueFileResource(clone_info->filename);
521
23.1k
  if (file != -1)
522
1.02k
    mat_file = fdopen(file,"w");
523
23.1k
  if(!mat_file)
524
22.1k
  {
525
22.1k
    RelinquishMagickMemory(cache_block);
526
22.1k
    RelinquishMagickMemory(decompress_block);
527
22.1k
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Cannot create file stream for decompressed image");
528
22.1k
    return NULL;
529
22.1k
  }
530
531
1.02k
  (void) memset(&zip_info,0,sizeof(zip_info));
532
1.02k
  zip_info.zalloc=AcquireZIPMemory;
533
1.02k
  zip_info.zfree=RelinquishZIPMemory;
534
1.02k
  zip_info.opaque = (voidpf) NULL;
535
1.02k
  zip_status = inflateInit(&zip_info);
536
1.02k
  if (zip_status != Z_OK)
537
0
    {
538
0
      RelinquishMagickMemory(cache_block);
539
0
      RelinquishMagickMemory(decompress_block);
540
0
      (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
541
0
        "UnableToUncompressImage","`%s'",clone_info->filename);
542
0
      (void) fclose(mat_file);
543
0
      RelinquishUniqueFileResource(clone_info->filename);
544
0
      return NULL;
545
0
    }
546
  /* zip_info.next_out = 8*4;*/
547
548
1.02k
  zip_info.avail_in = 0;
549
1.02k
  zip_info.total_out = 0;
550
1.61k
  while(*Size>0 && !EOFBlob(orig))
551
1.02k
  {
552
1.02k
    magick_size = ReadBlob(orig, (*Size < MagickMinBufferExtent) ? *Size : MagickMinBufferExtent, (unsigned char *) cache_block);
553
1.02k
    if (magick_size == 0)
554
49
      break;
555
973
    zip_info.next_in = (Bytef *) cache_block;
556
973
    zip_info.avail_in = (uInt) magick_size;
557
558
1.63k
    while(zip_info.avail_in>0)
559
1.03k
    {
560
1.03k
      zip_info.avail_out = 4096;
561
1.03k
      zip_info.next_out = (Bytef *) decompress_block;
562
1.03k
      zip_status = inflate(&zip_info,Z_NO_FLUSH);
563
1.03k
      if ((zip_status != Z_OK) && (zip_status != Z_STREAM_END))
564
367
        break;
565
671
      extent=fwrite(decompress_block,1,4096-zip_info.avail_out,mat_file);
566
671
      (void) extent;
567
671
      total_size += 4096-zip_info.avail_out;
568
569
671
      if(zip_status == Z_STREAM_END) goto DblBreak;
570
671
    }
571
963
    if ((zip_status != Z_OK) && (zip_status != Z_STREAM_END))
572
367
      break;
573
574
596
    *Size -= (unsigned int) magick_size;
575
596
  }
576
1.02k
DblBreak:
577
578
1.02k
  inflateEnd(&zip_info);
579
1.02k
  (void)fclose(mat_file);
580
1.02k
  RelinquishMagickMemory(cache_block);
581
1.02k
  RelinquishMagickMemory(decompress_block);
582
1.02k
  *Size = (unsigned int) total_size;
583
584
1.02k
  if((clone_info->file=fopen_utf8(clone_info->filename,"rb"))==NULL) goto UnlinkFile;
585
1.02k
  if( (image2 = AcquireImage(clone_info,exception))==NULL ) goto EraseFile;
586
1.02k
  image2->columns=0;
587
1.02k
  image2->rows=0;
588
1.02k
  status = OpenBlob(clone_info,image2,ReadBinaryBlobMode,exception);
589
1.02k
  if (status == MagickFalse)
590
0
  {
591
0
    DeleteImageFromList(&image2);
592
0
EraseFile:
593
0
    fclose(clone_info->file);
594
0
    clone_info->file = NULL;
595
0
UnlinkFile:
596
0
    RelinquishUniqueFileResource(clone_info->filename);
597
0
    return NULL;
598
0
  }
599
600
1.02k
  return image2;
601
1.02k
}
602
#endif
603
604
static Image *ReadMATImageV4(const ImageInfo *image_info,Image *image,
605
  ExceptionInfo *exception)
606
2.02k
{
607
2.02k
  typedef struct {
608
2.02k
    unsigned char Type[4];
609
2.02k
    unsigned int nRows;
610
2.02k
    unsigned int nCols;
611
2.02k
    unsigned int imagf;
612
2.02k
    unsigned int nameLen;
613
2.02k
  } MAT4_HDR;
614
615
2.02k
  EndianType
616
2.02k
    endian;
617
618
2.02k
  Image
619
2.02k
    *rotated_image;
620
621
2.02k
  MagickBooleanType
622
2.02k
    status;
623
624
2.02k
  MAT4_HDR
625
2.02k
    HDR;
626
627
2.02k
  QuantumInfo
628
2.02k
    *quantum_info;
629
630
2.02k
  QuantumFormatType
631
2.02k
    format_type;
632
633
2.02k
  ssize_t
634
2.02k
    count,
635
2.02k
    i,
636
2.02k
    ldblk,
637
2.02k
    y;
638
639
2.02k
  unsigned char
640
2.02k
    *pixels;
641
642
2.02k
  unsigned int
643
2.02k
    depth;
644
645
2.02k
  quantum_info=(QuantumInfo *) NULL;
646
2.02k
  (void) SeekBlob(image,0,SEEK_SET);
647
2.02k
  status=MagickTrue;
648
2.88k
  while (EOFBlob(image) == MagickFalse)
649
2.88k
  {
650
    /*
651
     Object parser loop.
652
    */
653
2.88k
    ldblk=ReadBlobLSBLong(image);
654
2.88k
    if(EOFBlob(image)) break;
655
2.84k
    if ((ldblk > 9999) || (ldblk < 0))
656
914
      break;
657
1.92k
    HDR.Type[3]=(unsigned char) (ldblk % 10); ldblk /= 10;  /* T digit */
658
1.92k
    HDR.Type[2]=(unsigned char) (ldblk % 10); ldblk /= 10;  /* P digit */
659
1.92k
    HDR.Type[1]=(unsigned char) (ldblk % 10); ldblk /= 10;  /* O digit */
660
1.92k
    HDR.Type[0]=(unsigned char) (ldblk);        /* M digit */
661
1.92k
    if (HDR.Type[3] != 0)
662
29
      break;  /* Data format */
663
1.89k
    if (HDR.Type[2] != 0)
664
7
      break;  /* Always 0 */
665
1.89k
    if (HDR.Type[0] == 0)
666
1.44k
      {
667
1.44k
        HDR.nRows=ReadBlobLSBLong(image);
668
1.44k
        HDR.nCols=ReadBlobLSBLong(image);
669
1.44k
        HDR.imagf=ReadBlobLSBLong(image);
670
1.44k
        HDR.nameLen=ReadBlobLSBLong(image);
671
1.44k
        endian=LSBEndian;
672
1.44k
      }
673
445
    else
674
445
      {
675
445
        HDR.nRows=ReadBlobMSBLong(image);
676
445
        HDR.nCols=ReadBlobMSBLong(image);
677
445
        HDR.imagf=ReadBlobMSBLong(image);
678
445
        HDR.nameLen=ReadBlobMSBLong(image);
679
445
        endian=MSBEndian;
680
445
      }
681
1.89k
    if ((HDR.imagf != 0) && (HDR.imagf != 1))
682
97
      break;
683
1.79k
    if (HDR.nameLen > 0xFFFF)
684
25
      return(DestroyImageList(image));
685
243k
    for (i=0; i < (ssize_t) HDR.nameLen; i++)
686
241k
    {
687
241k
      int
688
241k
        byte;
689
690
      /*
691
        Skip matrix name.
692
      */
693
241k
      byte=ReadBlobByte(image);
694
241k
      if (byte == EOF)
695
124
        {
696
124
          ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
697
124
            image->filename);
698
124
          break;
699
124
        }
700
241k
    }
701
1.77k
    image->columns=(size_t) HDR.nRows;
702
1.77k
    image->rows=(size_t) HDR.nCols;
703
1.77k
    if ((image->columns == 0) || (image->rows == 0))
704
199
      return(DestroyImageList(image));
705
1.57k
    if (image_info->ping != MagickFalse)
706
0
      {
707
0
        Swap(image->columns,image->rows);
708
0
        if(HDR.imagf==1) ldblk *= 2;
709
0
        SeekBlob(image, (MagickOffsetType) HDR.nCols*ldblk, SEEK_CUR);
710
0
        if ((image->columns == 0) || (image->rows == 0))
711
0
          return(image->previous == (Image *) NULL ? DestroyImageList(image)
712
0
            : image);
713
0
        goto skip_reading_current;
714
0
      }
715
1.57k
    status=SetImageExtent(image,image->columns,image->rows,exception);
716
1.57k
    if (status == MagickFalse)
717
166
      return(DestroyImageList(image));
718
1.40k
    (void) SetImageBackgroundColor(image,exception);
719
1.40k
    (void) SetImageColorspace(image,GRAYColorspace,exception);
720
1.40k
    quantum_info=AcquireQuantumInfo(image_info,image);
721
1.40k
    if (quantum_info == (QuantumInfo *) NULL)
722
0
      return(DestroyImageList(image));
723
1.40k
    switch(HDR.Type[1])
724
1.40k
    {
725
891
      case 0:
726
891
        format_type=FloatingPointQuantumFormat;
727
891
        depth=64;
728
891
        break;
729
96
      case 1:
730
96
        format_type=FloatingPointQuantumFormat;
731
96
        depth=32;
732
96
        break;
733
148
      case 2:
734
148
        format_type=UnsignedQuantumFormat;
735
148
        depth=16;
736
148
        break;
737
16
      case 3:
738
16
        format_type=SignedQuantumFormat;
739
16
        depth=16;
740
16
        break;
741
28
      case 4:
742
28
        format_type=UnsignedQuantumFormat;
743
28
        depth=8;
744
28
        break;
745
226
      default:
746
226
        format_type=UnsignedQuantumFormat;
747
226
        depth=8;
748
226
        break;
749
1.40k
    }
750
1.40k
    image->depth=depth;
751
1.40k
    if (HDR.Type[0] != 0)
752
399
      SetQuantumEndian(image,quantum_info,MSBEndian);
753
1.40k
    status=SetQuantumFormat(image,quantum_info,format_type);
754
1.40k
    status=SetQuantumDepth(image,quantum_info,depth);
755
1.40k
    status=SetQuantumEndian(image,quantum_info,endian);
756
1.40k
    SetQuantumScale(quantum_info,1.0);
757
1.40k
    pixels=(unsigned char *) GetQuantumPixels(quantum_info);
758
182k
    for (y=0; y < (ssize_t) image->rows; y++)
759
181k
    {
760
181k
      Quantum
761
181k
        *magick_restrict q;
762
763
181k
      count=ReadBlob(image,depth/8*image->columns,(char *) pixels);
764
181k
      if (count == -1)
765
0
        break;
766
181k
      q=QueueAuthenticPixels(image,0,(ssize_t) image->rows-y-1,image->columns,1,
767
181k
        exception);
768
181k
      if (q == (Quantum *) NULL)
769
0
        break;
770
181k
      (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
771
181k
        GrayQuantum,pixels,exception);
772
181k
      if ((HDR.Type[1] == 2) || (HDR.Type[1] == 3))
773
54.8k
        FixSignedValues(image,q,(int) image->columns);
774
181k
      if (SyncAuthenticPixels(image,exception) == MagickFalse)
775
0
        break;
776
181k
      if (image->previous == (Image *) NULL)
777
167k
        {
778
167k
          status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
779
167k
            image->rows);
780
167k
          if (status == MagickFalse)
781
0
            break;
782
167k
        }
783
181k
    }
784
1.40k
    if (HDR.imagf == 1)
785
48.8k
      for (y=0; y < (ssize_t) image->rows; y++)
786
48.4k
      {
787
        /*
788
          Read complex pixels.
789
        */
790
48.4k
        count=ReadBlob(image,depth/8*image->columns,(char *) pixels);
791
48.4k
        if (count == -1)
792
0
          break;
793
48.4k
        if (HDR.Type[1] == 0)
794
13.0k
          InsertComplexDoubleRow(image,(double *) pixels,(int) y,0,0,exception);
795
35.4k
        else
796
35.4k
          InsertComplexFloatRow(image,(float *) pixels,(int) y,0,0,exception);
797
48.4k
      }
798
1.40k
    if (quantum_info != (QuantumInfo *) NULL)
799
1.40k
      quantum_info=DestroyQuantumInfo(quantum_info);
800
1.40k
    if (EOFBlob(image) != MagickFalse)
801
539
      {
802
539
        ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
803
539
          image->filename);
804
539
        break;
805
539
      }
806
866
    rotated_image=RotateImage(image,90.0,exception);
807
866
    if (rotated_image != (Image *) NULL)
808
866
      {
809
866
        rotated_image->page.x=0;
810
866
        rotated_image->page.y=0;
811
866
        rotated_image->colors = image->colors;
812
866
        DestroyBlob(rotated_image);
813
866
        rotated_image->blob=ReferenceBlob(image->blob);
814
866
        ReplaceImageInList(&image,rotated_image);
815
866
        image=rotated_image;
816
866
      }
817
    /*
818
      Proceed to next image.
819
    */
820
866
    if (image_info->number_scenes != 0)
821
0
      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
822
0
        break;
823
    /*
824
      Allocate next image structure.
825
    */
826
866
skip_reading_current:
827
866
    if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
828
0
      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
829
0
        break;
830
866
    AcquireNextImage(image_info,image,exception);
831
866
    if (GetNextImageInList(image) == (Image *) NULL)
832
0
      {
833
0
        status=MagickFalse;
834
0
        break;
835
0
      }
836
866
    image=SyncNextImageInList(image);
837
866
    status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
838
866
      GetBlobSize(image));
839
866
    if (status == MagickFalse)
840
0
      break;
841
866
  }
842
1.63k
  if (CloseBlob(image) == MagickFalse)
843
429
    status=MagickFalse;
844
1.63k
  if (status == MagickFalse)
845
429
    return(DestroyImageList(image));
846
1.20k
  return(GetFirstImageInList(image));
847
1.63k
}
848

849
/*
850
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
851
%                                                                             %
852
%                                                                             %
853
%                                                                             %
854
%   R e a d M A T L A B i m a g e                                             %
855
%                                                                             %
856
%                                                                             %
857
%                                                                             %
858
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
859
%
860
%  ReadMATImage() reads an MAT X image file and returns it.  It
861
%  allocates the memory necessary for the new Image structure and returns a
862
%  pointer to the new image.
863
%
864
%  The format of the ReadMATImage method is:
865
%
866
%      Image *ReadMATImage(const ImageInfo *image_info,ExceptionInfo *exception)
867
%
868
%  A description of each parameter follows:
869
%
870
%    o image:  Method ReadMATImage returns a pointer to the image after
871
%      reading. A null image is returned if there is a memory shortage or if
872
%      the image cannot be read.
873
%
874
%    o image_info: Specifies a pointer to a ImageInfo structure.
875
%
876
%    o exception: return any errors or warnings in this structure.
877
%
878
*/
879
static Image *ReadMATImage(const ImageInfo *image_info,ExceptionInfo *exception)
880
5.04k
{
881
5.04k
  Image *image, *image2=NULL,
882
5.04k
   *rotated_image;
883
5.04k
  Quantum *q;
884
885
5.04k
  unsigned int status;
886
5.04k
  MATHeader MATLAB_HDR;
887
5.04k
  size_t size;
888
5.04k
  size_t CellType;
889
5.04k
  QuantumInfo *quantum_info;
890
5.04k
  ImageInfo *clone_info;
891
5.04k
  ssize_t i;
892
5.04k
  ssize_t ldblk;
893
5.04k
  unsigned char *BImgBuff = NULL;
894
5.04k
  double MinVal, MaxVal;
895
5.04k
  unsigned z, z2;
896
5.04k
  unsigned Frames;
897
5.04k
  MagickBooleanType logging;
898
5.04k
  int sample_size;
899
5.04k
  MagickOffsetType filepos=0x80;
900
901
5.04k
  unsigned int (*ReadBlobXXXLong)(Image *image);
902
5.04k
  unsigned short (*ReadBlobXXXShort)(Image *image);
903
5.04k
  void (*ReadBlobDoublesXXX)(Image * image, size_t len, double *data);
904
5.04k
  void (*ReadBlobFloatsXXX)(Image * image, size_t len, float *data);
905
906
907
5.04k
  assert(image_info != (const ImageInfo *) NULL);
908
5.04k
  assert(image_info->signature == MagickCoreSignature);
909
5.04k
  assert(exception != (ExceptionInfo *) NULL);
910
5.04k
  assert(exception->signature == MagickCoreSignature);
911
5.04k
  logging = LogMagickEvent(CoderEvent,GetMagickModule(),"enter");
912
913
  /*
914
     Open image file.
915
   */
916
5.04k
  image = AcquireImage(image_info,exception);
917
5.04k
  image2 = (Image *) NULL;
918
919
5.04k
  status = OpenBlob(image_info, image, ReadBinaryBlobMode, exception);
920
5.04k
  if (status == MagickFalse)
921
0
    {
922
0
      image=DestroyImageList(image);
923
0
      return((Image *) NULL);
924
0
    }
925
  /*
926
     Read MATLAB image.
927
   */
928
5.04k
  quantum_info=(QuantumInfo *) NULL;
929
5.04k
  clone_info=(ImageInfo *) NULL;
930
5.04k
  if (ReadBlob(image,124,(unsigned char *) &MATLAB_HDR.identific) != 124)
931
4.26k
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
932
4.26k
  if (strncmp(MATLAB_HDR.identific,"MATLAB",6) != 0)
933
2.02k
    {
934
2.02k
      image=ReadMATImageV4(image_info,image,exception);
935
2.02k
      if (image == NULL)
936
819
        {
937
819
          if ((image != image2) && (image2 != (Image *) NULL))
938
0
            image2=DestroyImage(image2);
939
819
          if (clone_info != (ImageInfo *) NULL)
940
0
            clone_info=DestroyImageInfo(clone_info);
941
819
          return((Image *) NULL);
942
819
        }
943
1.20k
      goto END_OF_READING;
944
2.02k
    }
945
2.23k
  MATLAB_HDR.Version = ReadBlobLSBShort(image);
946
2.23k
  if(ReadBlob(image,2,(unsigned char *) &MATLAB_HDR.EndianIndicator) != 2)
947
2.23k
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
948
949
2.23k
  if (logging)
950
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  Endian %c%c",
951
0
      MATLAB_HDR.EndianIndicator[0],MATLAB_HDR.EndianIndicator[1]);
952
2.23k
  if (!strncmp(MATLAB_HDR.EndianIndicator, "IM", 2))
953
1.11k
  {
954
1.11k
    ReadBlobXXXLong = ReadBlobLSBLong;
955
1.11k
    ReadBlobXXXShort = ReadBlobLSBShort;
956
1.11k
    ReadBlobDoublesXXX = ReadBlobDoublesLSB;
957
1.11k
    ReadBlobFloatsXXX = ReadBlobFloatsLSB;
958
1.11k
    image->endian = LSBEndian;
959
1.11k
  }
960
1.12k
  else if (!strncmp(MATLAB_HDR.EndianIndicator, "MI", 2))
961
1.09k
  {
962
1.09k
    ReadBlobXXXLong = ReadBlobMSBLong;
963
1.09k
    ReadBlobXXXShort = ReadBlobMSBShort;
964
1.09k
    ReadBlobDoublesXXX = ReadBlobDoublesMSB;
965
1.09k
    ReadBlobFloatsXXX = ReadBlobFloatsMSB;
966
1.09k
    image->endian = MSBEndian;
967
1.09k
  }
968
30
  else
969
30
    {
970
523
MATLAB_KO:
971
523
      if ((image != image2) && (image2 != (Image *) NULL))
972
1
        image2=DestroyImage(image2);
973
523
      if (clone_info != (ImageInfo *) NULL)
974
322
        clone_info=DestroyImageInfo(clone_info);
975
523
      ThrowReaderException(CorruptImageError,"ImproperImageHeader");
976
0
    }
977
978
2.20k
  filepos = TellBlob(image);
979
30.0k
  while(filepos < (MagickOffsetType) GetBlobSize(image) && !EOFBlob(image)) /* object parser loop */
980
29.5k
  {
981
29.5k
    Frames = 1;
982
29.5k
    if(filepos > (MagickOffsetType) GetBlobSize(image) || filepos < 0)
983
0
      break;
984
29.5k
    if(SeekBlob(image,(MagickOffsetType) filepos,SEEK_SET) != filepos) break;
985
    /* printf("pos=%X\n",TellBlob(image)); */
986
987
29.5k
    MATLAB_HDR.DataType = ReadBlobXXXLong(image);
988
29.5k
    if(EOFBlob(image)) break;
989
29.3k
    MATLAB_HDR.ObjectSize = ReadBlobXXXLong(image);
990
29.3k
    if(EOFBlob(image)) break;
991
29.3k
    if((MagickSizeType) (MATLAB_HDR.ObjectSize+filepos) >= GetBlobSize(image))
992
232
      goto MATLAB_KO;
993
29.0k
    filepos += (MagickOffsetType) MATLAB_HDR.ObjectSize + 4 + 4;
994
995
29.0k
    if (clone_info != (ImageInfo *) NULL)
996
22.2k
      clone_info=DestroyImageInfo(clone_info);
997
29.0k
    clone_info=CloneImageInfo(image_info);
998
29.0k
    if ((image != image2) && (image2 != (Image *) NULL))
999
0
      image2=DestroyImage(image2);
1000
29.0k
    image2 = image;
1001
29.0k
#if defined(MAGICKCORE_ZLIB_DELEGATE)
1002
29.0k
    if(MATLAB_HDR.DataType == miCOMPRESSED)
1003
23.6k
    {
1004
23.6k
      image2 = decompress_block(image,&MATLAB_HDR.ObjectSize,clone_info,exception);
1005
23.6k
      if(image2==NULL) continue;
1006
1.02k
      MATLAB_HDR.DataType = ReadBlobXXXLong(image2); /* replace compressed object type. */
1007
1.02k
    }
1008
6.49k
#endif
1009
1010
6.49k
    if (MATLAB_HDR.DataType != miMATRIX)
1011
3.99k
      {
1012
3.99k
        clone_info=DestroyImageInfo(clone_info);
1013
3.99k
#if defined(MAGICKCORE_ZLIB_DELEGATE)
1014
3.99k
        if (image2 != image)
1015
1.01k
          DeleteImageFromList(&image2);
1016
3.99k
#endif
1017
3.99k
        continue;  /* skip another objects. */
1018
3.99k
      }
1019
1020
2.49k
    MATLAB_HDR.unknown1 = ReadBlobXXXLong(image2);
1021
2.49k
    MATLAB_HDR.unknown2 = ReadBlobXXXLong(image2);
1022
1023
2.49k
    MATLAB_HDR.unknown5 = (unsigned short) ReadBlobXXXLong(image2);
1024
2.49k
    MATLAB_HDR.StructureClass = MATLAB_HDR.unknown5 & 0xFF;
1025
2.49k
    MATLAB_HDR.StructureFlag = (MATLAB_HDR.unknown5>>8) & 0xFF;
1026
1027
2.49k
    MATLAB_HDR.unknown3 = ReadBlobXXXLong(image2);
1028
2.49k
    if(image!=image2)
1029
9
      MATLAB_HDR.unknown4 = ReadBlobXXXLong(image2);  /* ??? don't understand why ?? */
1030
2.49k
    MATLAB_HDR.unknown4 = ReadBlobXXXLong(image2);
1031
2.49k
    MATLAB_HDR.DimFlag = ReadBlobXXXLong(image2);
1032
2.49k
    MATLAB_HDR.SizeX = ReadBlobXXXLong(image2);
1033
2.49k
    MATLAB_HDR.SizeY = ReadBlobXXXLong(image2);
1034
1035
1036
2.49k
    switch(MATLAB_HDR.DimFlag)
1037
2.49k
    {
1038
1.29k
      case  8: z2=z=1; break;      /* 2D matrix*/
1039
73
      case 12: z2=z = ReadBlobXXXLong(image2);  /* 3D matrix RGB*/
1040
73
           (void) ReadBlobXXXLong(image2);
1041
73
         if(z!=3)
1042
34
           {
1043
34
             if (clone_info != (ImageInfo *) NULL)
1044
34
               clone_info=DestroyImageInfo(clone_info);
1045
34
             if ((image != image2) && (image2 != (Image *) NULL))
1046
1
               image2=DestroyImage(image2);
1047
34
             ThrowReaderException(CoderError,
1048
34
               "MultidimensionalMatricesAreNotSupported");
1049
0
           }
1050
39
         break;
1051
1.10k
      case 16: z2=z = ReadBlobXXXLong(image2);  /* 4D matrix animation */
1052
1.10k
         if(z!=3 && z!=1)
1053
47
           {
1054
47
             if (clone_info != (ImageInfo *) NULL)
1055
47
               clone_info=DestroyImageInfo(clone_info);
1056
47
             if ((image != image2) && (image2 != (Image *) NULL))
1057
0
               image2=DestroyImage(image2);
1058
47
             ThrowReaderException(CoderError,
1059
47
               "MultidimensionalMatricesAreNotSupported");
1060
0
           }
1061
1.06k
          Frames = ReadBlobXXXLong(image2);
1062
1.06k
          if (Frames == 0)
1063
10
            {
1064
10
              if (clone_info != (ImageInfo *) NULL)
1065
10
                clone_info=DestroyImageInfo(clone_info);
1066
10
              if ((image != image2) && (image2 != (Image *) NULL))
1067
0
                image2=DestroyImage(image2);
1068
10
              ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1069
0
            }
1070
1.05k
          if (AcquireMagickResource(ListLengthResource,Frames) == MagickFalse)
1071
63
            {
1072
63
              if (clone_info != (ImageInfo *) NULL)
1073
63
                clone_info=DestroyImageInfo(clone_info);
1074
63
              if ((image != image2) && (image2 != (Image *) NULL))
1075
0
                image2=DestroyImage(image2);
1076
63
              ThrowReaderException(ResourceLimitError,"ListLengthExceedsLimit");
1077
0
            }
1078
989
         break;
1079
989
      default:
1080
20
        if (clone_info != (ImageInfo *) NULL)
1081
20
          clone_info=DestroyImageInfo(clone_info);
1082
20
        if ((image != image2) && (image2 != (Image *) NULL))
1083
1
          image2=DestroyImage(image2);
1084
20
        ThrowReaderException(CoderError, "MultidimensionalMatricesAreNotSupported");
1085
2.49k
    }
1086
1087
2.32k
    MATLAB_HDR.Flag1 = ReadBlobXXXShort(image2);
1088
2.32k
    MATLAB_HDR.NameFlag = ReadBlobXXXShort(image2);
1089
1090
2.32k
    if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),
1091
0
          "MATLAB_HDR.StructureClass %d",MATLAB_HDR.StructureClass);
1092
2.32k
    if (MATLAB_HDR.StructureClass != mxCHAR_CLASS &&
1093
2.01k
        MATLAB_HDR.StructureClass != mxSINGLE_CLASS &&    /* float + complex float */
1094
1.86k
        MATLAB_HDR.StructureClass != mxDOUBLE_CLASS &&    /* double + complex double */
1095
1.68k
        MATLAB_HDR.StructureClass != mxINT8_CLASS &&
1096
1.31k
        MATLAB_HDR.StructureClass != mxUINT8_CLASS &&    /* uint8 + uint8 3D */
1097
1.20k
        MATLAB_HDR.StructureClass != mxINT16_CLASS &&
1098
674
        MATLAB_HDR.StructureClass != mxUINT16_CLASS &&    /* uint16 + uint16 3D */
1099
510
        MATLAB_HDR.StructureClass != mxINT32_CLASS &&
1100
316
        MATLAB_HDR.StructureClass != mxUINT32_CLASS &&    /* uint32 + uint32 3D */
1101
233
        MATLAB_HDR.StructureClass != mxINT64_CLASS &&
1102
135
        MATLAB_HDR.StructureClass != mxUINT64_CLASS)    /* uint64 + uint64 3D */
1103
17
      {
1104
17
        if ((image2 != (Image*) NULL) && (image2 != image))
1105
0
          {
1106
0
            CloseBlob(image2);
1107
0
            DeleteImageFromList(&image2);
1108
0
          }
1109
17
        if (clone_info != (ImageInfo *) NULL)
1110
17
          clone_info=DestroyImageInfo(clone_info);
1111
17
        ThrowReaderException(CoderError,"UnsupportedCellTypeInTheMatrix");
1112
0
      }
1113
1114
2.30k
    switch (MATLAB_HDR.NameFlag)
1115
2.30k
    {
1116
282
      case 0:
1117
282
        size = ReadBlobXXXLong(image2);  /* Object name string size */
1118
282
        size = 4 * (((size_t) size + 3 + 1) / 4);
1119
282
        (void) SeekBlob(image2, (MagickOffsetType) size, SEEK_CUR);
1120
282
        break;
1121
1.29k
      case 1:
1122
1.59k
      case 2:
1123
1.82k
      case 3:
1124
2.02k
      case 4:
1125
2.02k
        (void) ReadBlob(image2, 4, (unsigned char *) &size); /* Object name string */
1126
2.02k
        break;
1127
2
      default:
1128
2
        goto MATLAB_KO;
1129
2.30k
    }
1130
1131
2.30k
    CellType = ReadBlobXXXLong(image2);    /* Additional object type */
1132
2.30k
    if (logging)
1133
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1134
0
        "MATLAB_HDR.CellType: %.20g",(double) CellType);
1135
1136
    /* data size */
1137
2.30k
    if (ReadBlob(image2, 4, (unsigned char *) &size) != 4)
1138
147
      goto MATLAB_KO;
1139
1140
5.24k
    NEXT_FRAME:
1141
5.24k
    switch (CellType)
1142
5.24k
    {
1143
2.35k
      case miINT8:
1144
2.83k
      case miUINT8:
1145
2.83k
        sample_size = 8;
1146
2.83k
        if(MATLAB_HDR.StructureFlag & FLAG_LOGICAL)
1147
744
          image->depth = 1;
1148
2.09k
        else
1149
2.09k
          image->depth = 8;         /* Byte type cell */
1150
2.83k
        ldblk = (ssize_t) MATLAB_HDR.SizeX;
1151
2.83k
        break;
1152
148
      case miINT16:
1153
257
      case miUINT16:
1154
257
        sample_size = 16;
1155
257
        image->depth = 16;        /* Word type cell */
1156
257
        ldblk = (ssize_t) (2 * MATLAB_HDR.SizeX);
1157
257
        break;
1158
281
      case miINT32:
1159
357
      case miUINT32:
1160
357
        sample_size = 32;
1161
357
        image->depth = 32;        /* Dword type cell */
1162
357
        ldblk = (ssize_t) (4 * MATLAB_HDR.SizeX);
1163
357
        break;
1164
271
      case miINT64:
1165
348
      case miUINT64:
1166
348
        sample_size = 64;
1167
348
        image->depth = 64;        /* Qword type cell */
1168
348
        ldblk = (ssize_t) (8 * MATLAB_HDR.SizeX);
1169
348
        break;
1170
1.00k
      case miSINGLE:
1171
1.00k
        sample_size = 32;
1172
1.00k
        image->depth = 32;        /* double type cell */
1173
1.00k
        (void) SetImageOption(clone_info,"quantum:format","floating-point");
1174
1.00k
        if (MATLAB_HDR.StructureFlag & FLAG_COMPLEX)
1175
308
          {              /* complex float type cell */
1176
308
          }
1177
1.00k
        ldblk = (ssize_t) (4 * MATLAB_HDR.SizeX);
1178
1.00k
        break;
1179
413
      case miDOUBLE:
1180
413
        sample_size = 64;
1181
413
        image->depth = 64;        /* double type cell */
1182
413
        (void) SetImageOption(clone_info,"quantum:format","floating-point");
1183
413
DisableMSCWarning(4127)
1184
413
        if (sizeof(double) != 8)
1185
0
RestoreMSCWarning
1186
0
          {
1187
0
            if (clone_info != (ImageInfo *) NULL)
1188
0
              clone_info=DestroyImageInfo(clone_info);
1189
0
            if ((image != image2) && (image2 != (Image *) NULL))
1190
0
              image2=DestroyImage(image2);
1191
0
            ThrowReaderException(CoderError, "IncompatibleSizeOfDouble");
1192
0
          }
1193
413
        if (MATLAB_HDR.StructureFlag & FLAG_COMPLEX)
1194
212
          {                         /* complex double type cell */
1195
212
          }
1196
413
        ldblk = (ssize_t) (8 * MATLAB_HDR.SizeX);
1197
413
        break;
1198
24
      default:
1199
24
        if ((image != image2) && (image2 != (Image *) NULL))
1200
1
          image2=DestroyImage(image2);
1201
24
        if (clone_info)
1202
24
          clone_info=DestroyImageInfo(clone_info);
1203
24
        ThrowReaderException(CoderError, "UnsupportedCellTypeInTheMatrix");
1204
5.24k
    }
1205
5.21k
    (void) sample_size;
1206
5.21k
    image->columns = MATLAB_HDR.SizeX;
1207
5.21k
    image->rows = MATLAB_HDR.SizeY;
1208
5.21k
    image->colors = (size_t) GetQuantumRange(image->depth);
1209
5.21k
    if (image->columns == 0 || image->rows == 0)
1210
2
      goto MATLAB_KO;
1211
5.21k
    if((size_t)ldblk*MATLAB_HDR.SizeY > MATLAB_HDR.ObjectSize)
1212
110
      goto MATLAB_KO;
1213
    /* Image is gray when no complex flag is set and 2D Matrix */
1214
5.10k
    if ((MATLAB_HDR.DimFlag == 8) &&
1215
1.03k
        ((MATLAB_HDR.StructureFlag & FLAG_COMPLEX) == 0))
1216
444
      {
1217
444
        image->type=GrayscaleType;
1218
444
        SetImageColorspace(image,GRAYColorspace,exception);
1219
444
      }
1220
1221
1222
    /*
1223
      If ping is true, then only set image size and colors without
1224
      reading any image data.
1225
    */
1226
5.10k
    if (image_info->ping)
1227
0
    {
1228
0
      size_t temp = image->columns;
1229
0
      image->columns = image->rows;
1230
0
      image->rows = temp;
1231
0
      goto done_reading; /* !!!!!! BAD  !!!! */
1232
0
    }
1233
5.10k
    status=SetImageExtent(image,image->columns,image->rows,exception);
1234
5.10k
    if (status == MagickFalse)
1235
21
      {
1236
21
        if (clone_info != (ImageInfo *) NULL)
1237
21
          clone_info=DestroyImageInfo(clone_info);
1238
21
        if ((image != image2) && (image2 != (Image *) NULL))
1239
0
          image2=DestroyImage(image2);
1240
21
        return(DestroyImageList(image));
1241
21
      }
1242
5.08k
    (void) SetImageBackgroundColor(image,exception);
1243
5.08k
    quantum_info=AcquireQuantumInfo(clone_info,image);
1244
5.08k
    if (quantum_info == (QuantumInfo *) NULL)
1245
0
      {
1246
0
        if (clone_info != (ImageInfo *) NULL)
1247
0
          clone_info=DestroyImageInfo(clone_info);
1248
0
        if ((image != image2) && (image2 != (Image *) NULL))
1249
0
          image2=DestroyImage(image2);
1250
0
        ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1251
0
      }
1252
1253
  /* ----- Load raster data ----- */
1254
5.08k
    BImgBuff = (unsigned char *) AcquireQuantumMemory((size_t) (ldblk),sizeof(double));    /* Ldblk was set in the check phase */
1255
5.08k
    if (BImgBuff == NULL)
1256
0
      {
1257
0
        if (clone_info != (ImageInfo *) NULL)
1258
0
          clone_info=DestroyImageInfo(clone_info);
1259
0
        if ((image != image2) && (image2 != (Image *) NULL))
1260
0
          image2=DestroyImage(image2);
1261
0
        if (quantum_info != (QuantumInfo *) NULL)
1262
0
          quantum_info=DestroyQuantumInfo(quantum_info);
1263
0
        ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1264
0
      }
1265
5.08k
    (void) memset(BImgBuff,0,(size_t) ldblk*sizeof(double));
1266
1267
5.08k
    MinVal = 0;
1268
5.08k
    MaxVal = 0;
1269
5.08k
    if (CellType==miDOUBLE || CellType==miSINGLE)        /* Find Min and Max Values for floats */
1270
1.38k
      {
1271
1.38k
        CalcMinMax(image2,(int) image_info->endian,MATLAB_HDR.SizeX,
1272
1.38k
          MATLAB_HDR.SizeY,CellType,(unsigned int) ldblk,BImgBuff,
1273
1.38k
          &quantum_info->minimum,&quantum_info->maximum);
1274
1.38k
      }
1275
1276
    /* Main loop for reading all scanlines */
1277
5.08k
    if(z==1) z=0; /* read grey scanlines */
1278
    /* else read color scanlines */
1279
5.08k
    do
1280
6.05k
    {
1281
40.8k
      for (i = 0; i < (ssize_t) MATLAB_HDR.SizeY; i++)
1282
35.2k
      {
1283
35.2k
        q=GetAuthenticPixels(image,0,MATLAB_HDR.SizeY-i-1,image->columns,1,exception);
1284
35.2k
        if (q == (Quantum *) NULL)
1285
0
          {
1286
0
            if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),
1287
0
              "  MAT set image pixels returns unexpected NULL on a row %u.", (unsigned)(MATLAB_HDR.SizeY-i-1));
1288
0
            goto done_reading;    /* Skip image rotation, when cannot set image pixels    */
1289
0
          }
1290
35.2k
        if(ReadBlob(image2,(size_t) ldblk,(unsigned char *) BImgBuff) != (ssize_t) ldblk)
1291
475
          {
1292
475
            if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),
1293
0
              "  MAT cannot read scanrow %u from a file.", (unsigned)(MATLAB_HDR.SizeY-i-1));
1294
475
           if ((image != image2) && (image2 != (Image *) NULL))
1295
2
              image2=DestroyImage(image2);
1296
475
            if (clone_info != (ImageInfo *) NULL)
1297
475
              clone_info=DestroyImageInfo(clone_info);
1298
475
            if (quantum_info != (QuantumInfo *) NULL)
1299
475
              quantum_info=DestroyQuantumInfo(quantum_info);
1300
475
            BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
1301
475
            ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
1302
0
          }
1303
34.7k
        if((CellType==miINT8 || CellType==miUINT8) && (MATLAB_HDR.StructureFlag & FLAG_LOGICAL))
1304
8.79k
        {
1305
8.79k
          FixLogical((unsigned char *)BImgBuff,ldblk);
1306
8.79k
          if(ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,z2qtype[z],BImgBuff,exception) <= 0)
1307
0
            {
1308
0
ImportQuantumPixelsFailed:
1309
0
              if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),
1310
0
                "  MAT failed to ImportQuantumPixels for a row %u", (unsigned)(MATLAB_HDR.SizeY-i-1));
1311
0
              break;
1312
0
            }
1313
8.79k
        }
1314
25.9k
        else
1315
25.9k
        {
1316
25.9k
          if(ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,z2qtype[z],BImgBuff,exception) <= 0)
1317
0
            goto ImportQuantumPixelsFailed;
1318
1319
1320
25.9k
          if (z<=1 &&       /* fix only during a last pass z==0 || z==1 */
1321
21.8k
             (CellType==miINT8 || CellType==miINT16 || CellType==miINT32 || CellType==miINT64))
1322
15.9k
            FixSignedValues(image,q,MATLAB_HDR.SizeX);
1323
25.9k
        }
1324
1325
34.7k
        if (!SyncAuthenticPixels(image,exception))
1326
0
          {
1327
0
            if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),
1328
0
              "  MAT failed to sync image pixels for a row %u", (unsigned)(MATLAB_HDR.SizeY-i-1));
1329
0
            goto ExitLoop;
1330
0
          }
1331
34.7k
      }
1332
6.05k
    } while(z-- >= 2);
1333
4.60k
ExitLoop:
1334
4.60k
    if (i != (long) MATLAB_HDR.SizeY)
1335
0
      goto END_OF_READING;
1336
1337
    /* Read complex part of numbers here */
1338
4.60k
    if (MATLAB_HDR.StructureFlag & FLAG_COMPLEX)
1339
1.02k
    {        /* Find Min and Max Values for complex parts of floats */
1340
1.02k
      CellType = ReadBlobXXXLong(image2);    /* Additional object type */
1341
1.02k
      i = ReadBlobXXXLong(image2);           /* size of a complex part - toss away*/
1342
1343
1.02k
      if (CellType==miDOUBLE || CellType==miSINGLE)
1344
313
      {
1345
313
        CalcMinMax(image2,(int) image_info->endian,MATLAB_HDR.SizeX,
1346
313
          MATLAB_HDR.SizeY,CellType,(unsigned int) ldblk,BImgBuff,&MinVal,&MaxVal);
1347
313
      }
1348
1349
1.02k
      if (CellType==miDOUBLE)
1350
2.47k
        for (i = 0; i < (ssize_t) MATLAB_HDR.SizeY; i++)
1351
2.31k
        {
1352
2.31k
          ReadBlobDoublesXXX(image2, (size_t) ldblk, (double *)BImgBuff);
1353
2.31k
          if (EOFBlob(image) != MagickFalse)
1354
32
            break;
1355
2.28k
          InsertComplexDoubleRow(image,(double *)BImgBuff,(int) i,MinVal,MaxVal,
1356
2.28k
            exception);
1357
2.28k
        }
1358
1359
1.02k
      if (CellType==miSINGLE)
1360
2.18k
        for (i = 0; i < (ssize_t) MATLAB_HDR.SizeY; i++)
1361
2.09k
        {
1362
2.09k
          ReadBlobFloatsXXX(image2, (size_t) ldblk, (float *)BImgBuff);
1363
2.09k
          if (EOFBlob(image) != MagickFalse)
1364
38
            break;
1365
2.06k
          InsertComplexFloatRow(image,(float *)BImgBuff,(int) i,MinVal,MaxVal,
1366
2.06k
            exception);
1367
2.06k
        }
1368
1.02k
    }
1369
1370
      /* Image is gray when no complex flag is set and 2D Matrix AGAIN!!! */
1371
4.60k
    if ((MATLAB_HDR.DimFlag == 8) &&
1372
907
        ((MATLAB_HDR.StructureFlag & FLAG_COMPLEX) == 0))
1373
378
      image->type=GrayscaleType;
1374
4.60k
    if (image->depth == 1)
1375
640
      image->type=BilevelType;
1376
1377
4.60k
    if(image2==image)
1378
4.60k
        image2 = NULL;    /* Remove shadow copy to an image before rotation. */
1379
1380
      /*  Rotate image. */
1381
4.60k
    rotated_image = RotateImage(image, 90.0, exception);
1382
4.60k
    if (rotated_image != (Image *) NULL)
1383
4.60k
    {
1384
        /* Remove page offsets added by RotateImage */
1385
4.60k
      rotated_image->page.x=0;
1386
4.60k
      rotated_image->page.y=0;
1387
4.60k
      rotated_image->colors = image->colors;
1388
4.60k
      DestroyBlob(rotated_image);
1389
4.60k
      rotated_image->blob=ReferenceBlob(image->blob);
1390
4.60k
      AppendImageToList(&image,rotated_image);
1391
4.60k
      DeleteImageFromList(&image);
1392
4.60k
    }
1393
1394
4.60k
done_reading:
1395
1396
4.60k
    if(image2!=NULL)
1397
3
      if(image2!=image)
1398
3
      {
1399
3
        DeleteImageFromList(&image2);
1400
3
        if(clone_info)
1401
3
        {
1402
3
          if(clone_info->file)
1403
3
          {
1404
3
            fclose(clone_info->file);
1405
3
            clone_info->file = NULL;
1406
3
            (void) remove_utf8(clone_info->filename);
1407
3
          }
1408
3
        }
1409
3
      }
1410
4.60k
    if (EOFBlob(image) != MagickFalse)
1411
266
      break;
1412
1413
      /* Allocate next image structure. */
1414
4.34k
    if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
1415
0
      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1416
0
        break;
1417
4.34k
    AcquireNextImage(image_info,image,exception);
1418
4.34k
    if (image->next == (Image *) NULL) break;
1419
4.34k
    image=SyncNextImageInList(image);
1420
4.34k
    image->columns=image->rows=0;
1421
4.34k
    image->colors=0;
1422
1423
      /* row scan buffer is no longer needed */
1424
4.34k
    RelinquishMagickMemory(BImgBuff);
1425
4.34k
    BImgBuff = NULL;
1426
4.34k
    if (quantum_info != (QuantumInfo *) NULL)
1427
4.34k
      quantum_info=DestroyQuantumInfo(quantum_info);
1428
1429
4.34k
    if(--Frames>0)
1430
3.40k
    {
1431
3.40k
      z = z2;
1432
3.40k
      if(image2==NULL) image2 = image;
1433
3.40k
      if(!EOFBlob(image) && TellBlob(image)<filepos)
1434
3.08k
        goto NEXT_FRAME;
1435
3.40k
    }
1436
1.26k
    if ((image2!=NULL) && (image2!=image))   /* Does shadow temporary decompressed image exist? */
1437
0
      {
1438
/*  CloseBlob(image2); */
1439
0
        DeleteImageFromList(&image2);
1440
0
        if(clone_info)
1441
0
        {
1442
0
          if(clone_info->file)
1443
0
          {
1444
0
            fclose(clone_info->file);
1445
0
            clone_info->file = NULL;
1446
0
            (void) remove_utf8(clone_info->filename);
1447
0
          }
1448
0
        }
1449
0
      }
1450
1451
1.26k
    if (clone_info)
1452
1.26k
      clone_info=DestroyImageInfo(clone_info);
1453
1.26k
  }
1454
1455
2.20k
END_OF_READING:
1456
2.20k
  RelinquishMagickMemory(BImgBuff);
1457
2.20k
  if (quantum_info != (QuantumInfo *) NULL)
1458
266
    quantum_info=DestroyQuantumInfo(quantum_info);
1459
2.20k
  CloseBlob(image);
1460
1461
1462
2.20k
  {
1463
2.20k
    Image *p;
1464
2.20k
    ssize_t scene=0;
1465
1466
    /*
1467
      Rewind list, removing any empty images while rewinding.
1468
    */
1469
2.20k
    p=image;
1470
2.20k
    image=NULL;
1471
6.73k
    while (p != (Image *) NULL)
1472
4.53k
      {
1473
4.53k
        Image *tmp=p;
1474
4.53k
        if ((p->rows == 0) || (p->columns == 0)) {
1475
1.17k
          p=p->previous;
1476
1.17k
          if (tmp == image2)
1477
135
            image2=(Image *) NULL;
1478
1.17k
          DeleteImageFromList(&tmp);
1479
3.35k
        } else {
1480
3.35k
          image=p;
1481
3.35k
          p=p->previous;
1482
3.35k
        }
1483
4.53k
      }
1484
1485
    /*
1486
      Fix scene numbers
1487
    */
1488
6.09k
    for (p=image; p != (Image *) NULL; p=p->next)
1489
3.89k
      p->scene=(size_t) scene++;
1490
2.20k
  }
1491
1492
2.20k
  if(clone_info != NULL)  /* cleanup garbage file from compression */
1493
545
  {
1494
545
    if(clone_info->file)
1495
0
    {
1496
0
      fclose(clone_info->file);
1497
0
      clone_info->file = NULL;
1498
0
      (void) remove_utf8(clone_info->filename);
1499
0
    }
1500
545
    DestroyImageInfo(clone_info);
1501
545
    clone_info = NULL;
1502
545
  }
1503
2.20k
  if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),"return");
1504
2.20k
  if ((image != image2) && (image2 != (Image *) NULL))
1505
0
    image2=DestroyImage(image2);
1506
2.20k
  if (image == (Image *) NULL)
1507
953
    ThrowReaderException(CorruptImageError,"ImproperImageHeader")
1508
1.24k
  return(image);
1509
2.20k
}
1510

1511
/*
1512
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1513
%                                                                             %
1514
%                                                                             %
1515
%                                                                             %
1516
%   R e g i s t e r M A T I m a g e                                           %
1517
%                                                                             %
1518
%                                                                             %
1519
%                                                                             %
1520
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1521
%
1522
%  Method RegisterMATImage adds attributes for the MAT image format to
1523
%  the list of supported formats.  The attributes include the image format
1524
%  tag, a method to read and/or write the format, whether the format
1525
%  supports the saving of more than one frame to the same file or blob,
1526
%  whether the format supports native in-memory I/O, and a brief
1527
%  description of the format.
1528
%
1529
%  The format of the RegisterMATImage method is:
1530
%
1531
%      size_t RegisterMATImage(void)
1532
%
1533
*/
1534
ModuleExport size_t RegisterMATImage(void)
1535
9
{
1536
9
  MagickInfo
1537
9
    *entry;
1538
1539
9
  entry=AcquireMagickInfo("MAT","MAT","MATLAB level 5 image format");
1540
9
  entry->decoder=(DecodeImageHandler *) ReadMATImage;
1541
9
  entry->encoder=(EncodeImageHandler *) WriteMATImage;
1542
9
  entry->flags^=CoderBlobSupportFlag;
1543
9
  entry->flags|=CoderDecoderSeekableStreamFlag;
1544
9
  (void) RegisterMagickInfo(entry);
1545
9
  return(MagickImageCoderSignature);
1546
9
}
1547

1548
/*
1549
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1550
%                                                                             %
1551
%                                                                             %
1552
%                                                                             %
1553
%   U n r e g i s t e r M A T I m a g e                                       %
1554
%                                                                             %
1555
%                                                                             %
1556
%                                                                             %
1557
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1558
%
1559
%  Method UnregisterMATImage removes format registrations made by the
1560
%  MAT module from the list of supported formats.
1561
%
1562
%  The format of the UnregisterMATImage method is:
1563
%
1564
%      UnregisterMATImage(void)
1565
%
1566
*/
1567
ModuleExport void UnregisterMATImage(void)
1568
0
{
1569
0
  (void) UnregisterMagickInfo("MAT");
1570
0
}
1571

1572
/*
1573
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1574
%                                                                             %
1575
%                                                                             %
1576
%                                                                             %
1577
%   W r i t e M A T L A B I m a g e                                           %
1578
%                                                                             %
1579
%                                                                             %
1580
%                                                                             %
1581
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1582
%
1583
%  Function WriteMATImage writes an Matlab matrix to a file.
1584
%
1585
%  The format of the WriteMATImage method is:
1586
%
1587
%      MagickBooleanType WriteMATImage(const ImageInfo *image_info,
1588
%        Image *image,ExceptionInfo *exception)
1589
%
1590
%  A description of each parameter follows.
1591
%
1592
%    o image_info: Specifies a pointer to a ImageInfo structure.
1593
%
1594
%    o image:  A pointer to an Image structure.
1595
%
1596
%    o exception: return any errors or warnings in this structure.
1597
%
1598
*/
1599
static MagickBooleanType WriteMATImage(const ImageInfo *image_info,Image *image,
1600
  ExceptionInfo *exception)
1601
722
{
1602
722
  char
1603
722
    MATLAB_HDR[0x80];
1604
1605
722
  MagickBooleanType
1606
722
    status;
1607
1608
722
  MagickOffsetType
1609
722
    scene;
1610
1611
722
  size_t
1612
722
    number_scenes;
1613
1614
722
  struct tm
1615
722
    utc_time;
1616
1617
722
  time_t
1618
722
    current_time;
1619
1620
  /*
1621
    Open output image file.
1622
  */
1623
722
  assert(image_info != (const ImageInfo *) NULL);
1624
722
  assert(image_info->signature == MagickCoreSignature);
1625
722
  assert(image != (Image *) NULL);
1626
722
  assert(image->signature == MagickCoreSignature);
1627
722
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),"enter MAT");
1628
722
  assert(exception != (ExceptionInfo *) NULL);
1629
722
  assert(exception->signature == MagickCoreSignature);
1630
722
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1631
722
  if (status == MagickFalse)
1632
0
    return(MagickFalse);
1633
722
  image->depth=8;
1634
1635
722
  current_time=GetMagickTime();
1636
722
  GetMagickUTCTime(&current_time,&utc_time);
1637
722
  (void) memset(MATLAB_HDR,' ',MagickMin(sizeof(MATLAB_HDR),124));
1638
722
  FormatLocaleString(MATLAB_HDR,sizeof(MATLAB_HDR),
1639
722
    "MATLAB 5.0 MAT-file, Platform: %s, Created on: %s %s %2d %2d:%2d:%2d %d",
1640
722
    OsDesc,DayOfWTab[utc_time.tm_wday],MonthsTab[utc_time.tm_mon],
1641
722
    utc_time.tm_mday,utc_time.tm_hour,utc_time.tm_min,
1642
722
    utc_time.tm_sec,utc_time.tm_year+1900);
1643
722
  MATLAB_HDR[0x7C]=0;
1644
722
  MATLAB_HDR[0x7D]=1;
1645
722
  MATLAB_HDR[0x7E]='I';
1646
722
  MATLAB_HDR[0x7F]='M';
1647
722
  (void) WriteBlob(image,sizeof(MATLAB_HDR),(unsigned char *) MATLAB_HDR);
1648
722
  scene=0;
1649
722
  number_scenes=GetImageListLength(image);
1650
722
  do
1651
722
  {
1652
722
    char
1653
722
      padding;
1654
1655
722
    MagickBooleanType
1656
722
      is_gray;
1657
1658
722
    QuantumInfo
1659
722
      *quantum_info;
1660
1661
722
    size_t
1662
722
      data_size;
1663
1664
722
    unsigned char
1665
722
      *pixels;
1666
1667
722
    unsigned int
1668
722
      z;
1669
1670
722
    if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
1671
0
      (void) TransformImageColorspace(image,sRGBColorspace,exception);
1672
722
    is_gray=IdentifyImageCoderGray(image,exception);
1673
722
    z=(is_gray != MagickFalse) ? 0 : 3;
1674
1675
    /*
1676
      Store MAT header.
1677
    */
1678
722
    data_size = image->rows * image->columns;
1679
722
    if (is_gray == MagickFalse)
1680
441
      data_size*=3;
1681
722
    padding=((unsigned char)(data_size-1) & 0x7) ^ 0x7;
1682
1683
722
    (void) WriteBlobLSBLong(image,miMATRIX);
1684
722
    (void) WriteBlobLSBLong(image,(unsigned int) ((ssize_t) data_size+padding+
1685
722
      ((is_gray != MagickFalse) ? 48 : 56)));
1686
722
    (void) WriteBlobLSBLong(image,0x6); /* 0x88 */
1687
722
    (void) WriteBlobLSBLong(image,0x8); /* 0x8C */
1688
722
    (void) WriteBlobLSBLong(image,0x6); /* 0x90 */
1689
722
    (void) WriteBlobLSBLong(image,0);
1690
722
    (void) WriteBlobLSBLong(image,0x5); /* 0x98 */
1691
722
    (void) WriteBlobLSBLong(image,(is_gray != MagickFalse) ? 0x8 : 0xC); /* 0x9C - DimFlag */
1692
722
    (void) WriteBlobLSBLong(image,(unsigned int) image->rows);    /* x: 0xA0 */
1693
722
    (void) WriteBlobLSBLong(image,(unsigned int) image->columns); /* y: 0xA4 */
1694
722
    if (is_gray == MagickFalse)
1695
441
      {
1696
441
        (void) WriteBlobLSBLong(image,3); /* z: 0xA8 */
1697
441
        (void) WriteBlobLSBLong(image,0);
1698
441
      }
1699
722
    (void) WriteBlobLSBShort(image,1);  /* 0xB0 */
1700
722
    (void) WriteBlobLSBShort(image,1);  /* 0xB2 */
1701
722
    (void) WriteBlobLSBLong(image,'M'); /* 0xB4 */
1702
722
    (void) WriteBlobLSBLong(image,0x2); /* 0xB8 */
1703
722
    (void) WriteBlobLSBLong(image,(unsigned int) data_size); /* 0xBC */
1704
1705
    /*
1706
      Store image data.
1707
    */
1708
722
    quantum_info=AcquireQuantumInfo(image_info,image);
1709
722
    if (quantum_info == (QuantumInfo *) NULL)
1710
722
      ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1711
722
    pixels=(unsigned char *) GetQuantumPixels(quantum_info);
1712
722
    do
1713
1.60k
    {
1714
1.60k
      const Quantum
1715
1.60k
        *p;
1716
1717
1.60k
      ssize_t
1718
1.60k
        y;
1719
1720
35.9k
      for (y=0; y < (ssize_t) image->columns; y++)
1721
34.2k
      {
1722
34.2k
        size_t
1723
34.2k
          length;
1724
1725
34.2k
        p=GetVirtualPixels(image,y,0,1,image->rows,exception);
1726
34.2k
        if (p == (const Quantum *) NULL)
1727
0
          break;
1728
34.2k
        length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1729
34.2k
          z2qtype[z],pixels,exception);
1730
34.2k
        if (length != image->columns)
1731
0
          break;
1732
34.2k
        if (WriteBlob(image,image->rows,pixels) != (ssize_t) image->rows)
1733
0
          break;
1734
34.2k
      }
1735
1.60k
      if (y < (ssize_t) image->columns)
1736
0
        break;
1737
1.60k
      if (SyncAuthenticPixels(image,exception) == MagickFalse)
1738
0
        break;
1739
1.60k
    } while (z-- >= 2);
1740
3.64k
    while (padding-- > 0)
1741
2.92k
      (void) WriteBlobByte(image,0);
1742
722
    quantum_info=DestroyQuantumInfo(quantum_info);
1743
722
    if (GetNextImageInList(image) == (Image *) NULL)
1744
722
      break;
1745
0
    image=SyncNextImageInList(image);
1746
0
    status=SetImageProgress(image,SaveImagesTag,scene++,number_scenes);
1747
0
    if (status == MagickFalse)
1748
0
      break;
1749
0
  } while (image_info->adjoin != MagickFalse);
1750
722
  if (CloseBlob(image) == MagickFalse)
1751
0
    status=MagickFalse;
1752
722
  return(status);
1753
722
}