]> granicus.if.org Git - imagemagick/blob - coders/viff.c
Horizon validity (anti-aliased) added to Plane2Cylinder
[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 "magick/studio.h"
43 #include "magick/blob.h"
44 #include "magick/blob-private.h"
45 #include "magick/cache.h"
46 #include "magick/color.h"
47 #include "magick/color-private.h"
48 #include "magick/colormap.h"
49 #include "magick/colorspace.h"
50 #include "magick/exception.h"
51 #include "magick/exception-private.h"
52 #include "magick/image.h"
53 #include "magick/image-private.h"
54 #include "magick/list.h"
55 #include "magick/magick.h"
56 #include "magick/memory_.h"
57 #include "magick/monitor.h"
58 #include "magick/monitor-private.h"
59 #include "magick/property.h"
60 #include "magick/quantum-private.h"
61 #include "magick/static.h"
62 #include "magick/string_.h"
63 #include "magick/module.h"
64 \f
65 /*
66   Forward declarations.
67 */
68 static MagickBooleanType
69   WriteVIFFImage(const ImageInfo *,Image *);
70 \f
71 /*
72 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
73 %                                                                             %
74 %                                                                             %
75 %                                                                             %
76 %   I s V I F F                                                               %
77 %                                                                             %
78 %                                                                             %
79 %                                                                             %
80 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
81 %
82 %  IsVIFF() returns MagickTrue if the image format type, identified by the
83 %  magick string, is VIFF.
84 %
85 %  The format of the IsVIFF method is:
86 %
87 %      MagickBooleanType IsVIFF(const unsigned char *magick,const size_t length)
88 %
89 %  A description of each parameter follows:
90 %
91 %    o magick: compare image format pattern against these bytes.
92 %
93 %    o length: Specifies the length of the magick string.
94 %
95 */
96 static MagickBooleanType IsVIFF(const unsigned char *magick,const size_t length)
97 {
98   if (length < 2)
99     return(MagickFalse);
100   if (memcmp(magick,"\253\001",2) == 0)
101     return(MagickTrue);
102   return(MagickFalse);
103 }
104 \f
105 /*
106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
107 %                                                                             %
108 %                                                                             %
109 %                                                                             %
110 %   R e a d V I F F I m a g e                                                 %
111 %                                                                             %
112 %                                                                             %
113 %                                                                             %
114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
115 %
116 %  ReadVIFFImage() reads a Khoros Visualization image file and returns
117 %  it.  It allocates the memory necessary for the new Image structure and
118 %  returns a pointer to the new image.
119 %
120 %  The format of the ReadVIFFImage method is:
121 %
122 %      Image *ReadVIFFImage(const ImageInfo *image_info,
123 %        ExceptionInfo *exception)
124 %
125 %  A description of each parameter follows:
126 %
127 %    o image: Method ReadVIFFImage returns a pointer to the image after
128 %      reading.  A null image is returned if there is a memory shortage or if
129 %      the image cannot be read.
130 %
131 %    o image_info: the image info.
132 %
133 %    o exception: return any errors or warnings in this structure.
134 %
135 */
136 static Image *ReadVIFFImage(const ImageInfo *image_info,
137   ExceptionInfo *exception)
138 {
139 #define VFF_CM_genericRGB  15
140 #define VFF_CM_ntscRGB  1
141 #define VFF_CM_NONE  0
142 #define VFF_DEP_DECORDER  0x4
143 #define VFF_DEP_NSORDER  0x8
144 #define VFF_DES_RAW  0
145 #define VFF_LOC_IMPLICIT  1
146 #define VFF_MAPTYP_NONE  0
147 #define VFF_MAPTYP_1_BYTE  1
148 #define VFF_MAPTYP_2_BYTE  2
149 #define VFF_MAPTYP_4_BYTE  4
150 #define VFF_MAPTYP_FLOAT  5
151 #define VFF_MAPTYP_DOUBLE  7
152 #define VFF_MS_NONE  0
153 #define VFF_MS_ONEPERBAND  1
154 #define VFF_MS_SHARED  3
155 #define VFF_TYP_BIT  0
156 #define VFF_TYP_1_BYTE  1
157 #define VFF_TYP_2_BYTE  2
158 #define VFF_TYP_4_BYTE  4
159 #define VFF_TYP_FLOAT  5
160 #define VFF_TYP_DOUBLE  9
161
162   typedef struct _ViffInfo
163   {
164     unsigned char
165       identifier,
166       file_type,
167       release,
168       version,
169       machine_dependency,
170       reserve[3];
171
172     char
173       comment[512];
174
175     unsigned int
176       rows,
177       columns,
178       subrows;
179
180     int
181       x_offset,
182       y_offset;
183
184     float
185       x_bits_per_pixel,
186       y_bits_per_pixel;
187
188     unsigned int
189       location_type,
190       location_dimension,
191       number_of_images,
192       number_data_bands,
193       data_storage_type,
194       data_encode_scheme,
195       map_scheme,
196       map_storage_type,
197       map_rows,
198       map_columns,
199       map_subrows,
200       map_enable,
201       maps_per_cycle,
202       color_space_model;
203   } ViffInfo;
204
205   double
206     min_value,
207     scale_factor,
208     value;
209
210   Image
211     *image;
212
213   int
214     bit;
215
216   MagickBooleanType
217     status;
218
219   MagickSizeType
220     number_pixels;
221
222   register IndexPacket
223     *indexes;
224
225   register ssize_t
226     x;
227
228   register PixelPacket
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 == (PixelPacket *) NULL)
624             break;
625           indexes=GetAuthenticIndexQueue(image);
626           for (x=0; x < (ssize_t) (image->columns-7); x+=8)
627           {
628             for (bit=0; bit < 8; bit++)
629               if (PixelIntensity(q) < ((MagickRealType) QuantumRange/2.0))
630                 {
631                   quantum=(size_t) GetIndexPixelComponent(indexes+x+bit);
632                   quantum|=0x01;
633                   SetIndexPixelComponent(indexes+x+bit,quantum);
634                 }
635             p++;
636           }
637           if ((image->columns % 8) != 0)
638             {
639               for (bit=0; bit < (ssize_t) (image->columns % 8); bit++)
640                 if (PixelIntensity(q) < ((MagickRealType) QuantumRange/2.0))
641                   {
642                     quantum=(size_t) GetIndexPixelComponent(indexes+x+bit);
643                     quantum|=0x01;
644                     SetIndexPixelComponent(indexes+x+bit,quantum);
645                   }
646               p++;
647             }
648           if (SyncAuthenticPixels(image,exception) == MagickFalse)
649             break;
650           if (image->previous == (Image *) NULL)
651             {
652               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
653                 image->rows);
654               if (status == MagickFalse)
655                 break;
656             }
657         }
658       }
659     else
660       if (image->storage_class == PseudoClass)
661         for (y=0; y < (ssize_t) image->rows; y++)
662         {
663           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
664           if (q == (PixelPacket *) NULL)
665             break;
666           indexes=GetAuthenticIndexQueue(image);
667           for (x=0; x < (ssize_t) image->columns; x++)
668             SetIndexPixelComponent(indexes+x,*p++);
669           if (SyncAuthenticPixels(image,exception) == MagickFalse)
670             break;
671           if (image->previous == (Image *) NULL)
672             {
673               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
674                 image->rows);
675               if (status == MagickFalse)
676                 break;
677             }
678         }
679       else
680         {
681           /*
682             Convert DirectColor scanline.
683           */
684           number_pixels=(MagickSizeType) image->columns*image->rows;
685           for (y=0; y < (ssize_t) image->rows; y++)
686           {
687             q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
688             if (q == (PixelPacket *) NULL)
689               break;
690             for (x=0; x < (ssize_t) image->columns; x++)
691             {
692               SetRedPixelComponent(q,ScaleCharToQuantum(*p));
693               SetGreenPixelComponent(q,ScaleCharToQuantum(*(p+number_pixels)));
694               SetBluePixelComponent(q,ScaleCharToQuantum(*(p+2*number_pixels)));
695               if (image->colors != 0)
696                 {
697                   SetRedPixelComponent(q,image->colormap[(ssize_t)
698                     GetRedPixelComponent(q)].red);
699                   SetGreenPixelComponent(q,image->colormap[(ssize_t)
700                     GetGreenPixelComponent(q)].green);
701                   SetBluePixelComponent(q,image->colormap[(ssize_t)
702                     GetBluePixelComponent(q)].blue);
703                 }
704               SetOpacityPixelComponent(q,image->matte != MagickFalse ?
705                 QuantumRange-ScaleCharToQuantum(*(p+number_pixels*3)) :
706                 OpaqueOpacity);
707               p++;
708               q++;
709             }
710             if (SyncAuthenticPixels(image,exception) == MagickFalse)
711               break;
712             if (image->previous == (Image *) NULL)
713               {
714                 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
715                 image->rows);
716                 if (status == MagickFalse)
717                   break;
718               }
719           }
720         }
721     viff_pixels=(unsigned char *) RelinquishMagickMemory(viff_pixels);
722     if (image->storage_class == PseudoClass)
723       (void) SyncImage(image);
724     if (EOFBlob(image) != MagickFalse)
725       {
726         ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
727           image->filename);
728         break;
729       }
730     /*
731       Proceed to next image.
732     */
733     if (image_info->number_scenes != 0)
734       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
735         break;
736     count=ReadBlob(image,1,&viff_info.identifier);
737     if ((count != 0) && (viff_info.identifier == 0xab))
738       {
739         /*
740           Allocate next image structure.
741         */
742         AcquireNextImage(image_info,image);
743         if (GetNextImageInList(image) == (Image *) NULL)
744           {
745             image=DestroyImageList(image);
746             return((Image *) NULL);
747           }
748         image=SyncNextImageInList(image);
749         status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
750           GetBlobSize(image));
751         if (status == MagickFalse)
752           break;
753       }
754   } while ((count != 0) && (viff_info.identifier == 0xab));
755   (void) CloseBlob(image);
756   return(GetFirstImageInList(image));
757 }
758 \f
759 /*
760 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
761 %                                                                             %
762 %                                                                             %
763 %                                                                             %
764 %   R e g i s t e r V I F F I m a g e                                         %
765 %                                                                             %
766 %                                                                             %
767 %                                                                             %
768 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
769 %
770 %  RegisterVIFFImage() adds properties for the VIFF image format to
771 %  the list of supported formats.  The properties include the image format
772 %  tag, a method to read and/or write the format, whether the format
773 %  supports the saving of more than one frame to the same file or blob,
774 %  whether the format supports native in-memory I/O, and a brief
775 %  description of the format.
776 %
777 %  The format of the RegisterVIFFImage method is:
778 %
779 %      size_t RegisterVIFFImage(void)
780 %
781 */
782 ModuleExport size_t RegisterVIFFImage(void)
783 {
784   MagickInfo
785     *entry;
786
787   entry=SetMagickInfo("VIFF");
788   entry->decoder=(DecodeImageHandler *) ReadVIFFImage;
789   entry->encoder=(EncodeImageHandler *) WriteVIFFImage;
790   entry->magick=(IsImageFormatHandler *) IsVIFF;
791   entry->description=ConstantString("Khoros Visualization image");
792   entry->module=ConstantString("VIFF");
793   (void) RegisterMagickInfo(entry);
794   entry=SetMagickInfo("XV");
795   entry->decoder=(DecodeImageHandler *) ReadVIFFImage;
796   entry->encoder=(EncodeImageHandler *) WriteVIFFImage;
797   entry->description=ConstantString("Khoros Visualization image");
798   entry->module=ConstantString("VIFF");
799   (void) RegisterMagickInfo(entry);
800   return(MagickImageCoderSignature);
801 }
802 \f
803 /*
804 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
805 %                                                                             %
806 %                                                                             %
807 %                                                                             %
808 %   U n r e g i s t e r V I F F I m a g e                                     %
809 %                                                                             %
810 %                                                                             %
811 %                                                                             %
812 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
813 %
814 %  UnregisterVIFFImage() removes format registrations made by the
815 %  VIFF module from the list of supported formats.
816 %
817 %  The format of the UnregisterVIFFImage method is:
818 %
819 %      UnregisterVIFFImage(void)
820 %
821 */
822 ModuleExport void UnregisterVIFFImage(void)
823 {
824   (void) UnregisterMagickInfo("VIFF");
825   (void) UnregisterMagickInfo("XV");
826 }
827 \f
828 /*
829 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
830 %                                                                             %
831 %                                                                             %
832 %                                                                             %
833 %   W r i t e V I F F I m a g e                                               %
834 %                                                                             %
835 %                                                                             %
836 %                                                                             %
837 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
838 %
839 %  WriteVIFFImage() writes an image to a file in the VIFF image format.
840 %
841 %  The format of the WriteVIFFImage method is:
842 %
843 %      MagickBooleanType WriteVIFFImage(const ImageInfo *image_info,
844 %        Image *image)
845 %
846 %  A description of each parameter follows.
847 %
848 %    o image_info: the image info.
849 %
850 %    o image:  The image.
851 %
852 */
853
854 static inline size_t MagickMin(const size_t x,const size_t y)
855 {
856   if (x < y)
857     return(x);
858   return(y);
859 }
860
861 static MagickBooleanType WriteVIFFImage(const ImageInfo *image_info,
862   Image *image)
863 {
864 #define VFF_CM_genericRGB  15
865 #define VFF_CM_NONE  0
866 #define VFF_DEP_IEEEORDER  0x2
867 #define VFF_DES_RAW  0
868 #define VFF_LOC_IMPLICIT  1
869 #define VFF_MAPTYP_NONE  0
870 #define VFF_MAPTYP_1_BYTE  1
871 #define VFF_MS_NONE  0
872 #define VFF_MS_ONEPERBAND  1
873 #define VFF_TYP_BIT  0
874 #define VFF_TYP_1_BYTE  1
875
876   typedef struct _ViffInfo
877   {
878     char
879       identifier,
880       file_type,
881       release,
882       version,
883       machine_dependency,
884       reserve[3],
885       comment[512];
886
887     size_t
888       rows,
889       columns,
890       subrows;
891
892     int
893       x_offset,
894       y_offset;
895
896     unsigned int
897       x_bits_per_pixel,
898       y_bits_per_pixel,
899       location_type,
900       location_dimension,
901       number_of_images,
902       number_data_bands,
903       data_storage_type,
904       data_encode_scheme,
905       map_scheme,
906       map_storage_type,
907       map_rows,
908       map_columns,
909       map_subrows,
910       map_enable,
911       maps_per_cycle,
912       color_space_model;
913   } ViffInfo;
914
915   const char
916     *value;
917
918   MagickBooleanType
919     status;
920
921   MagickOffsetType
922     scene;
923
924   MagickSizeType
925     number_pixels,
926     packets;
927
928   register const IndexPacket
929     *indexes;
930
931   register const PixelPacket
932     *p;
933
934   register ssize_t
935     x;
936
937   register ssize_t
938     i;
939
940   register unsigned char
941     *q;
942
943   ssize_t
944     y;
945
946   unsigned char
947     buffer[8],
948     *viff_pixels;
949
950   ViffInfo
951     viff_info;
952
953   /*
954     Open output image file.
955   */
956   assert(image_info != (const ImageInfo *) NULL);
957   assert(image_info->signature == MagickSignature);
958   assert(image != (Image *) NULL);
959   assert(image->signature == MagickSignature);
960   if (image->debug != MagickFalse)
961     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
962   status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
963   if (status == MagickFalse)
964     return(status);
965   (void) ResetMagickMemory(&viff_info,0,sizeof(ViffInfo));
966   scene=0;
967   do
968   {
969     /*
970       Initialize VIFF image structure.
971     */
972     if (image->colorspace != RGBColorspace)
973       (void) TransformImageColorspace(image,RGBColorspace);
974     if (IsGrayImage(image,&image->exception) != MagickFalse)
975       (void) SetImageStorageClass(image,DirectClass);
976     viff_info.identifier=(char) 0xab;
977     viff_info.file_type=1;
978     viff_info.release=1;
979     viff_info.version=3;
980     viff_info.machine_dependency=VFF_DEP_IEEEORDER;  /* IEEE byte ordering */
981     *viff_info.comment='\0';
982     value=GetImageProperty(image,"comment");
983     if (value != (const char *) NULL)
984       (void) CopyMagickString(viff_info.comment,value,MagickMin(strlen(value),
985         511)+1);
986     viff_info.rows=image->columns;
987     viff_info.columns=image->rows;
988     viff_info.subrows=0;
989     viff_info.x_offset=(~0);
990     viff_info.y_offset=(~0);
991     viff_info.x_bits_per_pixel=0;
992     viff_info.y_bits_per_pixel=0;
993     viff_info.location_type=VFF_LOC_IMPLICIT;
994     viff_info.location_dimension=0;
995     viff_info.number_of_images=1;
996     viff_info.data_encode_scheme=VFF_DES_RAW;
997     viff_info.map_scheme=VFF_MS_NONE;
998     viff_info.map_storage_type=VFF_MAPTYP_NONE;
999     viff_info.map_rows=0;
1000     viff_info.map_columns=0;
1001     viff_info.map_subrows=0;
1002     viff_info.map_enable=1;  /* no colormap */
1003     viff_info.maps_per_cycle=0;
1004     number_pixels=(MagickSizeType) image->columns*image->rows;
1005     if (image->storage_class == DirectClass)
1006       {
1007         /*
1008           Full color VIFF raster.
1009         */
1010         viff_info.number_data_bands=image->matte ? 4UL : 3UL;
1011         viff_info.color_space_model=VFF_CM_genericRGB;
1012         viff_info.data_storage_type=VFF_TYP_1_BYTE;
1013         packets=viff_info.number_data_bands*number_pixels;
1014       }
1015     else
1016       {
1017         viff_info.number_data_bands=1;
1018         viff_info.color_space_model=VFF_CM_NONE;
1019         viff_info.data_storage_type=VFF_TYP_1_BYTE;
1020         packets=number_pixels;
1021         if (IsGrayImage(image,&image->exception) == MagickFalse)
1022           {
1023             /*
1024               Colormapped VIFF raster.
1025             */
1026             viff_info.map_scheme=VFF_MS_ONEPERBAND;
1027             viff_info.map_storage_type=VFF_MAPTYP_1_BYTE;
1028             viff_info.map_rows=3;
1029             viff_info.map_columns=(unsigned int) image->colors;
1030           }
1031         else
1032           if (image->colors <= 2)
1033             {
1034               /*
1035                 Monochrome VIFF raster.
1036               */
1037               viff_info.data_storage_type=VFF_TYP_BIT;
1038               packets=((image->columns+7) >> 3)*image->rows;
1039             }
1040       }
1041     /*
1042       Write VIFF image header (pad to 1024 bytes).
1043     */
1044     buffer[0]=(unsigned char) viff_info.identifier;
1045     buffer[1]=(unsigned char) viff_info.file_type;
1046     buffer[2]=(unsigned char) viff_info.release;
1047     buffer[3]=(unsigned char) viff_info.version;
1048     buffer[4]=(unsigned char) viff_info.machine_dependency;
1049     buffer[5]=(unsigned char) viff_info.reserve[0];
1050     buffer[6]=(unsigned char) viff_info.reserve[1];
1051     buffer[7]=(unsigned char) viff_info.reserve[2];
1052     (void) WriteBlob(image,8,buffer);
1053     (void) WriteBlob(image,512,(unsigned char *) viff_info.comment);
1054     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.rows);
1055     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.columns);
1056     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.subrows);
1057     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.x_offset);
1058     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.y_offset);
1059     viff_info.x_bits_per_pixel=1U*(63 << 24) | (128 << 16);
1060     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.x_bits_per_pixel);
1061     viff_info.y_bits_per_pixel=1U*(63 << 24) | (128 << 16);
1062     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.y_bits_per_pixel);
1063     (void) WriteBlobMSBLong(image,viff_info.location_type);
1064     (void) WriteBlobMSBLong(image,viff_info.location_dimension);
1065     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.number_of_images);
1066     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.number_data_bands);
1067     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.data_storage_type);
1068     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.data_encode_scheme);
1069     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_scheme);
1070     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_storage_type);
1071     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_rows);
1072     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_columns);
1073     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_subrows);
1074     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_enable);
1075     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.maps_per_cycle);
1076     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.color_space_model);
1077     for (i=0; i < 420; i++)
1078       (void) WriteBlobByte(image,'\0');
1079     /*
1080       Convert MIFF to VIFF raster pixels.
1081     */
1082     viff_pixels=(unsigned char *) AcquireQuantumMemory((size_t) packets,
1083       sizeof(*viff_pixels));
1084     if (viff_pixels == (unsigned char *) NULL)
1085       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1086     q=viff_pixels;
1087     if (image->storage_class == DirectClass)
1088       {
1089         /*
1090           Convert DirectClass packet to VIFF RGB pixel.
1091         */
1092         number_pixels=(MagickSizeType) image->columns*image->rows;
1093         for (y=0; y < (ssize_t) image->rows; y++)
1094         {
1095           p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1096           if (p == (const PixelPacket *) NULL)
1097             break;
1098           for (x=0; x < (ssize_t) image->columns; x++)
1099           {
1100             *q=ScaleQuantumToChar(GetRedPixelComponent(p));
1101             *(q+number_pixels)=ScaleQuantumToChar(GetGreenPixelComponent(p));
1102             *(q+number_pixels*2)=ScaleQuantumToChar(GetBluePixelComponent(p));
1103             if (image->matte != MagickFalse)
1104               *(q+number_pixels*3)=ScaleQuantumToChar((Quantum)
1105                 (GetAlphaPixelComponent(p)));
1106             p++;
1107             q++;
1108           }
1109           if (image->previous == (Image *) NULL)
1110             {
1111               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1112                 image->rows);
1113               if (status == MagickFalse)
1114                 break;
1115             }
1116         }
1117       }
1118     else
1119       if (IsGrayImage(image,&image->exception) == MagickFalse)
1120         {
1121           unsigned char
1122             *viff_colormap;
1123
1124           /*
1125             Dump colormap to file.
1126           */
1127           viff_colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
1128             3*sizeof(*viff_colormap));
1129           if (viff_colormap == (unsigned char *) NULL)
1130             ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1131           q=viff_colormap;
1132           for (i=0; i < (ssize_t) image->colors; i++)
1133             *q++=ScaleQuantumToChar(image->colormap[i].red);
1134           for (i=0; i < (ssize_t) image->colors; i++)
1135             *q++=ScaleQuantumToChar(image->colormap[i].green);
1136           for (i=0; i < (ssize_t) image->colors; i++)
1137             *q++=ScaleQuantumToChar(image->colormap[i].blue);
1138           (void) WriteBlob(image,3*image->colors,viff_colormap);
1139           viff_colormap=(unsigned char *) RelinquishMagickMemory(viff_colormap);
1140           /*
1141             Convert PseudoClass packet to VIFF colormapped pixels.
1142           */
1143           q=viff_pixels;
1144           for (y=0; y < (ssize_t) image->rows; y++)
1145           {
1146             p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1147             if (p == (const PixelPacket *) NULL)
1148               break;
1149             indexes=GetVirtualIndexQueue(image);
1150             for (x=0; x < (ssize_t) image->columns; x++)
1151               *q++=(unsigned char) GetIndexPixelComponent(indexes+x);
1152             if (image->previous == (Image *) NULL)
1153               {
1154                 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1155                 image->rows);
1156                 if (status == MagickFalse)
1157                   break;
1158               }
1159           }
1160         }
1161       else
1162         if (image->colors <= 2)
1163           {
1164             ssize_t
1165               x,
1166               y;
1167
1168             register unsigned char
1169               bit,
1170               byte;
1171
1172             /*
1173               Convert PseudoClass image to a VIFF monochrome image.
1174             */
1175             (void) SetImageType(image,BilevelType);
1176             for (y=0; y < (ssize_t) image->rows; y++)
1177             {
1178               p=GetVirtualPixels(image,0,y,image->columns,1,
1179                 &image->exception);
1180               if (p == (const PixelPacket *) NULL)
1181                 break;
1182               indexes=GetVirtualIndexQueue(image);
1183               bit=0;
1184               byte=0;
1185               for (x=0; x < (ssize_t) image->columns; x++)
1186               {
1187                 byte>>=1;
1188                 if (PixelIntensity(p) < ((MagickRealType) QuantumRange/2.0))
1189                   byte|=0x80;
1190                 bit++;
1191                 if (bit == 8)
1192                   {
1193                     *q++=byte;
1194                     bit=0;
1195                     byte=0;
1196                   }
1197               }
1198               if (bit != 0)
1199                 *q++=byte >> (8-bit);
1200               if (image->previous == (Image *) NULL)
1201                 {
1202                   status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1203                     y,image->rows);
1204                   if (status == MagickFalse)
1205                     break;
1206                 }
1207             }
1208           }
1209         else
1210           {
1211             /*
1212               Convert PseudoClass packet to VIFF grayscale pixel.
1213             */
1214             for (y=0; y < (ssize_t) image->rows; y++)
1215             {
1216               p=GetVirtualPixels(image,0,y,image->columns,1,
1217                 &image->exception);
1218               if (p == (const PixelPacket *) NULL)
1219                 break;
1220               for (x=0; x < (ssize_t) image->columns; x++)
1221               {
1222                 *q++=(unsigned char) PixelIntensityToQuantum(p);
1223                 p++;
1224               }
1225               if (image->previous == (Image *) NULL)
1226                 {
1227                   status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1228                     y,image->rows);
1229                   if (status == MagickFalse)
1230                     break;
1231                 }
1232             }
1233           }
1234     (void) WriteBlob(image,(size_t) packets,viff_pixels);
1235     viff_pixels=(unsigned char *) RelinquishMagickMemory(viff_pixels);
1236     if (GetNextImageInList(image) == (Image *) NULL)
1237       break;
1238     image=SyncNextImageInList(image);
1239     status=SetImageProgress(image,SaveImagesTag,scene++,
1240       GetImageListLength(image));
1241     if (status == MagickFalse)
1242       break;
1243   } while (image_info->adjoin != MagickFalse);
1244   (void) CloseBlob(image);
1245   return(MagickTrue);
1246 }