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