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