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