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