Coverage Report

Created: 2025-06-16 07:00

/src/imagemagick/coders/viff.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3
%                                                                             %
4
%                                                                             %
5
%                                                                             %
6
%                        V   V  IIIII  FFFFF  FFFFF                           %
7
%                        V   V    I    F      F                               %
8
%                        V   V    I    FFF    FFF                             %
9
%                         V V     I    F      F                               %
10
%                          V    IIIII  F      F                               %
11
%                                                                             %
12
%                                                                             %
13
%                Read/Write Khoros Visualization Image Format                 %
14
%                                                                             %
15
%                              Software Design                                %
16
%                                   Cristy                                    %
17
%                                 July 1992                                   %
18
%                                                                             %
19
%                                                                             %
20
%  Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization         %
21
%  dedicated to making software imaging solutions freely available.           %
22
%                                                                             %
23
%  You may not use this file except in compliance with the License.  You may  %
24
%  obtain a copy of the License at                                            %
25
%                                                                             %
26
%    https://imagemagick.org/script/license.php                               %
27
%                                                                             %
28
%  Unless required by applicable law or agreed to in writing, software        %
29
%  distributed under the License is distributed on an "AS IS" BASIS,          %
30
%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31
%  See the License for the specific language governing permissions and        %
32
%  limitations under the License.                                             %
33
%                                                                             %
34
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35
%
36
%
37
*/
38

39
/*
40
  Include declarations.
41
*/
42
#include "MagickCore/studio.h"
43
#include "MagickCore/attribute.h"
44
#include "MagickCore/blob.h"
45
#include "MagickCore/blob-private.h"
46
#include "MagickCore/cache.h"
47
#include "MagickCore/color.h"
48
#include "MagickCore/color-private.h"
49
#include "MagickCore/colormap.h"
50
#include "MagickCore/colormap-private.h"
51
#include "MagickCore/colorspace.h"
52
#include "MagickCore/colorspace-private.h"
53
#include "MagickCore/exception.h"
54
#include "MagickCore/exception-private.h"
55
#include "MagickCore/image.h"
56
#include "MagickCore/image-private.h"
57
#include "MagickCore/list.h"
58
#include "MagickCore/magick.h"
59
#include "MagickCore/memory_.h"
60
#include "MagickCore/module.h"
61
#include "MagickCore/monitor.h"
62
#include "MagickCore/monitor-private.h"
63
#include "MagickCore/pixel-accessor.h"
64
#include "MagickCore/property.h"
65
#include "MagickCore/quantum-private.h"
66
#include "MagickCore/static.h"
67
#include "MagickCore/string_.h"
68
#include "coders/coders-private.h"
69

70
/*
71
  Forward declarations.
72
*/
73
static MagickBooleanType
74
  WriteVIFFImage(const ImageInfo *,Image *,ExceptionInfo *);
75

76
/*
77
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
78
%                                                                             %
79
%                                                                             %
80
%                                                                             %
81
%   I s V I F F                                                               %
82
%                                                                             %
83
%                                                                             %
84
%                                                                             %
85
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
86
%
87
%  IsVIFF() returns MagickTrue if the image format type, identified by the
88
%  magick string, is VIFF.
89
%
90
%  The format of the IsVIFF method is:
91
%
92
%      MagickBooleanType IsVIFF(const unsigned char *magick,const size_t length)
93
%
94
%  A description of each parameter follows:
95
%
96
%    o magick: compare image format pattern against these bytes.
97
%
98
%    o length: Specifies the length of the magick string.
99
%
100
*/
101
static MagickBooleanType IsVIFF(const unsigned char *magick,const size_t length)
102
0
{
103
0
  if (length < 2)
104
0
    return(MagickFalse);
105
0
  if (memcmp(magick,"\253\001",2) == 0)
106
0
    return(MagickTrue);
107
0
  return(MagickFalse);
108
0
}
109

110
/*
111
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
112
%                                                                             %
113
%                                                                             %
114
%                                                                             %
115
%   R e a d V I F F I m a g e                                                 %
116
%                                                                             %
117
%                                                                             %
118
%                                                                             %
119
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
120
%
121
%  ReadVIFFImage() reads a Khoros Visualization image file and returns
122
%  it.  It allocates the memory necessary for the new Image structure and
123
%  returns a pointer to the new image.
124
%
125
%  The format of the ReadVIFFImage method is:
126
%
127
%      Image *ReadVIFFImage(const ImageInfo *image_info,
128
%        ExceptionInfo *exception)
129
%
130
%  A description of each parameter follows:
131
%
132
%    o image: Method ReadVIFFImage returns a pointer to the image after
133
%      reading.  A null image is returned if there is a memory shortage or if
134
%      the image cannot be read.
135
%
136
%    o image_info: the image info.
137
%
138
%    o exception: return any errors or warnings in this structure.
139
%
140
*/
141
static Image *ReadVIFFImage(const ImageInfo *image_info,
142
  ExceptionInfo *exception)
143
1.78k
{
144
1.78k
#define VFF_CM_genericRGB  15
145
1.78k
#define VFF_CM_ntscRGB  1
146
1.78k
#define VFF_CM_NONE  0
147
3.60k
#define VFF_DEP_DECORDER  0x4
148
3.34k
#define VFF_DEP_NSORDER  0x8
149
1.78k
#define VFF_DES_RAW  0
150
1.78k
#define VFF_LOC_IMPLICIT  1
151
1.78k
#define VFF_MAPTYP_NONE  0
152
1.78k
#define VFF_MAPTYP_1_BYTE  1
153
461M
#define VFF_MAPTYP_2_BYTE  2
154
174M
#define VFF_MAPTYP_4_BYTE  4
155
186M
#define VFF_MAPTYP_FLOAT  5
156
13.9M
#define VFF_MAPTYP_DOUBLE  7
157
149k
#define VFF_MS_NONE  0
158
1.78k
#define VFF_MS_ONEPERBAND  1
159
1.78k
#define VFF_MS_SHARED  3
160
5.63k
#define VFF_TYP_BIT  0
161
2.10k
#define VFF_TYP_1_BYTE  1
162
1.78k
#define VFF_TYP_2_BYTE  2
163
1.78k
#define VFF_TYP_4_BYTE  4
164
2.24k
#define VFF_TYP_FLOAT  5
165
1.78k
#define VFF_TYP_DOUBLE  9
166
167
1.78k
  typedef struct _ViffInfo
168
1.78k
  {
169
1.78k
    unsigned char
170
1.78k
      identifier,
171
1.78k
      file_type,
172
1.78k
      release,
173
1.78k
      version,
174
1.78k
      machine_dependency,
175
1.78k
      reserve[3];
176
177
1.78k
    char
178
1.78k
      comment[512];
179
180
1.78k
    unsigned int
181
1.78k
      rows,
182
1.78k
      columns,
183
1.78k
      subrows;
184
185
1.78k
    int
186
1.78k
      x_offset,
187
1.78k
      y_offset;
188
189
1.78k
    float
190
1.78k
      x_bits_per_pixel,
191
1.78k
      y_bits_per_pixel;
192
193
1.78k
    unsigned int
194
1.78k
      location_type,
195
1.78k
      location_dimension,
196
1.78k
      number_of_images,
197
1.78k
      number_data_bands,
198
1.78k
      data_storage_type,
199
1.78k
      data_encode_scheme,
200
1.78k
      map_scheme,
201
1.78k
      map_storage_type,
202
1.78k
      map_rows,
203
1.78k
      map_columns,
204
1.78k
      map_subrows,
205
1.78k
      map_enable,
206
1.78k
      maps_per_cycle,
207
1.78k
      color_space_model;
208
1.78k
  } ViffInfo;
209
210
1.78k
  double
211
1.78k
    min_value,
212
1.78k
    scale_factor,
213
1.78k
    value;
214
215
1.78k
  Image
216
1.78k
    *image;
217
218
1.78k
  int
219
1.78k
    bit;
220
221
1.78k
  MagickBooleanType
222
1.78k
    status;
223
224
1.78k
  MagickSizeType
225
1.78k
    number_pixels;
226
227
1.78k
  Quantum
228
1.78k
    *q;
229
230
1.78k
  size_t
231
1.78k
    bytes_per_pixel,
232
1.78k
    max_packets,
233
1.78k
    quantum;
234
235
1.78k
  ssize_t
236
1.78k
    count,
237
1.78k
    i,
238
1.78k
    x,
239
1.78k
    y;
240
241
1.78k
  unsigned char
242
1.78k
    *p,
243
1.78k
    *pixels;
244
245
1.78k
  unsigned long
246
1.78k
    lsb_first;
247
248
1.78k
  ViffInfo
249
1.78k
    viff_info;
250
251
  /*
252
    Open image file.
253
  */
254
1.78k
  assert(image_info != (const ImageInfo *) NULL);
255
1.78k
  assert(image_info->signature == MagickCoreSignature);
256
1.78k
  assert(exception != (ExceptionInfo *) NULL);
257
1.78k
  assert(exception->signature == MagickCoreSignature);
258
1.78k
  if (IsEventLogging() != MagickFalse)
259
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
260
0
      image_info->filename);
261
1.78k
  image=AcquireImage(image_info,exception);
262
1.78k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
263
1.78k
  if (status == MagickFalse)
264
74
    {
265
74
      image=DestroyImageList(image);
266
74
      return((Image *) NULL);
267
74
    }
268
  /*
269
    Read VIFF header (1024 bytes).
270
  */
271
1.71k
  count=ReadBlob(image,1,&viff_info.identifier);
272
1.71k
  do
273
2.20k
  {
274
    /*
275
      Verify VIFF identifier.
276
    */
277
2.20k
    if ((count != 1) || ((unsigned char) viff_info.identifier != 0xab))
278
2.06k
      ThrowReaderException(CorruptImageError,"NotAVIFFImage");
279
    /*
280
      Initialize VIFF image.
281
    */
282
2.06k
    (void) ReadBlob(image,sizeof(viff_info.file_type),&viff_info.file_type);
283
2.06k
    (void) ReadBlob(image,sizeof(viff_info.release),&viff_info.release);
284
2.06k
    (void) ReadBlob(image,sizeof(viff_info.version),&viff_info.version);
285
2.06k
    (void) ReadBlob(image,sizeof(viff_info.machine_dependency),
286
2.06k
      &viff_info.machine_dependency);
287
2.06k
    (void) ReadBlob(image,sizeof(viff_info.reserve),viff_info.reserve);
288
2.06k
    count=ReadBlob(image,512,(unsigned char *) viff_info.comment);
289
2.06k
    if (count != 512)
290
2.00k
      ThrowReaderException(CorruptImageError,"ImproperImageHeader");
291
2.00k
    viff_info.comment[511]='\0';
292
2.00k
    if (strlen(viff_info.comment) > 4)
293
1.02k
      (void) SetImageProperty(image,"comment",viff_info.comment,exception);
294
2.00k
    if ((viff_info.machine_dependency == VFF_DEP_DECORDER) ||
295
2.00k
        (viff_info.machine_dependency == VFF_DEP_NSORDER))
296
394
      image->endian=LSBEndian;
297
1.60k
    else
298
1.60k
      image->endian=MSBEndian;
299
2.00k
    viff_info.rows=ReadBlobLong(image);
300
2.00k
    viff_info.columns=ReadBlobLong(image);
301
2.00k
    viff_info.subrows=ReadBlobLong(image);
302
2.00k
    viff_info.x_offset=ReadBlobSignedLong(image);
303
2.00k
    viff_info.y_offset=ReadBlobSignedLong(image);
304
2.00k
    viff_info.x_bits_per_pixel=(float) ReadBlobLong(image);
305
2.00k
    viff_info.y_bits_per_pixel=(float) ReadBlobLong(image);
306
2.00k
    viff_info.location_type=ReadBlobLong(image);
307
2.00k
    viff_info.location_dimension=ReadBlobLong(image);
308
2.00k
    viff_info.number_of_images=ReadBlobLong(image);
309
2.00k
    viff_info.number_data_bands=ReadBlobLong(image);
310
2.00k
    viff_info.data_storage_type=ReadBlobLong(image);
311
2.00k
    viff_info.data_encode_scheme=ReadBlobLong(image);
312
2.00k
    viff_info.map_scheme=ReadBlobLong(image);
313
2.00k
    viff_info.map_storage_type=ReadBlobLong(image);
314
2.00k
    viff_info.map_rows=ReadBlobLong(image);
315
2.00k
    viff_info.map_columns=ReadBlobLong(image);
316
2.00k
    viff_info.map_subrows=ReadBlobLong(image);
317
2.00k
    viff_info.map_enable=ReadBlobLong(image);
318
2.00k
    viff_info.maps_per_cycle=ReadBlobLong(image);
319
2.00k
    viff_info.color_space_model=ReadBlobLong(image);
320
842k
    for (i=0; i < 420; i++)
321
840k
      (void) ReadBlobByte(image);
322
2.00k
    if (EOFBlob(image) != MagickFalse)
323
1.89k
      ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
324
1.89k
    number_pixels=(MagickSizeType) viff_info.columns*viff_info.rows;
325
1.89k
    if (number_pixels > 8*GetBlobSize(image))
326
1.80k
      ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
327
1.80k
    if (number_pixels != (size_t) number_pixels)
328
1.80k
      ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
329
1.80k
    if (number_pixels == 0)
330
1.79k
      ThrowReaderException(CoderError,"ImageColumnOrRowSizeIsNotSupported");
331
1.79k
    image->columns=viff_info.rows;
332
1.79k
    image->rows=viff_info.columns;
333
1.79k
    image->depth=viff_info.x_bits_per_pixel <= 8 ? 8UL :
334
1.79k
      MAGICKCORE_QUANTUM_DEPTH;
335
1.79k
    image->alpha_trait=viff_info.number_data_bands == 4 ? BlendPixelTrait :
336
1.79k
      UndefinedPixelTrait;
337
1.79k
    status=SetImageExtent(image,image->columns,image->rows,exception);
338
1.79k
    if (status == MagickFalse)
339
43
      return(DestroyImageList(image));
340
1.75k
    (void) SetImageBackgroundColor(image,exception);
341
    /*
342
      Verify that we can read this VIFF image.
343
    */
344
1.75k
    if ((viff_info.number_data_bands < 1) || (viff_info.number_data_bands > 4))
345
1.69k
      ThrowReaderException(CorruptImageError,"ImproperImageHeader");
346
1.69k
    if ((viff_info.data_storage_type != VFF_TYP_BIT) &&
347
1.69k
        (viff_info.data_storage_type != VFF_TYP_1_BYTE) &&
348
1.69k
        (viff_info.data_storage_type != VFF_TYP_2_BYTE) &&
349
1.69k
        (viff_info.data_storage_type != VFF_TYP_4_BYTE) &&
350
1.69k
        (viff_info.data_storage_type != VFF_TYP_FLOAT) &&
351
1.69k
        (viff_info.data_storage_type != VFF_TYP_DOUBLE))
352
1.64k
      ThrowReaderException(CoderError,"DataStorageTypeIsNotSupported");
353
1.64k
    if (viff_info.data_encode_scheme != VFF_DES_RAW)
354
1.60k
      ThrowReaderException(CoderError,"DataEncodingSchemeIsNotSupported");
355
1.60k
    if ((viff_info.map_storage_type != VFF_MAPTYP_NONE) &&
356
1.60k
        (viff_info.map_storage_type != VFF_MAPTYP_1_BYTE) &&
357
1.60k
        (viff_info.map_storage_type != VFF_MAPTYP_2_BYTE) &&
358
1.60k
        (viff_info.map_storage_type != VFF_MAPTYP_4_BYTE) &&
359
1.60k
        (viff_info.map_storage_type != VFF_MAPTYP_FLOAT) &&
360
1.60k
        (viff_info.map_storage_type != VFF_MAPTYP_DOUBLE))
361
1.54k
      ThrowReaderException(CoderError,"MapStorageTypeIsNotSupported");
362
1.54k
    if ((viff_info.color_space_model != VFF_CM_NONE) &&
363
1.54k
        (viff_info.color_space_model != VFF_CM_ntscRGB) &&
364
1.54k
        (viff_info.color_space_model != VFF_CM_genericRGB))
365
1.48k
      ThrowReaderException(CoderError,"ColorspaceModelIsNotSupported");
366
1.48k
    if (viff_info.location_type != VFF_LOC_IMPLICIT)
367
1.44k
      ThrowReaderException(CoderError,"LocationTypeIsNotSupported");
368
1.44k
    if (viff_info.number_of_images != 1)
369
1.40k
      ThrowReaderException(CoderError,"NumberOfImagesIsNotSupported");
370
1.40k
    if (viff_info.map_rows == 0)
371
369
      viff_info.map_scheme=VFF_MS_NONE;
372
1.40k
    switch ((int) viff_info.map_scheme)
373
1.40k
    {
374
684
      case VFF_MS_NONE:
375
684
      {
376
684
        if (viff_info.number_data_bands < 3)
377
436
          {
378
            /*
379
              Create linear color ramp.
380
            */
381
436
            if (viff_info.data_storage_type == VFF_TYP_BIT)
382
243
              image->colors=2;
383
193
            else
384
193
              if (viff_info.data_storage_type == VFF_MAPTYP_1_BYTE)
385
98
                image->colors=256UL;
386
95
              else
387
95
                image->colors=image->depth <= 8 ? 256UL : 65536UL;
388
436
            status=AcquireImageColormap(image,image->colors,exception);
389
436
            if (status == MagickFalse)
390
436
              ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
391
436
          }
392
684
        break;
393
684
      }
394
684
      case VFF_MS_ONEPERBAND:
395
713
      case VFF_MS_SHARED:
396
713
      {
397
713
        unsigned char
398
713
          *viff_colormap;
399
400
        /*
401
          Allocate VIFF colormap.
402
        */
403
713
        switch ((int) viff_info.map_storage_type)
404
713
        {
405
15
          case VFF_MAPTYP_1_BYTE: bytes_per_pixel=1; break;
406
67
          case VFF_MAPTYP_2_BYTE: bytes_per_pixel=2; break;
407
63
          case VFF_MAPTYP_4_BYTE: bytes_per_pixel=4; break;
408
57
          case VFF_MAPTYP_FLOAT: bytes_per_pixel=4; break;
409
54
          case VFF_MAPTYP_DOUBLE: bytes_per_pixel=8; break;
410
457
          default: bytes_per_pixel=1; break;
411
713
        }
412
713
        image->colors=viff_info.map_columns;
413
713
        count=(ssize_t) (bytes_per_pixel*image->colors*viff_info.map_rows);
414
713
        if ((MagickSizeType) count > GetBlobSize(image))
415
619
          ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
416
619
        if ((MagickSizeType) viff_info.map_rows >
417
619
            (viff_info.map_rows*bytes_per_pixel*sizeof(*viff_colormap)))
418
619
          ThrowReaderException(CorruptImageError,"ImproperImageHeader");
419
619
        if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
420
614
          ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
421
614
        viff_colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
422
614
          viff_info.map_rows*bytes_per_pixel*sizeof(*viff_colormap));
423
614
        if (viff_colormap == (unsigned char *) NULL)
424
568
          ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
425
        /*
426
          Read VIFF raster colormap.
427
        */
428
568
        if (ReadBlob(image,(size_t) count,viff_colormap) != count)
429
27
          {
430
27
            viff_colormap=(unsigned char *) RelinquishMagickMemory(
431
27
              viff_colormap);
432
27
            ThrowReaderException(CorruptImageError,
433
27
              "InsufficientImageDataInFile");
434
0
          }
435
541
        lsb_first=1;
436
541
        if (*(char *) &lsb_first &&
437
541
            ((viff_info.machine_dependency != VFF_DEP_DECORDER) &&
438
541
             (viff_info.machine_dependency != VFF_DEP_NSORDER)))
439
363
          switch ((int) viff_info.map_storage_type)
440
363
          {
441
52
            case VFF_MAPTYP_2_BYTE:
442
52
            {
443
52
              MSBOrderShort(viff_colormap,(bytes_per_pixel*image->colors*
444
52
                viff_info.map_rows));
445
52
              break;
446
0
            }
447
48
            case VFF_MAPTYP_4_BYTE:
448
98
            case VFF_MAPTYP_FLOAT:
449
98
            {
450
98
              MSBOrderLong(viff_colormap,(bytes_per_pixel*image->colors*
451
98
                viff_info.map_rows));
452
98
              break;
453
48
            }
454
213
            default: break;
455
363
          }
456
1.91G
        for (i=0; i < (ssize_t) (viff_info.map_rows*image->colors); i++)
457
1.91G
        {
458
1.91G
          switch ((int) viff_info.map_storage_type)
459
1.91G
          {
460
461M
            case VFF_MAPTYP_2_BYTE: value=1.0*((short *) viff_colormap)[i]; break;
461
174M
            case VFF_MAPTYP_4_BYTE: value=1.0*((int *) viff_colormap)[i]; break;
462
186M
            case VFF_MAPTYP_FLOAT: value=((float *) viff_colormap)[i]; break;
463
13.9M
            case VFF_MAPTYP_DOUBLE: value=((double *) viff_colormap)[i]; break;
464
1.07G
            default: value=1.0*viff_colormap[i]; break;
465
1.91G
          }
466
1.91G
          if (i < (ssize_t) image->colors)
467
33.7k
            {
468
33.7k
              image->colormap[i].red=(MagickRealType)
469
33.7k
                ScaleCharToQuantum((unsigned char) value);
470
33.7k
              image->colormap[i].green=(MagickRealType)
471
33.7k
                ScaleCharToQuantum((unsigned char) value);
472
33.7k
              image->colormap[i].blue=(MagickRealType)
473
33.7k
                ScaleCharToQuantum((unsigned char) value);
474
33.7k
            }
475
1.91G
          else
476
1.91G
            if (i < (ssize_t) (2*image->colors))
477
18.8k
              image->colormap[i % (ssize_t) image->colors].green=
478
18.8k
                (MagickRealType) ScaleCharToQuantum((unsigned char) value);
479
1.91G
            else
480
1.91G
              if (i < (ssize_t) (3*image->colors))
481
2.82k
                image->colormap[i % (ssize_t) image->colors].blue=
482
2.82k
                  (MagickRealType) ScaleCharToQuantum((unsigned char) value);
483
1.91G
        }
484
541
        viff_colormap=(unsigned char *) RelinquishMagickMemory(viff_colormap);
485
541
        break;
486
541
      }
487
6
      default:
488
6
        ThrowReaderException(CoderError,"ColormapTypeNotSupported");
489
1.40k
    }
490
1.22k
    if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
491
0
      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
492
0
        break;
493
1.22k
    if (viff_info.data_storage_type == VFF_TYP_BIT)
494
512
      {
495
        /*
496
          Create bi-level colormap.
497
        */
498
512
        image->colors=2;
499
512
        if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
500
512
          ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
501
512
        image->colorspace=GRAYColorspace;
502
512
      }
503
    /*
504
      Allocate VIFF pixels.
505
    */
506
1.22k
    switch ((int) viff_info.data_storage_type)
507
1.22k
    {
508
72
      case VFF_TYP_2_BYTE: bytes_per_pixel=2; break;
509
38
      case VFF_TYP_4_BYTE: bytes_per_pixel=4; break;
510
26
      case VFF_TYP_FLOAT: bytes_per_pixel=4; break;
511
29
      case VFF_TYP_DOUBLE: bytes_per_pixel=8; break;
512
1.06k
      default: bytes_per_pixel=1; break;
513
1.22k
    }
514
1.22k
    if (viff_info.data_storage_type == VFF_TYP_BIT)
515
512
      {
516
512
        if (HeapOverflowSanityCheckGetSize((image->columns+7UL) >> 3UL,image->rows,&max_packets) != MagickFalse)
517
512
          ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
518
512
      }
519
713
    else
520
713
      {
521
713
        if (HeapOverflowSanityCheckGetSize((size_t) number_pixels,viff_info.number_data_bands,&max_packets) != MagickFalse)
522
713
          ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
523
713
      }
524
1.22k
    count=(ssize_t) (bytes_per_pixel*max_packets);
525
1.22k
    if ((MagickSizeType) count > GetBlobSize(image))
526
1.20k
      ThrowReaderException(CorruptImageError,"ImproperImageHeader");
527
1.20k
    pixels=(unsigned char *) AcquireQuantumMemory((size_t) MagickMax(
528
1.20k
      number_pixels,max_packets),bytes_per_pixel*sizeof(*pixels));
529
1.20k
    if (pixels == (unsigned char *) NULL)
530
1.20k
      ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
531
1.20k
    (void) memset(pixels,0,(size_t) MagickMax(number_pixels,max_packets)*
532
1.20k
      bytes_per_pixel*sizeof(*pixels));
533
1.20k
    if (ReadBlob(image,(size_t) count,pixels) != count)
534
150
      {
535
150
        pixels=(unsigned char *) RelinquishMagickMemory(pixels);
536
150
        ThrowReaderException(CorruptImageError,"ImproperImageHeader");
537
0
      }
538
1.05k
    lsb_first=1;
539
1.05k
    if (*(char *) &lsb_first &&
540
1.05k
        ((viff_info.machine_dependency != VFF_DEP_DECORDER) &&
541
1.05k
         (viff_info.machine_dependency != VFF_DEP_NSORDER)))
542
819
      switch ((int) viff_info.data_storage_type)
543
819
      {
544
45
        case VFF_TYP_2_BYTE:
545
45
        {
546
45
          MSBOrderShort(pixels,bytes_per_pixel*max_packets);
547
45
          break;
548
0
        }
549
32
        case VFF_TYP_4_BYTE:
550
55
        case VFF_TYP_FLOAT:
551
55
        {
552
55
          MSBOrderLong(pixels,bytes_per_pixel*max_packets);
553
55
          break;
554
32
        }
555
719
        default: break;
556
819
      }
557
1.05k
    min_value=0.0;
558
1.05k
    scale_factor=1.0;
559
1.05k
    if ((viff_info.data_storage_type != VFF_TYP_1_BYTE) &&
560
1.05k
        (viff_info.map_scheme == VFF_MS_NONE))
561
456
      {
562
456
        double
563
456
          max_value;
564
565
        /*
566
          Determine scale factor.
567
        */
568
456
        switch ((int) viff_info.data_storage_type)
569
456
        {
570
29
          case VFF_TYP_2_BYTE: value=1.0*((short *) pixels)[0]; break;
571
24
          case VFF_TYP_4_BYTE: value=1.0*((int *) pixels)[0]; break;
572
24
          case VFF_TYP_FLOAT: value=((float *) pixels)[0]; break;
573
23
          case VFF_TYP_DOUBLE: value=((double *) pixels)[0]; break;
574
356
          default: value=1.0*pixels[0]; break;
575
456
        }
576
456
        max_value=value;
577
456
        min_value=value;
578
89.9k
        for (i=0; i < (ssize_t) max_packets; i++)
579
89.5k
        {
580
89.5k
          switch ((int) viff_info.data_storage_type)
581
89.5k
          {
582
473
            case VFF_TYP_2_BYTE: value=1.0*((short *) pixels)[i]; break;
583
460
            case VFF_TYP_4_BYTE: value=1.0*((int *) pixels)[i]; break;
584
995
            case VFF_TYP_FLOAT: value=((float *) pixels)[i]; break;
585
209
            case VFF_TYP_DOUBLE: value=((double *) pixels)[i]; break;
586
87.3k
            default: value=1.0*pixels[i]; break;
587
89.5k
          }
588
89.5k
          if (value > max_value)
589
526
            max_value=value;
590
88.9k
          else
591
88.9k
            if (value < min_value)
592
341
              min_value=value;
593
89.5k
        }
594
456
        if ((min_value == 0) && (max_value == 0))
595
79
          scale_factor=0;
596
377
        else
597
377
          if (min_value == max_value)
598
195
            {
599
195
              scale_factor=(double) QuantumRange/min_value;
600
195
              min_value=0;
601
195
            }
602
182
          else
603
182
            scale_factor=(double) QuantumRange/(max_value-min_value);
604
456
      }
605
    /*
606
      Convert pixels to Quantum size.
607
    */
608
1.05k
    p=(unsigned char *) pixels;
609
149k
    for (i=0; i < (ssize_t) max_packets; i++)
610
148k
    {
611
148k
      switch ((int) viff_info.data_storage_type)
612
148k
      {
613
489
        case VFF_TYP_2_BYTE: value=1.0*((short *) pixels)[i]; break;
614
468
        case VFF_TYP_4_BYTE: value=1.0*((int *) pixels)[i]; break;
615
995
        case VFF_TYP_FLOAT: value=((float *) pixels)[i]; break;
616
470
        case VFF_TYP_DOUBLE: value=((double *) pixels)[i]; break;
617
145k
        default: value=1.0*pixels[i]; break;
618
148k
      }
619
148k
      if (viff_info.map_scheme == VFF_MS_NONE)
620
128k
        value=(value-min_value)*scale_factor;
621
148k
      *p=(unsigned char) ClampToQuantum(value);
622
148k
      p++;
623
148k
    }
624
    /*
625
      Convert VIFF raster image to pixel packets.
626
    */
627
1.05k
    p=(unsigned char *) pixels;
628
1.05k
    if (viff_info.data_storage_type == VFF_TYP_BIT)
629
435
      {
630
        /*
631
          Convert bitmap scanline.
632
        */
633
17.1k
        for (y=0; y < (ssize_t) image->rows; y++)
634
16.7k
        {
635
16.7k
          q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
636
16.7k
          if (q == (Quantum *) NULL)
637
0
            break;
638
101k
          for (x=0; x < (ssize_t) (image->columns-7); x+=8)
639
84.3k
          {
640
758k
            for (bit=0; bit < 8; bit++)
641
674k
            {
642
674k
              quantum=(size_t) ((*p) & (0x01 << bit) ? 0 : 1);
643
674k
              SetPixelRed(image,quantum == 0 ? 0 : QuantumRange,q);
644
674k
              SetPixelGreen(image,quantum == 0 ? 0 : QuantumRange,q);
645
674k
              SetPixelBlue(image,quantum == 0 ? 0 : QuantumRange,q);
646
674k
              if (image->storage_class == PseudoClass)
647
674k
                SetPixelIndex(image,(Quantum) quantum,q);
648
674k
              q+=(ptrdiff_t) GetPixelChannels(image);
649
674k
            }
650
84.3k
            p++;
651
84.3k
          }
652
16.7k
          if ((image->columns % 8) != 0)
653
10.8k
            {
654
69.9k
              for (bit=0; bit < (int) (image->columns % 8); bit++)
655
59.0k
              {
656
59.0k
                quantum=(size_t) ((*p) & (0x01 << bit) ? 0 : 1);
657
59.0k
                SetPixelRed(image,quantum == 0 ? 0 : QuantumRange,q);
658
59.0k
                SetPixelGreen(image,quantum == 0 ? 0 : QuantumRange,q);
659
59.0k
                SetPixelBlue(image,quantum == 0 ? 0 : QuantumRange,q);
660
59.0k
                if (image->storage_class == PseudoClass)
661
59.0k
                  SetPixelIndex(image,(Quantum) quantum,q);
662
59.0k
                q+=(ptrdiff_t) GetPixelChannels(image);
663
59.0k
              }
664
10.8k
              p++;
665
10.8k
            }
666
16.7k
          if (SyncAuthenticPixels(image,exception) == MagickFalse)
667
0
            break;
668
16.7k
          if (image->previous == (Image *) NULL)
669
16.3k
            {
670
16.3k
              status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
671
16.3k
                image->rows);
672
16.3k
              if (status == MagickFalse)
673
0
                break;
674
16.3k
            }
675
16.7k
        }
676
435
      }
677
622
    else
678
622
      if (image->storage_class == PseudoClass)
679
10.1k
        for (y=0; y < (ssize_t) image->rows; y++)
680
9.67k
        {
681
9.67k
          q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
682
9.67k
          if (q == (Quantum *) NULL)
683
0
            break;
684
36.2k
          for (x=0; x < (ssize_t) image->columns; x++)
685
26.5k
          {
686
26.5k
            SetPixelIndex(image,*p++,q);
687
26.5k
            q+=(ptrdiff_t) GetPixelChannels(image);
688
26.5k
          }
689
9.67k
          if (SyncAuthenticPixels(image,exception) == MagickFalse)
690
0
            break;
691
9.67k
          if (image->previous == (Image *) NULL)
692
9.28k
            {
693
9.28k
              status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
694
9.28k
                image->rows);
695
9.28k
              if (status == MagickFalse)
696
0
                break;
697
9.28k
            }
698
9.67k
        }
699
99
      else
700
99
        {
701
          /*
702
            Convert DirectColor scanline.
703
          */
704
99
          number_pixels=(MagickSizeType) image->columns*image->rows;
705
1.91k
          for (y=0; y < (ssize_t) image->rows; y++)
706
1.81k
          {
707
1.81k
            q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
708
1.81k
            if (q == (Quantum *) NULL)
709
0
              break;
710
10.3k
            for (x=0; x < (ssize_t) image->columns; x++)
711
8.50k
            {
712
8.50k
              SetPixelRed(image,ScaleCharToQuantum(*p),q);
713
8.50k
              SetPixelGreen(image,ScaleCharToQuantum(*(p+number_pixels)),q);
714
8.50k
              SetPixelBlue(image,ScaleCharToQuantum(*(p+2*number_pixels)),q);
715
8.50k
              if (image->colors != 0)
716
0
                {
717
0
                  ssize_t
718
0
                    index;
719
720
0
                  index=(ssize_t) GetPixelRed(image,q);
721
0
                  SetPixelRed(image,ClampToQuantum(image->colormap[
722
0
                    ConstrainColormapIndex(image,index,exception)].red),q);
723
0
                  index=(ssize_t) GetPixelGreen(image,q);
724
0
                  SetPixelGreen(image,ClampToQuantum(image->colormap[
725
0
                    ConstrainColormapIndex(image,index,exception)].green),q);
726
0
                  index=(ssize_t) GetPixelBlue(image,q);
727
0
                  SetPixelBlue(image,ClampToQuantum(image->colormap[
728
0
                    ConstrainColormapIndex(image,index,exception)].blue),q);
729
0
                }
730
8.50k
              SetPixelAlpha(image,image->alpha_trait != UndefinedPixelTrait ?
731
7.46k
                ScaleCharToQuantum(*(p+number_pixels*3)) : OpaqueAlpha,q);
732
8.50k
              p++;
733
8.50k
              q+=(ptrdiff_t) GetPixelChannels(image);
734
8.50k
            }
735
1.81k
            if (SyncAuthenticPixels(image,exception) == MagickFalse)
736
0
              break;
737
1.81k
            if (image->previous == (Image *) NULL)
738
1.60k
              {
739
1.60k
                status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
740
1.60k
                image->rows);
741
1.60k
                if (status == MagickFalse)
742
0
                  break;
743
1.60k
              }
744
1.81k
          }
745
99
        }
746
1.05k
    pixels=(unsigned char *) RelinquishMagickMemory(pixels);
747
1.05k
    if (image->storage_class == PseudoClass)
748
958
      (void) SyncImage(image,exception);
749
1.05k
    if (EOFBlob(image) != MagickFalse)
750
1.05k
      ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
751
    /*
752
      Proceed to next image.
753
    */
754
1.05k
    if (image_info->number_scenes != 0)
755
0
      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
756
0
        break;
757
1.05k
    count=ReadBlob(image,1,&viff_info.identifier);
758
1.05k
    if ((count == 1) && (viff_info.identifier == 0xab))
759
489
      {
760
        /*
761
          Allocate next image structure.
762
        */
763
489
        AcquireNextImage(image_info,image,exception);
764
489
        if (GetNextImageInList(image) == (Image *) NULL)
765
0
          {
766
0
            status=MagickFalse;
767
0
            break;
768
0
          }
769
489
        image=SyncNextImageInList(image);
770
489
        status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
771
489
          GetBlobSize(image));
772
489
        if (status == MagickFalse)
773
0
          break;
774
489
      }
775
1.05k
  } while ((count != 0) && (viff_info.identifier == 0xab));
776
568
  if (CloseBlob(image) == MagickFalse)
777
0
    status=MagickFalse;
778
568
  if (status == MagickFalse)
779
0
    return(DestroyImageList(image));
780
568
  return(GetFirstImageInList(image));
781
568
}
782

783
/*
784
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
785
%                                                                             %
786
%                                                                             %
787
%                                                                             %
788
%   R e g i s t e r V I F F I m a g e                                         %
789
%                                                                             %
790
%                                                                             %
791
%                                                                             %
792
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
793
%
794
%  RegisterVIFFImage() adds properties for the VIFF image format to
795
%  the list of supported formats.  The properties include the image format
796
%  tag, a method to read and/or write the format, whether the format
797
%  supports the saving of more than one frame to the same file or blob,
798
%  whether the format supports native in-memory I/O, and a brief
799
%  description of the format.
800
%
801
%  The format of the RegisterVIFFImage method is:
802
%
803
%      size_t RegisterVIFFImage(void)
804
%
805
*/
806
ModuleExport size_t RegisterVIFFImage(void)
807
10
{
808
10
  MagickInfo
809
10
    *entry;
810
811
10
  entry=AcquireMagickInfo("VIFF","VIFF","Khoros Visualization image");
812
10
  entry->decoder=(DecodeImageHandler *) ReadVIFFImage;
813
10
  entry->encoder=(EncodeImageHandler *) WriteVIFFImage;
814
10
  entry->magick=(IsImageFormatHandler *) IsVIFF;
815
10
  entry->flags|=CoderDecoderSeekableStreamFlag;
816
10
  (void) RegisterMagickInfo(entry);
817
10
  entry=AcquireMagickInfo("VIFF","XV","Khoros Visualization image");
818
10
  entry->decoder=(DecodeImageHandler *) ReadVIFFImage;
819
10
  entry->encoder=(EncodeImageHandler *) WriteVIFFImage;
820
10
  entry->flags|=CoderDecoderSeekableStreamFlag;
821
10
  (void) RegisterMagickInfo(entry);
822
10
  return(MagickImageCoderSignature);
823
10
}
824

825
/*
826
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
827
%                                                                             %
828
%                                                                             %
829
%                                                                             %
830
%   U n r e g i s t e r V I F F I m a g e                                     %
831
%                                                                             %
832
%                                                                             %
833
%                                                                             %
834
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
835
%
836
%  UnregisterVIFFImage() removes format registrations made by the
837
%  VIFF module from the list of supported formats.
838
%
839
%  The format of the UnregisterVIFFImage method is:
840
%
841
%      UnregisterVIFFImage(void)
842
%
843
*/
844
ModuleExport void UnregisterVIFFImage(void)
845
0
{
846
0
  (void) UnregisterMagickInfo("VIFF");
847
0
  (void) UnregisterMagickInfo("XV");
848
0
}
849

850
/*
851
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
852
%                                                                             %
853
%                                                                             %
854
%                                                                             %
855
%   W r i t e V I F F I m a g e                                               %
856
%                                                                             %
857
%                                                                             %
858
%                                                                             %
859
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
860
%
861
%  WriteVIFFImage() writes an image to a file in the VIFF image format.
862
%
863
%  The format of the WriteVIFFImage method is:
864
%
865
%      MagickBooleanType WriteVIFFImage(const ImageInfo *image_info,
866
%        Image *image,ExceptionInfo *exception)
867
%
868
%  A description of each parameter follows.
869
%
870
%    o image_info: the image info.
871
%
872
%    o image:  The image.
873
%
874
%    o exception: return any errors or warnings in this structure.
875
%
876
*/
877
static MagickBooleanType WriteVIFFImage(const ImageInfo *image_info,
878
  Image *image,ExceptionInfo *exception)
879
516
{
880
516
#define VFF_CM_genericRGB  15
881
516
#define VFF_CM_NONE  0
882
516
#define VFF_DEP_IEEEORDER  0x2
883
516
#define VFF_DES_RAW  0
884
516
#define VFF_LOC_IMPLICIT  1
885
516
#define VFF_MAPTYP_NONE  0
886
516
#define VFF_MAPTYP_1_BYTE  1
887
516
#define VFF_MS_NONE  0
888
516
#define VFF_MS_ONEPERBAND  1
889
516
#define VFF_TYP_BIT  0
890
516
#define VFF_TYP_1_BYTE  1
891
892
516
  typedef struct _ViffInfo
893
516
  {
894
516
    char
895
516
      identifier,
896
516
      file_type,
897
516
      release,
898
516
      version,
899
516
      machine_dependency,
900
516
      reserve[3],
901
516
      comment[512];
902
903
516
    size_t
904
516
      rows,
905
516
      columns,
906
516
      subrows;
907
908
516
    int
909
516
      x_offset,
910
516
      y_offset;
911
912
516
    unsigned int
913
516
      x_bits_per_pixel,
914
516
      y_bits_per_pixel,
915
516
      location_type,
916
516
      location_dimension,
917
516
      number_of_images,
918
516
      number_data_bands,
919
516
      data_storage_type,
920
516
      data_encode_scheme,
921
516
      map_scheme,
922
516
      map_storage_type,
923
516
      map_rows,
924
516
      map_columns,
925
516
      map_subrows,
926
516
      map_enable,
927
516
      maps_per_cycle,
928
516
      color_space_model;
929
516
  } ViffInfo;
930
931
516
  const char
932
516
    *value;
933
934
516
  const Quantum
935
516
    *p;
936
937
516
  MagickBooleanType
938
516
    status;
939
940
516
  MagickOffsetType
941
516
    scene;
942
943
516
  MagickSizeType
944
516
    number_pixels,
945
516
    packets;
946
947
516
  MemoryInfo
948
516
    *pixel_info;
949
950
516
  size_t
951
516
    number_scenes;
952
953
516
  ssize_t
954
516
    i,
955
516
    x,
956
516
    y;
957
958
516
  unsigned char
959
516
    *pixels,
960
516
    *q;
961
962
516
  ViffInfo
963
516
    viff_info;
964
965
  /*
966
    Open output image file.
967
  */
968
516
  assert(image_info != (const ImageInfo *) NULL);
969
516
  assert(image_info->signature == MagickCoreSignature);
970
516
  assert(image != (Image *) NULL);
971
516
  assert(image->signature == MagickCoreSignature);
972
516
  assert(exception != (ExceptionInfo *) NULL);
973
516
  assert(exception->signature == MagickCoreSignature);
974
516
  if (IsEventLogging() != MagickFalse)
975
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
976
516
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
977
516
  if (status == MagickFalse)
978
0
    return(status);
979
516
  (void) memset(&viff_info,0,sizeof(ViffInfo));
980
516
  scene=0;
981
516
  number_scenes=GetImageListLength(image);
982
516
  do
983
516
  {
984
516
    MagickBooleanType
985
516
      is_gray;
986
987
    /*
988
      Initialize VIFF image structure.
989
    */
990
516
    (void) TransformImageColorspace(image,sRGBColorspace,exception);
991
516
    viff_info.identifier=(char) -85;
992
516
    viff_info.file_type=1;
993
516
    viff_info.release=1;
994
516
    viff_info.version=3;
995
516
    viff_info.machine_dependency=VFF_DEP_IEEEORDER;  /* IEEE byte ordering */
996
516
    *viff_info.comment='\0';
997
516
    value=GetImageProperty(image,"comment",exception);
998
516
    if (value != (const char *) NULL)
999
265
      (void) CopyMagickString(viff_info.comment,value,MagickMin(strlen(value),
1000
265
        511)+1);
1001
516
    viff_info.rows=image->columns;
1002
516
    viff_info.columns=image->rows;
1003
516
    viff_info.subrows=0;
1004
516
    viff_info.x_offset=(~0);
1005
516
    viff_info.y_offset=(~0);
1006
516
    viff_info.x_bits_per_pixel=0;
1007
516
    viff_info.y_bits_per_pixel=0;
1008
516
    viff_info.location_type=VFF_LOC_IMPLICIT;
1009
516
    viff_info.location_dimension=0;
1010
516
    viff_info.number_of_images=1;
1011
516
    viff_info.data_encode_scheme=VFF_DES_RAW;
1012
516
    viff_info.map_scheme=VFF_MS_NONE;
1013
516
    viff_info.map_storage_type=VFF_MAPTYP_NONE;
1014
516
    viff_info.map_rows=0;
1015
516
    viff_info.map_columns=0;
1016
516
    viff_info.map_subrows=0;
1017
516
    viff_info.map_enable=1;  /* no colormap */
1018
516
    viff_info.maps_per_cycle=0;
1019
516
    number_pixels=(MagickSizeType) image->columns*image->rows;
1020
516
    is_gray=IdentifyImageCoderGray(image,exception);
1021
516
    if (image->storage_class == DirectClass)
1022
300
      {
1023
        /*
1024
          Full color VIFF raster.
1025
        */
1026
300
        viff_info.number_data_bands=image->alpha_trait ? 4U : 3U;
1027
300
        viff_info.color_space_model=VFF_CM_genericRGB;
1028
300
        viff_info.data_storage_type=VFF_TYP_1_BYTE;
1029
300
        packets=viff_info.number_data_bands*number_pixels;
1030
300
      }
1031
216
    else
1032
216
      {
1033
216
        viff_info.number_data_bands=1;
1034
216
        viff_info.color_space_model=VFF_CM_NONE;
1035
216
        viff_info.data_storage_type=VFF_TYP_1_BYTE;
1036
216
        packets=number_pixels;
1037
216
        if (is_gray == MagickFalse)
1038
96
          {
1039
            /*
1040
              Colormapped VIFF raster.
1041
            */
1042
96
            viff_info.map_scheme=VFF_MS_ONEPERBAND;
1043
96
            viff_info.map_storage_type=VFF_MAPTYP_1_BYTE;
1044
96
            viff_info.map_rows=3;
1045
96
            viff_info.map_columns=(unsigned int) image->colors;
1046
96
          }
1047
120
        else
1048
120
          if (image->colors <= 2)
1049
26
            {
1050
              /*
1051
                Monochrome VIFF raster.
1052
              */
1053
26
              viff_info.data_storage_type=VFF_TYP_BIT;
1054
26
              packets=((image->columns+7) >> 3)*image->rows;
1055
26
            }
1056
216
      }
1057
    /*
1058
      Write VIFF image header (pad to 1024 bytes).
1059
    */
1060
516
    (void) WriteBlob(image,sizeof(viff_info.identifier),(unsigned char *)
1061
516
      &viff_info.identifier);
1062
516
    (void) WriteBlob(image,sizeof(viff_info.file_type),(unsigned char *)
1063
516
      &viff_info.file_type);
1064
516
    (void) WriteBlob(image,sizeof(viff_info.release),(unsigned char *)
1065
516
      &viff_info.release);
1066
516
    (void) WriteBlob(image,sizeof(viff_info.version),(unsigned char *)
1067
516
      &viff_info.version);
1068
516
    (void) WriteBlob(image,sizeof(viff_info.machine_dependency),
1069
516
      (unsigned char *) &viff_info.machine_dependency);
1070
516
    (void) WriteBlob(image,sizeof(viff_info.reserve),(unsigned char *)
1071
516
      viff_info.reserve);
1072
516
    (void) WriteBlob(image,512,(unsigned char *) viff_info.comment);
1073
516
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.rows);
1074
516
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.columns);
1075
516
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.subrows);
1076
516
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.x_offset);
1077
516
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.y_offset);
1078
516
    viff_info.x_bits_per_pixel=(unsigned int) ((63 << 24) | (128 << 16));
1079
516
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.x_bits_per_pixel);
1080
516
    viff_info.y_bits_per_pixel=(unsigned int) ((63 << 24) | (128 << 16));
1081
516
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.y_bits_per_pixel);
1082
516
    (void) WriteBlobMSBLong(image,viff_info.location_type);
1083
516
    (void) WriteBlobMSBLong(image,viff_info.location_dimension);
1084
516
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.number_of_images);
1085
516
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.number_data_bands);
1086
516
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.data_storage_type);
1087
516
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.data_encode_scheme);
1088
516
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_scheme);
1089
516
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_storage_type);
1090
516
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_rows);
1091
516
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_columns);
1092
516
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_subrows);
1093
516
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_enable);
1094
516
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.maps_per_cycle);
1095
516
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.color_space_model);
1096
217k
    for (i=0; i < 420; i++)
1097
216k
      (void) WriteBlobByte(image,'\0');
1098
    /*
1099
      Convert MIFF to VIFF raster pixels.
1100
    */
1101
516
    pixel_info=AcquireVirtualMemory((size_t) packets,sizeof(*pixels));
1102
516
    if (pixel_info == (MemoryInfo *) NULL)
1103
516
      ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1104
516
    pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
1105
516
    q=pixels;
1106
516
    if (image->storage_class == DirectClass)
1107
300
      {
1108
        /*
1109
          Convert DirectClass packet to VIFF RGB pixel.
1110
        */
1111
300
        number_pixels=(MagickSizeType) image->columns*image->rows;
1112
18.0k
        for (y=0; y < (ssize_t) image->rows; y++)
1113
17.7k
        {
1114
17.7k
          p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1115
17.7k
          if (p == (const Quantum *) NULL)
1116
0
            break;
1117
739k
          for (x=0; x < (ssize_t) image->columns; x++)
1118
721k
          {
1119
721k
            *q=ScaleQuantumToChar(GetPixelRed(image,p));
1120
721k
            *(q+number_pixels)=ScaleQuantumToChar(GetPixelGreen(image,p));
1121
721k
            *(q+number_pixels*2)=ScaleQuantumToChar(GetPixelBlue(image,p));
1122
721k
            if (image->alpha_trait != UndefinedPixelTrait)
1123
591k
              *(q+number_pixels*3)=ScaleQuantumToChar((Quantum)
1124
591k
                (GetPixelAlpha(image,p)));
1125
721k
            p+=(ptrdiff_t) GetPixelChannels(image);
1126
721k
            q++;
1127
721k
          }
1128
17.7k
          if (image->previous == (Image *) NULL)
1129
17.7k
            {
1130
17.7k
              status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1131
17.7k
                image->rows);
1132
17.7k
              if (status == MagickFalse)
1133
0
                break;
1134
17.7k
            }
1135
17.7k
        }
1136
300
      }
1137
216
    else
1138
216
      if (is_gray == MagickFalse)
1139
96
        {
1140
96
          unsigned char
1141
96
            *viff_colormap;
1142
1143
          /*
1144
            Dump colormap to file.
1145
          */
1146
96
          viff_colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
1147
96
            3*sizeof(*viff_colormap));
1148
96
          if (viff_colormap == (unsigned char *) NULL)
1149
96
            ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1150
96
          q=viff_colormap;
1151
17.5k
          for (i=0; i < (ssize_t) image->colors; i++)
1152
17.5k
            *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].red));
1153
17.5k
          for (i=0; i < (ssize_t) image->colors; i++)
1154
17.5k
            *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].green));
1155
17.5k
          for (i=0; i < (ssize_t) image->colors; i++)
1156
17.5k
            *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].blue));
1157
96
          (void) WriteBlob(image,3*image->colors,viff_colormap);
1158
96
          viff_colormap=(unsigned char *) RelinquishMagickMemory(viff_colormap);
1159
          /*
1160
            Convert PseudoClass packet to VIFF colormapped pixels.
1161
          */
1162
96
          q=pixels;
1163
3.15k
          for (y=0; y < (ssize_t) image->rows; y++)
1164
3.06k
          {
1165
3.06k
            p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1166
3.06k
            if (p == (const Quantum *) NULL)
1167
0
              break;
1168
10.7k
            for (x=0; x < (ssize_t) image->columns; x++)
1169
7.64k
            {
1170
7.64k
              *q++=(unsigned char) ((ssize_t) GetPixelIndex(image,p));
1171
7.64k
              p+=(ptrdiff_t) GetPixelChannels(image);
1172
7.64k
            }
1173
3.06k
            if (image->previous == (Image *) NULL)
1174
3.06k
              {
1175
3.06k
                status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1176
3.06k
                image->rows);
1177
3.06k
                if (status == MagickFalse)
1178
0
                  break;
1179
3.06k
              }
1180
3.06k
          }
1181
96
        }
1182
120
      else
1183
120
        if (image->colors <= 2)
1184
26
          {
1185
26
            unsigned char
1186
26
              bit,
1187
26
              byte;
1188
1189
            /*
1190
              Convert PseudoClass image to a VIFF monochrome image.
1191
            */
1192
434
            for (y=0; y < (ssize_t) image->rows; y++)
1193
408
            {
1194
408
              p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1195
408
              if (p == (const Quantum *) NULL)
1196
0
                break;
1197
408
              bit=0;
1198
408
              byte=0;
1199
2.37k
              for (x=0; x < (ssize_t) image->columns; x++)
1200
1.97k
              {
1201
1.97k
                byte>>=1;
1202
1.97k
                if (GetPixelLuma(image,p) < ((double) QuantumRange/2.0))
1203
1.58k
                  byte|=0x80;
1204
1.97k
                bit++;
1205
1.97k
                if (bit == 8)
1206
218
                  {
1207
218
                    *q++=byte;
1208
218
                    bit=0;
1209
218
                    byte=0;
1210
218
                  }
1211
1.97k
                p+=(ptrdiff_t) GetPixelChannels(image);
1212
1.97k
              }
1213
408
              if (bit != 0)
1214
214
                *q++=byte >> (8-bit);
1215
408
              if (image->previous == (Image *) NULL)
1216
408
                {
1217
408
                  status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1218
408
                    y,image->rows);
1219
408
                  if (status == MagickFalse)
1220
0
                    break;
1221
408
                }
1222
408
            }
1223
26
          }
1224
94
        else
1225
94
          {
1226
            /*
1227
              Convert PseudoClass packet to VIFF grayscale pixel.
1228
            */
1229
5.49k
            for (y=0; y < (ssize_t) image->rows; y++)
1230
5.39k
            {
1231
5.39k
              p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1232
5.39k
              if (p == (const Quantum *) NULL)
1233
0
                break;
1234
19.8k
              for (x=0; x < (ssize_t) image->columns; x++)
1235
14.4k
              {
1236
14.4k
                *q++=(unsigned char) ClampToQuantum(GetPixelLuma(image,p));
1237
14.4k
                p+=(ptrdiff_t) GetPixelChannels(image);
1238
14.4k
              }
1239
5.39k
              if (image->previous == (Image *) NULL)
1240
5.39k
                {
1241
5.39k
                  status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1242
5.39k
                    y,image->rows);
1243
5.39k
                  if (status == MagickFalse)
1244
0
                    break;
1245
5.39k
                }
1246
5.39k
            }
1247
94
          }
1248
516
    (void) WriteBlob(image,(size_t) packets,pixels);
1249
516
    pixel_info=RelinquishVirtualMemory(pixel_info);
1250
516
    if (GetNextImageInList(image) == (Image *) NULL)
1251
516
      break;
1252
0
    image=SyncNextImageInList(image);
1253
0
    status=SetImageProgress(image,SaveImagesTag,scene++,number_scenes);
1254
0
    if (status == MagickFalse)
1255
0
      break;
1256
0
  } while (image_info->adjoin != MagickFalse);
1257
516
  if (CloseBlob(image) == MagickFalse)
1258
0
    status=MagickFalse;
1259
516
  return(status);
1260
516
}