Coverage Report

Created: 2026-02-14 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/imagemagick/coders/viff.c
Line
Count
Source
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/license/                                         %
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.76k
{
144
1.76k
#define VFF_CM_genericRGB  15
145
1.76k
#define VFF_CM_ntscRGB  1
146
1.76k
#define VFF_CM_NONE  0
147
3.64k
#define VFF_DEP_DECORDER  0x4
148
3.38k
#define VFF_DEP_NSORDER  0x8
149
1.76k
#define VFF_DES_RAW  0
150
1.76k
#define VFF_LOC_IMPLICIT  1
151
1.76k
#define VFF_MAPTYP_NONE  0
152
1.76k
#define VFF_MAPTYP_1_BYTE  1
153
507M
#define VFF_MAPTYP_2_BYTE  2
154
234M
#define VFF_MAPTYP_4_BYTE  4
155
129M
#define VFF_MAPTYP_FLOAT  5
156
16.5M
#define VFF_MAPTYP_DOUBLE  7
157
150k
#define VFF_MS_NONE  0
158
1.76k
#define VFF_MS_ONEPERBAND  1
159
1.76k
#define VFF_MS_SHARED  3
160
5.70k
#define VFF_TYP_BIT  0
161
2.15k
#define VFF_TYP_1_BYTE  1
162
3.66k
#define VFF_TYP_2_BYTE  2
163
1.76k
#define VFF_TYP_4_BYTE  4
164
2.35k
#define VFF_TYP_FLOAT  5
165
1.76k
#define VFF_TYP_DOUBLE  9
166
167
1.76k
  typedef struct _ViffInfo
168
1.76k
  {
169
1.76k
    unsigned char
170
1.76k
      identifier,
171
1.76k
      file_type,
172
1.76k
      release,
173
1.76k
      version,
174
1.76k
      machine_dependency,
175
1.76k
      reserve[3];
176
177
1.76k
    char
178
1.76k
      comment[512];
179
180
1.76k
    unsigned int
181
1.76k
      rows,
182
1.76k
      columns,
183
1.76k
      subrows;
184
185
1.76k
    int
186
1.76k
      x_offset,
187
1.76k
      y_offset;
188
189
1.76k
    float
190
1.76k
      x_bits_per_pixel,
191
1.76k
      y_bits_per_pixel;
192
193
1.76k
    unsigned int
194
1.76k
      location_type,
195
1.76k
      location_dimension,
196
1.76k
      number_of_images,
197
1.76k
      number_data_bands,
198
1.76k
      data_storage_type,
199
1.76k
      data_encode_scheme,
200
1.76k
      map_scheme,
201
1.76k
      map_storage_type,
202
1.76k
      map_rows,
203
1.76k
      map_columns,
204
1.76k
      map_subrows,
205
1.76k
      map_enable,
206
1.76k
      maps_per_cycle,
207
1.76k
      color_space_model;
208
1.76k
  } ViffInfo;
209
210
1.76k
  double
211
1.76k
    min_value,
212
1.76k
    scale_factor,
213
1.76k
    value;
214
215
1.76k
  Image
216
1.76k
    *image;
217
218
1.76k
  int
219
1.76k
    bit;
220
221
1.76k
  MagickBooleanType
222
1.76k
    status;
223
224
1.76k
  MagickSizeType
225
1.76k
    number_pixels;
226
227
1.76k
  Quantum
228
1.76k
    *q;
229
230
1.76k
  size_t
231
1.76k
    bytes_per_pixel,
232
1.76k
    max_packets,
233
1.76k
    quantum;
234
235
1.76k
  ssize_t
236
1.76k
    count,
237
1.76k
    i,
238
1.76k
    x,
239
1.76k
    y;
240
241
1.76k
  unsigned char
242
1.76k
    *p,
243
1.76k
    *pixels;
244
245
1.76k
  unsigned long
246
1.76k
    lsb_first;
247
248
1.76k
  ViffInfo
249
1.76k
    viff_info;
250
251
  /*
252
    Open image file.
253
  */
254
1.76k
  assert(image_info != (const ImageInfo *) NULL);
255
1.76k
  assert(image_info->signature == MagickCoreSignature);
256
1.76k
  assert(exception != (ExceptionInfo *) NULL);
257
1.76k
  assert(exception->signature == MagickCoreSignature);
258
1.76k
  if (IsEventLogging() != MagickFalse)
259
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
260
0
      image_info->filename);
261
1.76k
  image=AcquireImage(image_info,exception);
262
1.76k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
263
1.76k
  if (status == MagickFalse)
264
73
    {
265
73
      image=DestroyImageList(image);
266
73
      return((Image *) NULL);
267
73
    }
268
  /*
269
    Read VIFF header (1024 bytes).
270
  */
271
1.69k
  count=ReadBlob(image,1,&viff_info.identifier);
272
1.69k
  do
273
2.23k
  {
274
    /*
275
      Verify VIFF identifier.
276
    */
277
2.23k
    if ((count != 1) || ((unsigned char) viff_info.identifier != 0xab))
278
2.04k
      ThrowReaderException(CorruptImageError,"NotAVIFFImage");
279
    /*
280
      Initialize VIFF image.
281
    */
282
2.04k
    (void) ReadBlob(image,sizeof(viff_info.file_type),&viff_info.file_type);
283
2.04k
    (void) ReadBlob(image,sizeof(viff_info.release),&viff_info.release);
284
2.04k
    (void) ReadBlob(image,sizeof(viff_info.version),&viff_info.version);
285
2.04k
    (void) ReadBlob(image,sizeof(viff_info.machine_dependency),
286
2.04k
      &viff_info.machine_dependency);
287
2.04k
    (void) ReadBlob(image,sizeof(viff_info.reserve),viff_info.reserve);
288
2.04k
    count=ReadBlob(image,512,(unsigned char *) viff_info.comment);
289
2.04k
    if (count != 512)
290
1.99k
      ThrowReaderException(CorruptImageError,"ImproperImageHeader");
291
1.99k
    viff_info.comment[511]='\0';
292
1.99k
    if (strlen(viff_info.comment) > 4)
293
1.04k
      (void) SetImageProperty(image,"comment",viff_info.comment,exception);
294
1.99k
    if ((viff_info.machine_dependency == VFF_DEP_DECORDER) ||
295
1.86k
        (viff_info.machine_dependency == VFF_DEP_NSORDER))
296
422
      image->endian=LSBEndian;
297
1.56k
    else
298
1.56k
      image->endian=MSBEndian;
299
1.99k
    viff_info.rows=ReadBlobLong(image);
300
1.99k
    viff_info.columns=ReadBlobLong(image);
301
1.99k
    viff_info.subrows=ReadBlobLong(image);
302
1.99k
    viff_info.x_offset=ReadBlobSignedLong(image);
303
1.99k
    viff_info.y_offset=ReadBlobSignedLong(image);
304
1.99k
    viff_info.x_bits_per_pixel=(float) ReadBlobLong(image);
305
1.99k
    viff_info.y_bits_per_pixel=(float) ReadBlobLong(image);
306
1.99k
    viff_info.location_type=ReadBlobLong(image);
307
1.99k
    viff_info.location_dimension=ReadBlobLong(image);
308
1.99k
    viff_info.number_of_images=ReadBlobLong(image);
309
1.99k
    viff_info.number_data_bands=ReadBlobLong(image);
310
1.99k
    viff_info.data_storage_type=ReadBlobLong(image);
311
1.99k
    viff_info.data_encode_scheme=ReadBlobLong(image);
312
1.99k
    viff_info.map_scheme=ReadBlobLong(image);
313
1.99k
    viff_info.map_storage_type=ReadBlobLong(image);
314
1.99k
    viff_info.map_rows=ReadBlobLong(image);
315
1.99k
    viff_info.map_columns=ReadBlobLong(image);
316
1.99k
    viff_info.map_subrows=ReadBlobLong(image);
317
1.99k
    viff_info.map_enable=ReadBlobLong(image);
318
1.99k
    viff_info.maps_per_cycle=ReadBlobLong(image);
319
1.99k
    viff_info.color_space_model=ReadBlobLong(image);
320
838k
    for (i=0; i < 420; i++)
321
836k
      (void) ReadBlobByte(image);
322
1.99k
    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.79k
      ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
327
1.79k
    if (number_pixels != (size_t) number_pixels)
328
1.79k
      ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
329
1.79k
    if (number_pixels == 0)
330
1.78k
      ThrowReaderException(CoderError,"ImageColumnOrRowSizeIsNotSupported");
331
1.78k
    image->columns=viff_info.rows;
332
1.78k
    image->rows=viff_info.columns;
333
1.78k
    image->depth=viff_info.x_bits_per_pixel <= 8 ? 8UL :
334
1.78k
      MAGICKCORE_QUANTUM_DEPTH;
335
1.78k
    image->alpha_trait=viff_info.number_data_bands == 4 ? BlendPixelTrait :
336
1.78k
      UndefinedPixelTrait;
337
1.78k
    status=SetImageExtent(image,image->columns,image->rows,exception);
338
1.78k
    if (status == MagickFalse)
339
41
      return(DestroyImageList(image));
340
1.74k
    (void) SetImageBackgroundColor(image,exception);
341
    /*
342
      Verify that we can read this VIFF image.
343
    */
344
1.74k
    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.07k
        (viff_info.data_storage_type != VFF_TYP_1_BYTE) &&
348
315
        (viff_info.data_storage_type != VFF_TYP_2_BYTE) &&
349
226
        (viff_info.data_storage_type != VFF_TYP_4_BYTE) &&
350
153
        (viff_info.data_storage_type != VFF_TYP_FLOAT) &&
351
96
        (viff_info.data_storage_type != VFF_TYP_DOUBLE))
352
1.63k
      ThrowReaderException(CoderError,"DataStorageTypeIsNotSupported");
353
1.63k
    if (viff_info.data_encode_scheme != VFF_DES_RAW)
354
1.59k
      ThrowReaderException(CoderError,"DataEncodingSchemeIsNotSupported");
355
1.59k
    if ((viff_info.map_storage_type != VFF_MAPTYP_NONE) &&
356
590
        (viff_info.map_storage_type != VFF_MAPTYP_1_BYTE) &&
357
499
        (viff_info.map_storage_type != VFF_MAPTYP_2_BYTE) &&
358
276
        (viff_info.map_storage_type != VFF_MAPTYP_4_BYTE) &&
359
191
        (viff_info.map_storage_type != VFF_MAPTYP_FLOAT) &&
360
124
        (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
194
        (viff_info.color_space_model != VFF_CM_ntscRGB) &&
364
97
        (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
377
      viff_info.map_scheme=VFF_MS_NONE;
372
1.40k
    switch ((int) viff_info.map_scheme)
373
1.40k
    {
374
683
      case VFF_MS_NONE:
375
683
      {
376
683
        if (viff_info.number_data_bands < 3)
377
428
          {
378
            /*
379
              Create linear color ramp.
380
            */
381
428
            if (viff_info.data_storage_type == VFF_TYP_BIT)
382
200
              image->colors=2;
383
228
            else
384
228
              if (viff_info.data_storage_type == VFF_MAPTYP_1_BYTE)
385
105
                image->colors=256UL;
386
123
              else
387
123
                image->colors=image->depth <= 8 ? 256UL : 65536UL;
388
428
            status=AcquireImageColormap(image,image->colors,exception);
389
428
            if (status == MagickFalse)
390
428
              ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
391
428
          }
392
683
        break;
393
683
      }
394
683
      case VFF_MS_ONEPERBAND:
395
718
      case VFF_MS_SHARED:
396
718
      {
397
718
        unsigned char
398
718
          *viff_colormap;
399
400
        /*
401
          Allocate VIFF colormap.
402
        */
403
718
        switch ((int) viff_info.map_storage_type)
404
718
        {
405
17
          case VFF_MAPTYP_1_BYTE: bytes_per_pixel=1; break;
406
70
          case VFF_MAPTYP_2_BYTE: bytes_per_pixel=2; break;
407
73
          case VFF_MAPTYP_4_BYTE: bytes_per_pixel=4; break;
408
59
          case VFF_MAPTYP_FLOAT: bytes_per_pixel=4; break;
409
41
          case VFF_MAPTYP_DOUBLE: bytes_per_pixel=8; break;
410
458
          default: bytes_per_pixel=1; break;
411
718
        }
412
718
        image->colors=viff_info.map_columns;
413
718
        count=(ssize_t) (bytes_per_pixel*image->colors*viff_info.map_rows);
414
718
        if ((MagickSizeType) count > GetBlobSize(image))
415
624
          ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
416
624
        if ((MagickSizeType) viff_info.map_rows >
417
624
            (viff_info.map_rows*bytes_per_pixel*sizeof(*viff_colormap)))
418
624
          ThrowReaderException(CorruptImageError,"ImproperImageHeader");
419
624
        if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
420
619
          ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
421
619
        viff_colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
422
619
          viff_info.map_rows*bytes_per_pixel*sizeof(*viff_colormap));
423
619
        if (viff_colormap == (unsigned char *) NULL)
424
597
          ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
425
        /*
426
          Read VIFF raster colormap.
427
        */
428
597
        if (ReadBlob(image,(size_t) count,viff_colormap) != count)
429
25
          {
430
25
            viff_colormap=(unsigned char *) RelinquishMagickMemory(
431
25
              viff_colormap);
432
25
            ThrowReaderException(CorruptImageError,
433
25
              "InsufficientImageDataInFile");
434
0
          }
435
572
        lsb_first=1;
436
572
        if (*(char *) &lsb_first &&
437
572
            ((viff_info.machine_dependency != VFF_DEP_DECORDER) &&
438
510
             (viff_info.machine_dependency != VFF_DEP_NSORDER)))
439
403
          switch ((int) viff_info.map_storage_type)
440
403
          {
441
59
            case VFF_MAPTYP_2_BYTE:
442
59
            {
443
59
              MSBOrderShort(viff_colormap,(bytes_per_pixel*image->colors*
444
59
                viff_info.map_rows));
445
59
              break;
446
0
            }
447
64
            case VFF_MAPTYP_4_BYTE:
448
114
            case VFF_MAPTYP_FLOAT:
449
114
            {
450
114
              MSBOrderLong(viff_colormap,(bytes_per_pixel*image->colors*
451
114
                viff_info.map_rows));
452
114
              break;
453
64
            }
454
230
            default: break;
455
403
          }
456
2.62G
        for (i=0; i < (ssize_t) (viff_info.map_rows*image->colors); i++)
457
2.62G
        {
458
2.62G
          switch ((int) viff_info.map_storage_type)
459
2.62G
          {
460
507M
            case VFF_MAPTYP_2_BYTE: value=1.0*((short *) viff_colormap)[i]; break;
461
234M
            case VFF_MAPTYP_4_BYTE: value=1.0*((int *) viff_colormap)[i]; break;
462
129M
            case VFF_MAPTYP_FLOAT: value=((float *) viff_colormap)[i]; break;
463
16.5M
            case VFF_MAPTYP_DOUBLE: value=((double *) viff_colormap)[i]; break;
464
1.73G
            default: value=1.0*viff_colormap[i]; break;
465
2.62G
          }
466
2.62G
          if (i < (ssize_t) image->colors)
467
35.6k
            {
468
35.6k
              image->colormap[i].red=(MagickRealType)
469
35.6k
                ScaleCharToQuantum((unsigned char) value);
470
35.6k
              image->colormap[i].green=(MagickRealType)
471
35.6k
                ScaleCharToQuantum((unsigned char) value);
472
35.6k
              image->colormap[i].blue=(MagickRealType)
473
35.6k
                ScaleCharToQuantum((unsigned char) value);
474
35.6k
            }
475
2.62G
          else
476
2.62G
            if (i < (ssize_t) (2*image->colors))
477
13.2k
              image->colormap[i % (ssize_t) image->colors].green=
478
13.2k
                (MagickRealType) ScaleCharToQuantum((unsigned char) value);
479
2.62G
            else
480
2.62G
              if (i < (ssize_t) (3*image->colors))
481
866
                image->colormap[i % (ssize_t) image->colors].blue=
482
866
                  (MagickRealType) ScaleCharToQuantum((unsigned char) value);
483
2.62G
        }
484
572
        viff_colormap=(unsigned char *) RelinquishMagickMemory(viff_colormap);
485
572
        break;
486
572
      }
487
4
      default:
488
4
        ThrowReaderException(CoderError,"ColormapTypeNotSupported");
489
1.40k
    }
490
1.25k
    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.25k
    if (viff_info.data_storage_type == VFF_TYP_BIT)
494
486
      {
495
        /*
496
          Create bi-level colormap.
497
        */
498
486
        image->colors=2;
499
486
        if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
500
486
          ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
501
486
        image->colorspace=GRAYColorspace;
502
486
      }
503
    /*
504
      Allocate VIFF pixels.
505
    */
506
1.25k
    switch ((int) viff_info.data_storage_type)
507
1.25k
    {
508
61
      case VFF_TYP_2_BYTE: bytes_per_pixel=2; break;
509
65
      case VFF_TYP_4_BYTE: bytes_per_pixel=4; break;
510
49
      case VFF_TYP_FLOAT: bytes_per_pixel=4; break;
511
32
      case VFF_TYP_DOUBLE: bytes_per_pixel=8; break;
512
1.04k
      default: bytes_per_pixel=1; break;
513
1.25k
    }
514
1.25k
    if (viff_info.data_storage_type == VFF_TYP_BIT)
515
486
      {
516
486
        if (HeapOverflowSanityCheckGetSize((image->columns+7UL) >> 3UL,image->rows,&max_packets) != MagickFalse)
517
486
          ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
518
486
      }
519
769
    else
520
769
      {
521
769
        if (HeapOverflowSanityCheckGetSize((size_t) number_pixels,viff_info.number_data_bands,&max_packets) != MagickFalse)
522
769
          ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
523
769
      }
524
1.25k
    count=(ssize_t) (bytes_per_pixel*max_packets);
525
1.25k
    if ((MagickSizeType) count > GetBlobSize(image))
526
1.22k
      ThrowReaderException(CorruptImageError,"ImproperImageHeader");
527
1.22k
    pixels=(unsigned char *) AcquireQuantumMemory((size_t) MagickMax(
528
1.22k
      number_pixels,max_packets),bytes_per_pixel*sizeof(*pixels));
529
1.22k
    if (pixels == (unsigned char *) NULL)
530
1.22k
      ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
531
1.22k
    (void) memset(pixels,0,(size_t) MagickMax(number_pixels,max_packets)*
532
1.22k
      bytes_per_pixel*sizeof(*pixels));
533
1.22k
    if (ReadBlob(image,(size_t) count,pixels) != count)
534
144
      {
535
144
        pixels=(unsigned char *) RelinquishMagickMemory(pixels);
536
144
        ThrowReaderException(CorruptImageError,"ImproperImageHeader");
537
0
      }
538
1.07k
    lsb_first=1;
539
1.07k
    if (*(char *) &lsb_first &&
540
1.07k
        ((viff_info.machine_dependency != VFF_DEP_DECORDER) &&
541
1.00k
         (viff_info.machine_dependency != VFF_DEP_NSORDER)))
542
836
      switch ((int) viff_info.data_storage_type)
543
836
      {
544
42
        case VFF_TYP_2_BYTE:
545
42
        {
546
42
          MSBOrderShort(pixels,bytes_per_pixel*max_packets);
547
42
          break;
548
0
        }
549
55
        case VFF_TYP_4_BYTE:
550
94
        case VFF_TYP_FLOAT:
551
94
        {
552
94
          MSBOrderLong(pixels,bytes_per_pixel*max_packets);
553
94
          break;
554
55
        }
555
700
        default: break;
556
836
      }
557
1.07k
    min_value=0.0;
558
1.07k
    scale_factor=1.0;
559
1.07k
    if ((viff_info.data_storage_type != VFF_TYP_1_BYTE) &&
560
574
        (viff_info.map_scheme == VFF_MS_NONE))
561
455
      {
562
455
        double
563
455
          max_value;
564
565
        /*
566
          Determine scale factor.
567
        */
568
455
        switch ((int) viff_info.data_storage_type)
569
455
        {
570
29
          case VFF_TYP_2_BYTE: value=1.0*((short *) pixels)[0]; break;
571
35
          case VFF_TYP_4_BYTE: value=1.0*((int *) pixels)[0]; break;
572
39
          case VFF_TYP_FLOAT: value=((float *) pixels)[0]; break;
573
23
          case VFF_TYP_DOUBLE: value=((double *) pixels)[0]; break;
574
329
          default: value=1.0*pixels[0]; break;
575
455
        }
576
455
        max_value=value;
577
455
        min_value=value;
578
99.2k
        for (i=0; i < (ssize_t) max_packets; i++)
579
98.7k
        {
580
98.7k
          switch ((int) viff_info.data_storage_type)
581
98.7k
          {
582
1.60k
            case VFF_TYP_2_BYTE: value=1.0*((short *) pixels)[i]; break;
583
221
            case VFF_TYP_4_BYTE: value=1.0*((int *) pixels)[i]; break;
584
1.01k
            case VFF_TYP_FLOAT: value=((float *) pixels)[i]; break;
585
209
            case VFF_TYP_DOUBLE: value=((double *) pixels)[i]; break;
586
95.7k
            default: value=1.0*pixels[i]; break;
587
98.7k
          }
588
98.7k
          if (value > max_value)
589
556
            max_value=value;
590
98.2k
          else
591
98.2k
            if (value < min_value)
592
343
              min_value=value;
593
98.7k
        }
594
455
        if ((min_value == 0) && (max_value == 0))
595
93
          scale_factor=0;
596
362
        else
597
362
          if (min_value == max_value)
598
188
            {
599
188
              scale_factor=(double) QuantumRange/min_value;
600
188
              min_value=0;
601
188
            }
602
174
          else
603
174
            scale_factor=(double) QuantumRange/(max_value-min_value);
604
455
      }
605
    /*
606
      Convert pixels to Quantum size.
607
    */
608
1.07k
    p=(unsigned char *) pixels;
609
150k
    for (i=0; i < (ssize_t) max_packets; i++)
610
148k
    {
611
148k
      switch ((int) viff_info.data_storage_type)
612
148k
      {
613
1.61k
        case VFF_TYP_2_BYTE: value=1.0*((short *) pixels)[i]; break;
614
273
        case VFF_TYP_4_BYTE: value=1.0*((int *) pixels)[i]; break;
615
1.01k
        case VFF_TYP_FLOAT: value=((float *) pixels)[i]; break;
616
210
        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
127k
        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.07k
    p=(unsigned char *) pixels;
628
1.07k
    if (viff_info.data_storage_type == VFF_TYP_BIT)
629
411
      {
630
        /*
631
          Convert bitmap scanline.
632
        */
633
18.1k
        for (y=0; y < (ssize_t) image->rows; y++)
634
17.7k
        {
635
17.7k
          q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
636
17.7k
          if (q == (Quantum *) NULL)
637
0
            break;
638
107k
          for (x=0; x < (ssize_t) (image->columns-7); x+=8)
639
90.0k
          {
640
810k
            for (bit=0; bit < 8; bit++)
641
720k
            {
642
720k
              quantum=(size_t) ((*p) & (0x01 << bit) ? 0 : 1);
643
720k
              SetPixelRed(image,quantum == 0 ? 0 : QuantumRange,q);
644
720k
              SetPixelGreen(image,quantum == 0 ? 0 : QuantumRange,q);
645
720k
              SetPixelBlue(image,quantum == 0 ? 0 : QuantumRange,q);
646
720k
              if (image->storage_class == PseudoClass)
647
720k
                SetPixelIndex(image,(Quantum) quantum,q);
648
720k
              q+=(ptrdiff_t) GetPixelChannels(image);
649
720k
            }
650
90.0k
            p++;
651
90.0k
          }
652
17.7k
          if ((image->columns % 8) != 0)
653
12.2k
            {
654
79.1k
              for (bit=0; bit < (int) (image->columns % 8); bit++)
655
66.9k
              {
656
66.9k
                quantum=(size_t) ((*p) & (0x01 << bit) ? 0 : 1);
657
66.9k
                SetPixelRed(image,quantum == 0 ? 0 : QuantumRange,q);
658
66.9k
                SetPixelGreen(image,quantum == 0 ? 0 : QuantumRange,q);
659
66.9k
                SetPixelBlue(image,quantum == 0 ? 0 : QuantumRange,q);
660
66.9k
                if (image->storage_class == PseudoClass)
661
66.9k
                  SetPixelIndex(image,(Quantum) quantum,q);
662
66.9k
                q+=(ptrdiff_t) GetPixelChannels(image);
663
66.9k
              }
664
12.2k
              p++;
665
12.2k
            }
666
17.7k
          if (SyncAuthenticPixels(image,exception) == MagickFalse)
667
0
            break;
668
17.7k
          if (image->previous == (Image *) NULL)
669
17.3k
            {
670
17.3k
              status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
671
17.3k
                image->rows);
672
17.3k
              if (status == MagickFalse)
673
0
                break;
674
17.3k
            }
675
17.7k
        }
676
411
      }
677
666
    else
678
666
      if (image->storage_class == PseudoClass)
679
12.5k
        for (y=0; y < (ssize_t) image->rows; y++)
680
11.9k
        {
681
11.9k
          q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
682
11.9k
          if (q == (Quantum *) NULL)
683
0
            break;
684
43.1k
          for (x=0; x < (ssize_t) image->columns; x++)
685
31.2k
          {
686
31.2k
            SetPixelIndex(image,*p++,q);
687
31.2k
            q+=(ptrdiff_t) GetPixelChannels(image);
688
31.2k
          }
689
11.9k
          if (SyncAuthenticPixels(image,exception) == MagickFalse)
690
0
            break;
691
11.9k
          if (image->previous == (Image *) NULL)
692
11.5k
            {
693
11.5k
              status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
694
11.5k
                image->rows);
695
11.5k
              if (status == MagickFalse)
696
0
                break;
697
11.5k
            }
698
11.9k
        }
699
90
      else
700
90
        {
701
          /*
702
            Convert DirectColor scanline.
703
          */
704
90
          number_pixels=(MagickSizeType) image->columns*image->rows;
705
1.23k
          for (y=0; y < (ssize_t) image->rows; y++)
706
1.14k
          {
707
1.14k
            q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
708
1.14k
            if (q == (Quantum *) NULL)
709
0
              break;
710
6.07k
            for (x=0; x < (ssize_t) image->columns; x++)
711
4.93k
            {
712
4.93k
              SetPixelRed(image,ScaleCharToQuantum(*p),q);
713
4.93k
              SetPixelGreen(image,ScaleCharToQuantum(*(p+number_pixels)),q);
714
4.93k
              SetPixelBlue(image,ScaleCharToQuantum(*(p+2*number_pixels)),q);
715
4.93k
              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
4.93k
              SetPixelAlpha(image,image->alpha_trait != UndefinedPixelTrait ?
731
4.41k
                ScaleCharToQuantum(*(p+number_pixels*3)) : OpaqueAlpha,q);
732
4.93k
              p++;
733
4.93k
              q+=(ptrdiff_t) GetPixelChannels(image);
734
4.93k
            }
735
1.14k
            if (SyncAuthenticPixels(image,exception) == MagickFalse)
736
0
              break;
737
1.14k
            if (image->previous == (Image *) NULL)
738
932
              {
739
932
                status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
740
932
                image->rows);
741
932
                if (status == MagickFalse)
742
0
                  break;
743
932
              }
744
1.14k
          }
745
90
        }
746
1.07k
    pixels=(unsigned char *) RelinquishMagickMemory(pixels);
747
1.07k
    if (image->storage_class == PseudoClass)
748
987
      (void) SyncImage(image,exception);
749
1.07k
    if (EOFBlob(image) != MagickFalse)
750
1.07k
      ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
751
    /*
752
      Proceed to next image.
753
    */
754
1.07k
    if (image_info->number_scenes != 0)
755
0
      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
756
0
        break;
757
1.07k
    count=ReadBlob(image,1,&viff_info.identifier);
758
1.07k
    if ((count == 1) && (viff_info.identifier == 0xab))
759
544
      {
760
        /*
761
          Allocate next image structure.
762
        */
763
544
        AcquireNextImage(image_info,image,exception);
764
544
        if (GetNextImageInList(image) == (Image *) NULL)
765
0
          {
766
0
            status=MagickFalse;
767
0
            break;
768
0
          }
769
544
        image=SyncNextImageInList(image);
770
544
        status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
771
544
          GetBlobSize(image));
772
544
        if (status == MagickFalse)
773
0
          break;
774
544
      }
775
1.07k
  } while ((count != 0) && (viff_info.identifier == 0xab));
776
533
  if (CloseBlob(image) == MagickFalse)
777
0
    status=MagickFalse;
778
533
  if (status == MagickFalse)
779
0
    return(DestroyImageList(image));
780
533
  return(GetFirstImageInList(image));
781
533
}
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
488
{
880
488
#define VFF_CM_genericRGB  15
881
488
#define VFF_CM_NONE  0
882
488
#define VFF_DEP_IEEEORDER  0x2
883
488
#define VFF_DES_RAW  0
884
488
#define VFF_LOC_IMPLICIT  1
885
488
#define VFF_MAPTYP_NONE  0
886
488
#define VFF_MAPTYP_1_BYTE  1
887
488
#define VFF_MS_NONE  0
888
488
#define VFF_MS_ONEPERBAND  1
889
488
#define VFF_TYP_BIT  0
890
488
#define VFF_TYP_1_BYTE  1
891
892
488
  typedef struct _ViffInfo
893
488
  {
894
488
    char
895
488
      identifier,
896
488
      file_type,
897
488
      release,
898
488
      version,
899
488
      machine_dependency,
900
488
      reserve[3],
901
488
      comment[512];
902
903
488
    size_t
904
488
      rows,
905
488
      columns,
906
488
      subrows;
907
908
488
    int
909
488
      x_offset,
910
488
      y_offset;
911
912
488
    unsigned int
913
488
      x_bits_per_pixel,
914
488
      y_bits_per_pixel,
915
488
      location_type,
916
488
      location_dimension,
917
488
      number_of_images,
918
488
      number_data_bands,
919
488
      data_storage_type,
920
488
      data_encode_scheme,
921
488
      map_scheme,
922
488
      map_storage_type,
923
488
      map_rows,
924
488
      map_columns,
925
488
      map_subrows,
926
488
      map_enable,
927
488
      maps_per_cycle,
928
488
      color_space_model;
929
488
  } ViffInfo;
930
931
488
  const char
932
488
    *value;
933
934
488
  const Quantum
935
488
    *p;
936
937
488
  MagickBooleanType
938
488
    status;
939
940
488
  MagickOffsetType
941
488
    scene;
942
943
488
  MagickSizeType
944
488
    number_pixels,
945
488
    packets;
946
947
488
  MemoryInfo
948
488
    *pixel_info;
949
950
488
  size_t
951
488
    number_scenes;
952
953
488
  ssize_t
954
488
    i,
955
488
    x,
956
488
    y;
957
958
488
  unsigned char
959
488
    *pixels,
960
488
    *q;
961
962
488
  ViffInfo
963
488
    viff_info;
964
965
  /*
966
    Open output image file.
967
  */
968
488
  assert(image_info != (const ImageInfo *) NULL);
969
488
  assert(image_info->signature == MagickCoreSignature);
970
488
  assert(image != (Image *) NULL);
971
488
  assert(image->signature == MagickCoreSignature);
972
488
  assert(exception != (ExceptionInfo *) NULL);
973
488
  assert(exception->signature == MagickCoreSignature);
974
488
  if (IsEventLogging() != MagickFalse)
975
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
976
488
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
977
488
  if (status == MagickFalse)
978
0
    return(status);
979
488
  (void) memset(&viff_info,0,sizeof(ViffInfo));
980
488
  scene=0;
981
488
  number_scenes=GetImageListLength(image);
982
488
  do
983
488
  {
984
488
    MagickBooleanType
985
488
      is_gray;
986
987
    /*
988
      Initialize VIFF image structure.
989
    */
990
488
    (void) TransformImageColorspace(image,sRGBColorspace,exception);
991
488
    viff_info.identifier=(char) -85;
992
488
    viff_info.file_type=1;
993
488
    viff_info.release=1;
994
488
    viff_info.version=3;
995
488
    viff_info.machine_dependency=VFF_DEP_IEEEORDER;  /* IEEE byte ordering */
996
488
    *viff_info.comment='\0';
997
488
    value=GetImageProperty(image,"comment",exception);
998
488
    if (value != (const char *) NULL)
999
268
      (void) CopyMagickString(viff_info.comment,value,MagickMin(strlen(value),
1000
268
        511)+1);
1001
488
    viff_info.rows=image->columns;
1002
488
    viff_info.columns=image->rows;
1003
488
    viff_info.subrows=0;
1004
488
    viff_info.x_offset=(~0);
1005
488
    viff_info.y_offset=(~0);
1006
488
    viff_info.x_bits_per_pixel=0;
1007
488
    viff_info.y_bits_per_pixel=0;
1008
488
    viff_info.location_type=VFF_LOC_IMPLICIT;
1009
488
    viff_info.location_dimension=0;
1010
488
    viff_info.number_of_images=1;
1011
488
    viff_info.data_encode_scheme=VFF_DES_RAW;
1012
488
    viff_info.map_scheme=VFF_MS_NONE;
1013
488
    viff_info.map_storage_type=VFF_MAPTYP_NONE;
1014
488
    viff_info.map_rows=0;
1015
488
    viff_info.map_columns=0;
1016
488
    viff_info.map_subrows=0;
1017
488
    viff_info.map_enable=1;  /* no colormap */
1018
488
    viff_info.maps_per_cycle=0;
1019
488
    number_pixels=(MagickSizeType) image->columns*image->rows;
1020
488
    is_gray=IdentifyImageCoderGray(image,exception);
1021
488
    if (image->storage_class == DirectClass)
1022
280
      {
1023
        /*
1024
          Full color VIFF raster.
1025
        */
1026
280
        viff_info.number_data_bands=image->alpha_trait ? 4U : 3U;
1027
280
        viff_info.color_space_model=VFF_CM_genericRGB;
1028
280
        viff_info.data_storage_type=VFF_TYP_1_BYTE;
1029
280
        packets=viff_info.number_data_bands*number_pixels;
1030
280
      }
1031
208
    else
1032
208
      {
1033
208
        viff_info.number_data_bands=1;
1034
208
        viff_info.color_space_model=VFF_CM_NONE;
1035
208
        viff_info.data_storage_type=VFF_TYP_1_BYTE;
1036
208
        packets=number_pixels;
1037
208
        if (is_gray == MagickFalse)
1038
88
          {
1039
            /*
1040
              Colormapped VIFF raster.
1041
            */
1042
88
            viff_info.map_scheme=VFF_MS_ONEPERBAND;
1043
88
            viff_info.map_storage_type=VFF_MAPTYP_1_BYTE;
1044
88
            viff_info.map_rows=3;
1045
88
            viff_info.map_columns=(unsigned int) image->colors;
1046
88
          }
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
208
      }
1057
    /*
1058
      Write VIFF image header (pad to 1024 bytes).
1059
    */
1060
488
    (void) WriteBlob(image,sizeof(viff_info.identifier),(unsigned char *)
1061
488
      &viff_info.identifier);
1062
488
    (void) WriteBlob(image,sizeof(viff_info.file_type),(unsigned char *)
1063
488
      &viff_info.file_type);
1064
488
    (void) WriteBlob(image,sizeof(viff_info.release),(unsigned char *)
1065
488
      &viff_info.release);
1066
488
    (void) WriteBlob(image,sizeof(viff_info.version),(unsigned char *)
1067
488
      &viff_info.version);
1068
488
    (void) WriteBlob(image,sizeof(viff_info.machine_dependency),
1069
488
      (unsigned char *) &viff_info.machine_dependency);
1070
488
    (void) WriteBlob(image,sizeof(viff_info.reserve),(unsigned char *)
1071
488
      viff_info.reserve);
1072
488
    (void) WriteBlob(image,512,(unsigned char *) viff_info.comment);
1073
488
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.rows);
1074
488
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.columns);
1075
488
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.subrows);
1076
488
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.x_offset);
1077
488
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.y_offset);
1078
488
    viff_info.x_bits_per_pixel=(unsigned int) ((63 << 24) | (128 << 16));
1079
488
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.x_bits_per_pixel);
1080
488
    viff_info.y_bits_per_pixel=(unsigned int) ((63 << 24) | (128 << 16));
1081
488
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.y_bits_per_pixel);
1082
488
    (void) WriteBlobMSBLong(image,viff_info.location_type);
1083
488
    (void) WriteBlobMSBLong(image,viff_info.location_dimension);
1084
488
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.number_of_images);
1085
488
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.number_data_bands);
1086
488
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.data_storage_type);
1087
488
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.data_encode_scheme);
1088
488
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_scheme);
1089
488
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_storage_type);
1090
488
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_rows);
1091
488
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_columns);
1092
488
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_subrows);
1093
488
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_enable);
1094
488
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.maps_per_cycle);
1095
488
    (void) WriteBlobMSBLong(image,(unsigned int) viff_info.color_space_model);
1096
205k
    for (i=0; i < 420; i++)
1097
204k
      (void) WriteBlobByte(image,'\0');
1098
    /*
1099
      Convert MIFF to VIFF raster pixels.
1100
    */
1101
488
    pixel_info=AcquireVirtualMemory((size_t) packets,sizeof(*pixels));
1102
488
    if (pixel_info == (MemoryInfo *) NULL)
1103
488
      ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1104
488
    pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
1105
488
    q=pixels;
1106
488
    if (image->storage_class == DirectClass)
1107
280
      {
1108
        /*
1109
          Convert DirectClass packet to VIFF RGB pixel.
1110
        */
1111
280
        number_pixels=(MagickSizeType) image->columns*image->rows;
1112
18.5k
        for (y=0; y < (ssize_t) image->rows; y++)
1113
18.2k
        {
1114
18.2k
          p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1115
18.2k
          if (p == (const Quantum *) NULL)
1116
0
            break;
1117
808k
          for (x=0; x < (ssize_t) image->columns; x++)
1118
790k
          {
1119
790k
            *q=ScaleQuantumToChar(GetPixelRed(image,p));
1120
790k
            *(q+number_pixels)=ScaleQuantumToChar(GetPixelGreen(image,p));
1121
790k
            *(q+number_pixels*2)=ScaleQuantumToChar(GetPixelBlue(image,p));
1122
790k
            if (image->alpha_trait != UndefinedPixelTrait)
1123
587k
              *(q+number_pixels*3)=ScaleQuantumToChar((Quantum)
1124
587k
                (GetPixelAlpha(image,p)));
1125
790k
            p+=(ptrdiff_t) GetPixelChannels(image);
1126
790k
            q++;
1127
790k
          }
1128
18.2k
          if (image->previous == (Image *) NULL)
1129
18.2k
            {
1130
18.2k
              status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1131
18.2k
                image->rows);
1132
18.2k
              if (status == MagickFalse)
1133
0
                break;
1134
18.2k
            }
1135
18.2k
        }
1136
280
      }
1137
208
    else
1138
208
      if (is_gray == MagickFalse)
1139
88
        {
1140
88
          unsigned char
1141
88
            *viff_colormap;
1142
1143
          /*
1144
            Dump colormap to file.
1145
          */
1146
88
          viff_colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
1147
88
            3*sizeof(*viff_colormap));
1148
88
          if (viff_colormap == (unsigned char *) NULL)
1149
88
            ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1150
88
          q=viff_colormap;
1151
12.5k
          for (i=0; i < (ssize_t) image->colors; i++)
1152
12.4k
            *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].red));
1153
12.5k
          for (i=0; i < (ssize_t) image->colors; i++)
1154
12.4k
            *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].green));
1155
12.5k
          for (i=0; i < (ssize_t) image->colors; i++)
1156
12.4k
            *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].blue));
1157
88
          (void) WriteBlob(image,3*image->colors,viff_colormap);
1158
88
          viff_colormap=(unsigned char *) RelinquishMagickMemory(viff_colormap);
1159
          /*
1160
            Convert PseudoClass packet to VIFF colormapped pixels.
1161
          */
1162
88
          q=pixels;
1163
5.84k
          for (y=0; y < (ssize_t) image->rows; y++)
1164
5.75k
          {
1165
5.75k
            p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1166
5.75k
            if (p == (const Quantum *) NULL)
1167
0
              break;
1168
16.2k
            for (x=0; x < (ssize_t) image->columns; x++)
1169
10.4k
            {
1170
10.4k
              *q++=(unsigned char) ((ssize_t) GetPixelIndex(image,p));
1171
10.4k
              p+=(ptrdiff_t) GetPixelChannels(image);
1172
10.4k
            }
1173
5.75k
            if (image->previous == (Image *) NULL)
1174
5.75k
              {
1175
5.75k
                status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1176
5.75k
                image->rows);
1177
5.75k
                if (status == MagickFalse)
1178
0
                  break;
1179
5.75k
              }
1180
5.75k
          }
1181
88
        }
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
329
            for (y=0; y < (ssize_t) image->rows; y++)
1193
303
            {
1194
303
              p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1195
303
              if (p == (const Quantum *) NULL)
1196
0
                break;
1197
303
              bit=0;
1198
303
              byte=0;
1199
3.17k
              for (x=0; x < (ssize_t) image->columns; x++)
1200
2.87k
              {
1201
2.87k
                byte>>=1;
1202
2.87k
                if (GetPixelLuma(image,p) < ((double) QuantumRange/2.0))
1203
2.85k
                  byte|=0x80;
1204
2.87k
                bit++;
1205
2.87k
                if (bit == 8)
1206
343
                  {
1207
343
                    *q++=byte;
1208
343
                    bit=0;
1209
343
                    byte=0;
1210
343
                  }
1211
2.87k
                p+=(ptrdiff_t) GetPixelChannels(image);
1212
2.87k
              }
1213
303
              if (bit != 0)
1214
109
                *q++=byte >> (8-bit);
1215
303
              if (image->previous == (Image *) NULL)
1216
303
                {
1217
303
                  status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1218
303
                    y,image->rows);
1219
303
                  if (status == MagickFalse)
1220
0
                    break;
1221
303
                }
1222
303
            }
1223
26
          }
1224
94
        else
1225
94
          {
1226
            /*
1227
              Convert PseudoClass packet to VIFF grayscale pixel.
1228
            */
1229
5.15k
            for (y=0; y < (ssize_t) image->rows; y++)
1230
5.06k
            {
1231
5.06k
              p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1232
5.06k
              if (p == (const Quantum *) NULL)
1233
0
                break;
1234
21.0k
              for (x=0; x < (ssize_t) image->columns; x++)
1235
15.9k
              {
1236
15.9k
                *q++=(unsigned char) ClampToQuantum(GetPixelLuma(image,p));
1237
15.9k
                p+=(ptrdiff_t) GetPixelChannels(image);
1238
15.9k
              }
1239
5.06k
              if (image->previous == (Image *) NULL)
1240
5.06k
                {
1241
5.06k
                  status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1242
5.06k
                    y,image->rows);
1243
5.06k
                  if (status == MagickFalse)
1244
0
                    break;
1245
5.06k
                }
1246
5.06k
            }
1247
94
          }
1248
488
    (void) WriteBlob(image,(size_t) packets,pixels);
1249
488
    pixel_info=RelinquishVirtualMemory(pixel_info);
1250
488
    if (GetNextImageInList(image) == (Image *) NULL)
1251
488
      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
488
  if (CloseBlob(image) == MagickFalse)
1258
0
    status=MagickFalse;
1259
488
  return(status);
1260
488
}