]> 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-2011 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 *);
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);
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);
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) == 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) == 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->matte=viff_info.number_data_bands == 4 ? MagickTrue : MagickFalse;
489     image->storage_class=
490       (viff_info.number_data_bands < 3 ? PseudoClass : DirectClass);
491     image->columns=viff_info.rows;
492     image->rows=viff_info.columns;
493     if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
494       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
495         break;
496     /*
497       Allocate VIFF pixels.
498     */
499     switch ((int) viff_info.data_storage_type)
500     {
501       case VFF_TYP_2_BYTE: bytes_per_pixel=2; break;
502       case VFF_TYP_4_BYTE: bytes_per_pixel=4; break;
503       case VFF_TYP_FLOAT: bytes_per_pixel=4; break;
504       case VFF_TYP_DOUBLE: bytes_per_pixel=8; break;
505       default: bytes_per_pixel=1; break;
506     }
507     if (viff_info.data_storage_type == VFF_TYP_BIT)
508       max_packets=((image->columns+7UL) >> 3UL)*image->rows;
509     else
510       max_packets=(size_t) (number_pixels*viff_info.number_data_bands);
511     viff_pixels=(unsigned char *) AcquireQuantumMemory(max_packets,
512       bytes_per_pixel*sizeof(*viff_pixels));
513     if (viff_pixels == (unsigned char *) NULL)
514       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
515     count=ReadBlob(image,bytes_per_pixel*max_packets,viff_pixels);
516     lsb_first=1;
517     if (*(char *) &lsb_first &&
518         ((viff_info.machine_dependency != VFF_DEP_DECORDER) &&
519          (viff_info.machine_dependency != VFF_DEP_NSORDER)))
520       switch ((int) viff_info.data_storage_type)
521       {
522         case VFF_TYP_2_BYTE:
523         {
524           MSBOrderShort(viff_pixels,bytes_per_pixel*max_packets);
525           break;
526         }
527         case VFF_TYP_4_BYTE:
528         case VFF_TYP_FLOAT:
529         {
530           MSBOrderLong(viff_pixels,bytes_per_pixel*max_packets);
531           break;
532         }
533         default: break;
534       }
535     min_value=0.0;
536     scale_factor=1.0;
537     if ((viff_info.data_storage_type != VFF_TYP_1_BYTE) &&
538         (viff_info.map_scheme == VFF_MS_NONE))
539       {
540         double
541           max_value;
542
543         /*
544           Determine scale factor.
545         */
546         switch ((int) viff_info.data_storage_type)
547         {
548           case VFF_TYP_2_BYTE: value=1.0*((short *) viff_pixels)[0]; break;
549           case VFF_TYP_4_BYTE: value=1.0*((int *) viff_pixels)[0]; break;
550           case VFF_TYP_FLOAT: value=((float *) viff_pixels)[0]; break;
551           case VFF_TYP_DOUBLE: value=((double *) viff_pixels)[0]; break;
552           default: value=1.0*viff_pixels[0]; break;
553         }
554         max_value=value;
555         min_value=value;
556         for (i=0; i < (ssize_t) max_packets; i++)
557         {
558           switch ((int) viff_info.data_storage_type)
559           {
560             case VFF_TYP_2_BYTE: value=1.0*((short *) viff_pixels)[i]; break;
561             case VFF_TYP_4_BYTE: value=1.0*((int *) viff_pixels)[i]; break;
562             case VFF_TYP_FLOAT: value=((float *) viff_pixels)[i]; break;
563             case VFF_TYP_DOUBLE: value=((double *) viff_pixels)[i]; break;
564             default: value=1.0*viff_pixels[i]; break;
565           }
566           if (value > max_value)
567             max_value=value;
568           else
569             if (value < min_value)
570               min_value=value;
571         }
572         if ((min_value == 0) && (max_value == 0))
573           scale_factor=0;
574         else
575           if (min_value == max_value)
576             {
577               scale_factor=(MagickRealType) QuantumRange/min_value;
578               min_value=0;
579             }
580           else
581             scale_factor=(MagickRealType) QuantumRange/(max_value-min_value);
582       }
583     /*
584       Convert pixels to Quantum size.
585     */
586     p=(unsigned char *) viff_pixels;
587     for (i=0; i < (ssize_t) max_packets; i++)
588     {
589       switch ((int) viff_info.data_storage_type)
590       {
591         case VFF_TYP_2_BYTE: value=1.0*((short *) viff_pixels)[i]; break;
592         case VFF_TYP_4_BYTE: value=1.0*((int *) viff_pixels)[i]; break;
593         case VFF_TYP_FLOAT: value=((float *) viff_pixels)[i]; break;
594         case VFF_TYP_DOUBLE: value=((double *) viff_pixels)[i]; break;
595         default: value=1.0*viff_pixels[i]; break;
596       }
597       if (viff_info.map_scheme == VFF_MS_NONE)
598         {
599           value=(value-min_value)*scale_factor;
600           if (value > QuantumRange)
601             value=QuantumRange;
602           else
603             if (value < 0)
604               value=0;
605         }
606       *p=(unsigned char) value;
607       p++;
608     }
609     /*
610       Convert VIFF raster image to pixel packets.
611     */
612     p=(unsigned char *) viff_pixels;
613     if (viff_info.data_storage_type == VFF_TYP_BIT)
614       {
615         /*
616           Convert bitmap scanline.
617         */
618         (void) SetImageType(image,BilevelType);
619         (void) SetImageType(image,PaletteType);
620         for (y=0; y < (ssize_t) image->rows; y++)
621         {
622           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
623           if (q == (const Quantum *) NULL)
624             break;
625           for (x=0; x < (ssize_t) (image->columns-7); x+=8)
626           {
627             for (bit=0; bit < 8; bit++)
628             {
629               if (GetPixelIntensity(image,q) < ((MagickRealType) QuantumRange/2.0))
630                 {
631                   quantum=(size_t) GetPixelIndex(image,q);
632                   quantum|=0x01;
633                   SetPixelIndex(image,quantum,q);
634                 }
635               q+=GetPixelChannels(image);
636             }
637             p++;
638           }
639           if ((image->columns % 8) != 0)
640             {
641               for (bit=0; bit < (ssize_t) (image->columns % 8); bit++)
642                 if (GetPixelIntensity(image,q) < ((MagickRealType) QuantumRange/2.0))
643                   {
644                     quantum=(size_t) GetPixelIndex(image,q);
645                     quantum|=0x01;
646                     SetPixelIndex(image,quantum,q);
647                     q+=GetPixelChannels(image);
648                   }
649               p++;
650             }
651           if (SyncAuthenticPixels(image,exception) == MagickFalse)
652             break;
653           if (image->previous == (Image *) NULL)
654             {
655               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
656                 image->rows);
657               if (status == MagickFalse)
658                 break;
659             }
660         }
661       }
662     else
663       if (image->storage_class == PseudoClass)
664         for (y=0; y < (ssize_t) image->rows; y++)
665         {
666           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
667           if (q == (const Quantum *) NULL)
668             break;
669           for (x=0; x < (ssize_t) image->columns; x++)
670           {
671             SetPixelIndex(image,*p++,q);
672             q+=GetPixelChannels(image);
673           }
674           if (SyncAuthenticPixels(image,exception) == MagickFalse)
675             break;
676           if (image->previous == (Image *) NULL)
677             {
678               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
679                 image->rows);
680               if (status == MagickFalse)
681                 break;
682             }
683         }
684       else
685         {
686           /*
687             Convert DirectColor scanline.
688           */
689           number_pixels=(MagickSizeType) image->columns*image->rows;
690           for (y=0; y < (ssize_t) image->rows; y++)
691           {
692             q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
693             if (q == (const Quantum *) NULL)
694               break;
695             for (x=0; x < (ssize_t) image->columns; x++)
696             {
697               SetPixelRed(image,ScaleCharToQuantum(*p),q);
698               SetPixelGreen(image,ScaleCharToQuantum(*(p+number_pixels)),q);
699               SetPixelBlue(image,ScaleCharToQuantum(*(p+2*number_pixels)),q);
700               if (image->colors != 0)
701                 {
702                   SetPixelRed(image,image->colormap[(ssize_t)
703                     GetPixelRed(image,q)].red,q);
704                   SetPixelGreen(image,image->colormap[(ssize_t)
705                     GetPixelGreen(image,q)].green,q);
706                   SetPixelBlue(image,image->colormap[(ssize_t)
707                     GetPixelBlue(image,q)].blue,q);
708                 }
709               SetPixelAlpha(image,image->matte != MagickFalse ?
710                 ScaleCharToQuantum(*(p+number_pixels*3)) : OpaqueAlpha,q);
711               p++;
712               q+=GetPixelChannels(image);
713             }
714             if (SyncAuthenticPixels(image,exception) == MagickFalse)
715               break;
716             if (image->previous == (Image *) NULL)
717               {
718                 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
719                 image->rows);
720                 if (status == MagickFalse)
721                   break;
722               }
723           }
724         }
725     viff_pixels=(unsigned char *) RelinquishMagickMemory(viff_pixels);
726     if (image->storage_class == PseudoClass)
727       (void) SyncImage(image);
728     if (EOFBlob(image) != MagickFalse)
729       {
730         ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
731           image->filename);
732         break;
733       }
734     /*
735       Proceed to next image.
736     */
737     if (image_info->number_scenes != 0)
738       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
739         break;
740     count=ReadBlob(image,1,&viff_info.identifier);
741     if ((count != 0) && (viff_info.identifier == 0xab))
742       {
743         /*
744           Allocate next image structure.
745         */
746         AcquireNextImage(image_info,image);
747         if (GetNextImageInList(image) == (Image *) NULL)
748           {
749             image=DestroyImageList(image);
750             return((Image *) NULL);
751           }
752         image=SyncNextImageInList(image);
753         status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
754           GetBlobSize(image));
755         if (status == MagickFalse)
756           break;
757       }
758   } while ((count != 0) && (viff_info.identifier == 0xab));
759   (void) CloseBlob(image);
760   return(GetFirstImageInList(image));
761 }
762 \f
763 /*
764 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
765 %                                                                             %
766 %                                                                             %
767 %                                                                             %
768 %   R e g i s t e r V I F F I m a g e                                         %
769 %                                                                             %
770 %                                                                             %
771 %                                                                             %
772 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
773 %
774 %  RegisterVIFFImage() adds properties for the VIFF image format to
775 %  the list of supported formats.  The properties include the image format
776 %  tag, a method to read and/or write the format, whether the format
777 %  supports the saving of more than one frame to the same file or blob,
778 %  whether the format supports native in-memory I/O, and a brief
779 %  description of the format.
780 %
781 %  The format of the RegisterVIFFImage method is:
782 %
783 %      size_t RegisterVIFFImage(void)
784 %
785 */
786 ModuleExport size_t RegisterVIFFImage(void)
787 {
788   MagickInfo
789     *entry;
790
791   entry=SetMagickInfo("VIFF");
792   entry->decoder=(DecodeImageHandler *) ReadVIFFImage;
793   entry->encoder=(EncodeImageHandler *) WriteVIFFImage;
794   entry->magick=(IsImageFormatHandler *) IsVIFF;
795   entry->description=ConstantString("Khoros Visualization image");
796   entry->module=ConstantString("VIFF");
797   (void) RegisterMagickInfo(entry);
798   entry=SetMagickInfo("XV");
799   entry->decoder=(DecodeImageHandler *) ReadVIFFImage;
800   entry->encoder=(EncodeImageHandler *) WriteVIFFImage;
801   entry->description=ConstantString("Khoros Visualization image");
802   entry->module=ConstantString("VIFF");
803   (void) RegisterMagickInfo(entry);
804   return(MagickImageCoderSignature);
805 }
806 \f
807 /*
808 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
809 %                                                                             %
810 %                                                                             %
811 %                                                                             %
812 %   U n r e g i s t e r V I F F I m a g e                                     %
813 %                                                                             %
814 %                                                                             %
815 %                                                                             %
816 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
817 %
818 %  UnregisterVIFFImage() removes format registrations made by the
819 %  VIFF module from the list of supported formats.
820 %
821 %  The format of the UnregisterVIFFImage method is:
822 %
823 %      UnregisterVIFFImage(void)
824 %
825 */
826 ModuleExport void UnregisterVIFFImage(void)
827 {
828   (void) UnregisterMagickInfo("VIFF");
829   (void) UnregisterMagickInfo("XV");
830 }
831 \f
832 /*
833 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
834 %                                                                             %
835 %                                                                             %
836 %                                                                             %
837 %   W r i t e V I F F I m a g e                                               %
838 %                                                                             %
839 %                                                                             %
840 %                                                                             %
841 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
842 %
843 %  WriteVIFFImage() writes an image to a file in the VIFF image format.
844 %
845 %  The format of the WriteVIFFImage method is:
846 %
847 %      MagickBooleanType WriteVIFFImage(const ImageInfo *image_info,
848 %        Image *image)
849 %
850 %  A description of each parameter follows.
851 %
852 %    o image_info: the image info.
853 %
854 %    o image:  The image.
855 %
856 */
857
858 static inline size_t MagickMin(const size_t x,const size_t y)
859 {
860   if (x < y)
861     return(x);
862   return(y);
863 }
864
865 static MagickBooleanType WriteVIFFImage(const ImageInfo *image_info,
866   Image *image)
867 {
868 #define VFF_CM_genericRGB  15
869 #define VFF_CM_NONE  0
870 #define VFF_DEP_IEEEORDER  0x2
871 #define VFF_DES_RAW  0
872 #define VFF_LOC_IMPLICIT  1
873 #define VFF_MAPTYP_NONE  0
874 #define VFF_MAPTYP_1_BYTE  1
875 #define VFF_MS_NONE  0
876 #define VFF_MS_ONEPERBAND  1
877 #define VFF_TYP_BIT  0
878 #define VFF_TYP_1_BYTE  1
879
880   typedef struct _ViffInfo
881   {
882     char
883       identifier,
884       file_type,
885       release,
886       version,
887       machine_dependency,
888       reserve[3],
889       comment[512];
890
891     size_t
892       rows,
893       columns,
894       subrows;
895
896     int
897       x_offset,
898       y_offset;
899
900     unsigned int
901       x_bits_per_pixel,
902       y_bits_per_pixel,
903       location_type,
904       location_dimension,
905       number_of_images,
906       number_data_bands,
907       data_storage_type,
908       data_encode_scheme,
909       map_scheme,
910       map_storage_type,
911       map_rows,
912       map_columns,
913       map_subrows,
914       map_enable,
915       maps_per_cycle,
916       color_space_model;
917   } ViffInfo;
918
919   const char
920     *value;
921
922   MagickBooleanType
923     status;
924
925   MagickOffsetType
926     scene;
927
928   MagickSizeType
929     number_pixels,
930     packets;
931
932   register const Quantum
933     *p;
934
935   register ssize_t
936     x;
937
938   register ssize_t
939     i;
940
941   register unsigned char
942     *q;
943
944   ssize_t
945     y;
946
947   unsigned char
948     buffer[8],
949     *viff_pixels;
950
951   ViffInfo
952     viff_info;
953
954   /*
955     Open output image file.
956   */
957   assert(image_info != (const ImageInfo *) NULL);
958   assert(image_info->signature == MagickSignature);
959   assert(image != (Image *) NULL);
960   assert(image->signature == MagickSignature);
961   if (image->debug != MagickFalse)
962     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
963   status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
964   if (status == MagickFalse)
965     return(status);
966   (void) ResetMagickMemory(&viff_info,0,sizeof(ViffInfo));
967   scene=0;
968   do
969   {
970     /*
971       Initialize VIFF image structure.
972     */
973     if (IsRGBColorspace(image->colorspace) == MagickFalse)
974       (void) TransformImageColorspace(image,RGBColorspace);
975     if (IsImageGray(image,&image->exception) != MagickFalse)
976       (void) SetImageStorageClass(image,DirectClass);
977     viff_info.identifier=(char) 0xab;
978     viff_info.file_type=1;
979     viff_info.release=1;
980     viff_info.version=3;
981     viff_info.machine_dependency=VFF_DEP_IEEEORDER;  /* IEEE byte ordering */
982     *viff_info.comment='\0';
983     value=GetImageProperty(image,"comment");
984     if (value != (const char *) NULL)
985       (void) CopyMagickString(viff_info.comment,value,MagickMin(strlen(value),
986         511)+1);
987     viff_info.rows=image->columns;
988     viff_info.columns=image->rows;
989     viff_info.subrows=0;
990     viff_info.x_offset=(~0);
991     viff_info.y_offset=(~0);
992     viff_info.x_bits_per_pixel=0;
993     viff_info.y_bits_per_pixel=0;
994     viff_info.location_type=VFF_LOC_IMPLICIT;
995     viff_info.location_dimension=0;
996     viff_info.number_of_images=1;
997     viff_info.data_encode_scheme=VFF_DES_RAW;
998     viff_info.map_scheme=VFF_MS_NONE;
999     viff_info.map_storage_type=VFF_MAPTYP_NONE;
1000     viff_info.map_rows=0;
1001     viff_info.map_columns=0;
1002     viff_info.map_subrows=0;
1003     viff_info.map_enable=1;  /* no colormap */
1004     viff_info.maps_per_cycle=0;
1005     number_pixels=(MagickSizeType) image->columns*image->rows;
1006     if (image->storage_class == DirectClass)
1007       {
1008         /*
1009           Full color VIFF raster.
1010         */
1011         viff_info.number_data_bands=image->matte ? 4UL : 3UL;
1012         viff_info.color_space_model=VFF_CM_genericRGB;
1013         viff_info.data_storage_type=VFF_TYP_1_BYTE;
1014         packets=viff_info.number_data_bands*number_pixels;
1015       }
1016     else
1017       {
1018         viff_info.number_data_bands=1;
1019         viff_info.color_space_model=VFF_CM_NONE;
1020         viff_info.data_storage_type=VFF_TYP_1_BYTE;
1021         packets=number_pixels;
1022         if (IsImageGray(image,&image->exception) == MagickFalse)
1023           {
1024             /*
1025               Colormapped VIFF raster.
1026             */
1027             viff_info.map_scheme=VFF_MS_ONEPERBAND;
1028             viff_info.map_storage_type=VFF_MAPTYP_1_BYTE;
1029             viff_info.map_rows=3;
1030             viff_info.map_columns=(unsigned int) image->colors;
1031           }
1032         else
1033           if (image->colors <= 2)
1034             {
1035               /*
1036                 Monochrome VIFF raster.
1037               */
1038               viff_info.data_storage_type=VFF_TYP_BIT;
1039               packets=((image->columns+7) >> 3)*image->rows;
1040             }
1041       }
1042     /*
1043       Write VIFF image header (pad to 1024 bytes).
1044     */
1045     buffer[0]=(unsigned char) viff_info.identifier;
1046     buffer[1]=(unsigned char) viff_info.file_type;
1047     buffer[2]=(unsigned char) viff_info.release;
1048     buffer[3]=(unsigned char) viff_info.version;
1049     buffer[4]=(unsigned char) viff_info.machine_dependency;
1050     buffer[5]=(unsigned char) viff_info.reserve[0];
1051     buffer[6]=(unsigned char) viff_info.reserve[1];
1052     buffer[7]=(unsigned char) viff_info.reserve[2];
1053     (void) WriteBlob(image,8,buffer);
1054     (void) WriteBlob(image,512,(unsigned char *) viff_info.comment);
1055     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.rows);
1056     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.columns);
1057     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.subrows);
1058     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.x_offset);
1059     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.y_offset);
1060     viff_info.x_bits_per_pixel=1U*(63 << 24) | (128 << 16);
1061     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.x_bits_per_pixel);
1062     viff_info.y_bits_per_pixel=1U*(63 << 24) | (128 << 16);
1063     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.y_bits_per_pixel);
1064     (void) WriteBlobMSBLong(image,viff_info.location_type);
1065     (void) WriteBlobMSBLong(image,viff_info.location_dimension);
1066     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.number_of_images);
1067     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.number_data_bands);
1068     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.data_storage_type);
1069     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.data_encode_scheme);
1070     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_scheme);
1071     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_storage_type);
1072     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_rows);
1073     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_columns);
1074     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_subrows);
1075     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_enable);
1076     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.maps_per_cycle);
1077     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.color_space_model);
1078     for (i=0; i < 420; i++)
1079       (void) WriteBlobByte(image,'\0');
1080     /*
1081       Convert MIFF to VIFF raster pixels.
1082     */
1083     viff_pixels=(unsigned char *) AcquireQuantumMemory((size_t) packets,
1084       sizeof(*viff_pixels));
1085     if (viff_pixels == (unsigned char *) NULL)
1086       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1087     q=viff_pixels;
1088     if (image->storage_class == DirectClass)
1089       {
1090         /*
1091           Convert DirectClass packet to VIFF RGB pixel.
1092         */
1093         number_pixels=(MagickSizeType) image->columns*image->rows;
1094         for (y=0; y < (ssize_t) image->rows; y++)
1095         {
1096           p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1097           if (p == (const Quantum *) NULL)
1098             break;
1099           for (x=0; x < (ssize_t) image->columns; x++)
1100           {
1101             *q=ScaleQuantumToChar(GetPixelRed(image,p));
1102             *(q+number_pixels)=ScaleQuantumToChar(GetPixelGreen(image,p));
1103             *(q+number_pixels*2)=ScaleQuantumToChar(GetPixelBlue(image,p));
1104             if (image->matte != MagickFalse)
1105               *(q+number_pixels*3)=ScaleQuantumToChar((Quantum)
1106                 (GetPixelAlpha(image,p)));
1107             p+=GetPixelChannels(image);
1108             q++;
1109           }
1110           if (image->previous == (Image *) NULL)
1111             {
1112               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1113                 image->rows);
1114               if (status == MagickFalse)
1115                 break;
1116             }
1117         }
1118       }
1119     else
1120       if (IsImageGray(image,&image->exception) == MagickFalse)
1121         {
1122           unsigned char
1123             *viff_colormap;
1124
1125           /*
1126             Dump colormap to file.
1127           */
1128           viff_colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
1129             3*sizeof(*viff_colormap));
1130           if (viff_colormap == (unsigned char *) NULL)
1131             ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1132           q=viff_colormap;
1133           for (i=0; i < (ssize_t) image->colors; i++)
1134             *q++=ScaleQuantumToChar(image->colormap[i].red);
1135           for (i=0; i < (ssize_t) image->colors; i++)
1136             *q++=ScaleQuantumToChar(image->colormap[i].green);
1137           for (i=0; i < (ssize_t) image->colors; i++)
1138             *q++=ScaleQuantumToChar(image->colormap[i].blue);
1139           (void) WriteBlob(image,3*image->colors,viff_colormap);
1140           viff_colormap=(unsigned char *) RelinquishMagickMemory(viff_colormap);
1141           /*
1142             Convert PseudoClass packet to VIFF colormapped pixels.
1143           */
1144           q=viff_pixels;
1145           for (y=0; y < (ssize_t) image->rows; y++)
1146           {
1147             p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1148             if (p == (const Quantum *) NULL)
1149               break;
1150             for (x=0; x < (ssize_t) image->columns; x++)
1151             {
1152               *q++=(unsigned char) GetPixelIndex(image,p);
1153               p+=GetPixelChannels(image);
1154             }
1155             if (image->previous == (Image *) NULL)
1156               {
1157                 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1158                 image->rows);
1159                 if (status == MagickFalse)
1160                   break;
1161               }
1162           }
1163         }
1164       else
1165         if (image->colors <= 2)
1166           {
1167             ssize_t
1168               x,
1169               y;
1170
1171             register unsigned char
1172               bit,
1173               byte;
1174
1175             /*
1176               Convert PseudoClass image to a VIFF monochrome image.
1177             */
1178             (void) SetImageType(image,BilevelType);
1179             for (y=0; y < (ssize_t) image->rows; y++)
1180             {
1181               p=GetVirtualPixels(image,0,y,image->columns,1,
1182                 &image->exception);
1183               if (p == (const Quantum *) NULL)
1184                 break;
1185               bit=0;
1186               byte=0;
1187               for (x=0; x < (ssize_t) image->columns; x++)
1188               {
1189                 byte>>=1;
1190                 if (GetPixelIntensity(image,p) < ((MagickRealType) QuantumRange/2.0))
1191                   byte|=0x80;
1192                 bit++;
1193                 if (bit == 8)
1194                   {
1195                     *q++=byte;
1196                     bit=0;
1197                     byte=0;
1198                   }
1199                 p+=GetPixelChannels(image);
1200               }
1201               if (bit != 0)
1202                 *q++=byte >> (8-bit);
1203               if (image->previous == (Image *) NULL)
1204                 {
1205                   status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1206                     y,image->rows);
1207                   if (status == MagickFalse)
1208                     break;
1209                 }
1210             }
1211           }
1212         else
1213           {
1214             /*
1215               Convert PseudoClass packet to VIFF grayscale pixel.
1216             */
1217             for (y=0; y < (ssize_t) image->rows; y++)
1218             {
1219               p=GetVirtualPixels(image,0,y,image->columns,1,
1220                 &image->exception);
1221               if (p == (const Quantum *) NULL)
1222                 break;
1223               for (x=0; x < (ssize_t) image->columns; x++)
1224               {
1225                 *q++=(unsigned char) GetPixelIntensity(image,p);
1226                 p+=GetPixelChannels(image);
1227               }
1228               if (image->previous == (Image *) NULL)
1229                 {
1230                   status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1231                     y,image->rows);
1232                   if (status == MagickFalse)
1233                     break;
1234                 }
1235             }
1236           }
1237     (void) WriteBlob(image,(size_t) packets,viff_pixels);
1238     viff_pixels=(unsigned char *) RelinquishMagickMemory(viff_pixels);
1239     if (GetNextImageInList(image) == (Image *) NULL)
1240       break;
1241     image=SyncNextImageInList(image);
1242     status=SetImageProgress(image,SaveImagesTag,scene++,
1243       GetImageListLength(image));
1244     if (status == MagickFalse)
1245       break;
1246   } while (image_info->adjoin != MagickFalse);
1247   (void) CloseBlob(image);
1248   return(MagickTrue);
1249 }