]> 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-2012 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    http://www.imagemagick.org/script/license.php                            %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38 \f
39 /*
40   Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/attribute.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/color.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/colormap.h"
50 #include "MagickCore/colorspace.h"
51 #include "MagickCore/colorspace-private.h"
52 #include "MagickCore/exception.h"
53 #include "MagickCore/exception-private.h"
54 #include "MagickCore/image.h"
55 #include "MagickCore/image-private.h"
56 #include "MagickCore/list.h"
57 #include "MagickCore/magick.h"
58 #include "MagickCore/memory_.h"
59 #include "MagickCore/monitor.h"
60 #include "MagickCore/monitor-private.h"
61 #include "MagickCore/pixel-accessor.h"
62 #include "MagickCore/property.h"
63 #include "MagickCore/quantum-private.h"
64 #include "MagickCore/static.h"
65 #include "MagickCore/string_.h"
66 #include "MagickCore/module.h"
67 \f
68 /*
69   Forward declarations.
70 */
71 static MagickBooleanType
72   WriteVIFFImage(const ImageInfo *,Image *,ExceptionInfo *);
73 \f
74 /*
75 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
76 %                                                                             %
77 %                                                                             %
78 %                                                                             %
79 %   I s V I F F                                                               %
80 %                                                                             %
81 %                                                                             %
82 %                                                                             %
83 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
84 %
85 %  IsVIFF() returns MagickTrue if the image format type, identified by the
86 %  magick string, is VIFF.
87 %
88 %  The format of the IsVIFF method is:
89 %
90 %      MagickBooleanType IsVIFF(const unsigned char *magick,const size_t length)
91 %
92 %  A description of each parameter follows:
93 %
94 %    o magick: compare image format pattern against these bytes.
95 %
96 %    o length: Specifies the length of the magick string.
97 %
98 */
99 static MagickBooleanType IsVIFF(const unsigned char *magick,const size_t length)
100 {
101   if (length < 2)
102     return(MagickFalse);
103   if (memcmp(magick,"\253\001",2) == 0)
104     return(MagickTrue);
105   return(MagickFalse);
106 }
107 \f
108 /*
109 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
110 %                                                                             %
111 %                                                                             %
112 %                                                                             %
113 %   R e a d V I F F I m a g e                                                 %
114 %                                                                             %
115 %                                                                             %
116 %                                                                             %
117 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
118 %
119 %  ReadVIFFImage() reads a Khoros Visualization image file and returns
120 %  it.  It allocates the memory necessary for the new Image structure and
121 %  returns a pointer to the new image.
122 %
123 %  The format of the ReadVIFFImage method is:
124 %
125 %      Image *ReadVIFFImage(const ImageInfo *image_info,
126 %        ExceptionInfo *exception)
127 %
128 %  A description of each parameter follows:
129 %
130 %    o image: Method ReadVIFFImage returns a pointer to the image after
131 %      reading.  A null image is returned if there is a memory shortage or if
132 %      the image cannot be read.
133 %
134 %    o image_info: the image info.
135 %
136 %    o exception: return any errors or warnings in this structure.
137 %
138 */
139 static Image *ReadVIFFImage(const ImageInfo *image_info,
140   ExceptionInfo *exception)
141 {
142 #define VFF_CM_genericRGB  15
143 #define VFF_CM_ntscRGB  1
144 #define VFF_CM_NONE  0
145 #define VFF_DEP_DECORDER  0x4
146 #define VFF_DEP_NSORDER  0x8
147 #define VFF_DES_RAW  0
148 #define VFF_LOC_IMPLICIT  1
149 #define VFF_MAPTYP_NONE  0
150 #define VFF_MAPTYP_1_BYTE  1
151 #define VFF_MAPTYP_2_BYTE  2
152 #define VFF_MAPTYP_4_BYTE  4
153 #define VFF_MAPTYP_FLOAT  5
154 #define VFF_MAPTYP_DOUBLE  7
155 #define VFF_MS_NONE  0
156 #define VFF_MS_ONEPERBAND  1
157 #define VFF_MS_SHARED  3
158 #define VFF_TYP_BIT  0
159 #define VFF_TYP_1_BYTE  1
160 #define VFF_TYP_2_BYTE  2
161 #define VFF_TYP_4_BYTE  4
162 #define VFF_TYP_FLOAT  5
163 #define VFF_TYP_DOUBLE  9
164
165   typedef struct _ViffInfo
166   {
167     unsigned char
168       identifier,
169       file_type,
170       release,
171       version,
172       machine_dependency,
173       reserve[3];
174
175     char
176       comment[512];
177
178     unsigned int
179       rows,
180       columns,
181       subrows;
182
183     int
184       x_offset,
185       y_offset;
186
187     float
188       x_bits_per_pixel,
189       y_bits_per_pixel;
190
191     unsigned int
192       location_type,
193       location_dimension,
194       number_of_images,
195       number_data_bands,
196       data_storage_type,
197       data_encode_scheme,
198       map_scheme,
199       map_storage_type,
200       map_rows,
201       map_columns,
202       map_subrows,
203       map_enable,
204       maps_per_cycle,
205       color_space_model;
206   } ViffInfo;
207
208   double
209     min_value,
210     scale_factor,
211     value;
212
213   Image
214     *image;
215
216   int
217     bit;
218
219   MagickBooleanType
220     status;
221
222   MagickSizeType
223     number_pixels;
224
225   register ssize_t
226     x;
227
228   register Quantum
229     *q;
230
231   register ssize_t
232     i;
233
234   register unsigned char
235     *p;
236
237   size_t
238     bytes_per_pixel,
239     lsb_first,
240     max_packets,
241     quantum;
242
243   ssize_t
244     count,
245     y;
246
247   unsigned char
248     buffer[7],
249     *viff_pixels;
250
251   ViffInfo
252     viff_info;
253
254   /*
255     Open image file.
256   */
257   assert(image_info != (const ImageInfo *) NULL);
258   assert(image_info->signature == MagickSignature);
259   if (image_info->debug != MagickFalse)
260     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
261       image_info->filename);
262   assert(exception != (ExceptionInfo *) NULL);
263   assert(exception->signature == MagickSignature);
264   image=AcquireImage(image_info,exception);
265   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
266   if (status == MagickFalse)
267     {
268       image=DestroyImageList(image);
269       return((Image *) NULL);
270     }
271   /*
272     Read VIFF header (1024 bytes).
273   */
274   count=ReadBlob(image,1,&viff_info.identifier);
275   do
276   {
277     /*
278       Verify VIFF identifier.
279     */
280     if ((count == 0) || ((unsigned char) viff_info.identifier != 0xab))
281       ThrowReaderException(CorruptImageError,"NotAVIFFImage");
282     /*
283       Initialize VIFF image.
284     */
285     count=ReadBlob(image,7,buffer);
286     viff_info.file_type=buffer[0];
287     viff_info.release=buffer[1];
288     viff_info.version=buffer[2];
289     viff_info.machine_dependency=buffer[3];
290     count=ReadBlob(image,512,(unsigned char *) viff_info.comment);
291     viff_info.comment[511]='\0';
292     if (strlen(viff_info.comment) > 4)
293       (void) SetImageProperty(image,"comment",viff_info.comment,exception);
294     if ((viff_info.machine_dependency == VFF_DEP_DECORDER) ||
295         (viff_info.machine_dependency == VFF_DEP_NSORDER))
296       {
297         viff_info.rows=ReadBlobLSBLong(image);
298         viff_info.columns=ReadBlobLSBLong(image);
299         viff_info.subrows=ReadBlobLSBLong(image);
300         viff_info.x_offset=(int) ReadBlobLSBLong(image);
301         viff_info.y_offset=(int) ReadBlobLSBLong(image);
302         viff_info.x_bits_per_pixel=(float) ReadBlobLSBLong(image);
303         viff_info.y_bits_per_pixel=(float) ReadBlobLSBLong(image);
304         viff_info.location_type=ReadBlobLSBLong(image);
305         viff_info.location_dimension=ReadBlobLSBLong(image);
306         viff_info.number_of_images=ReadBlobLSBLong(image);
307         viff_info.number_data_bands=ReadBlobLSBLong(image);
308         viff_info.data_storage_type=ReadBlobLSBLong(image);
309         viff_info.data_encode_scheme=ReadBlobLSBLong(image);
310         viff_info.map_scheme=ReadBlobLSBLong(image);
311         viff_info.map_storage_type=ReadBlobLSBLong(image);
312         viff_info.map_rows=ReadBlobLSBLong(image);
313         viff_info.map_columns=ReadBlobLSBLong(image);
314         viff_info.map_subrows=ReadBlobLSBLong(image);
315         viff_info.map_enable=ReadBlobLSBLong(image);
316         viff_info.maps_per_cycle=ReadBlobLSBLong(image);
317         viff_info.color_space_model=ReadBlobLSBLong(image);
318       }
319     else
320       {
321         viff_info.rows=ReadBlobMSBLong(image);
322         viff_info.columns=ReadBlobMSBLong(image);
323         viff_info.subrows=ReadBlobMSBLong(image);
324         viff_info.x_offset=(int) ReadBlobMSBLong(image);
325         viff_info.y_offset=(int) ReadBlobMSBLong(image);
326         viff_info.x_bits_per_pixel=(float) ReadBlobMSBLong(image);
327         viff_info.y_bits_per_pixel=(float) ReadBlobMSBLong(image);
328         viff_info.location_type=ReadBlobMSBLong(image);
329         viff_info.location_dimension=ReadBlobMSBLong(image);
330         viff_info.number_of_images=ReadBlobMSBLong(image);
331         viff_info.number_data_bands=ReadBlobMSBLong(image);
332         viff_info.data_storage_type=ReadBlobMSBLong(image);
333         viff_info.data_encode_scheme=ReadBlobMSBLong(image);
334         viff_info.map_scheme=ReadBlobMSBLong(image);
335         viff_info.map_storage_type=ReadBlobMSBLong(image);
336         viff_info.map_rows=ReadBlobMSBLong(image);
337         viff_info.map_columns=ReadBlobMSBLong(image);
338         viff_info.map_subrows=ReadBlobMSBLong(image);
339         viff_info.map_enable=ReadBlobMSBLong(image);
340         viff_info.maps_per_cycle=ReadBlobMSBLong(image);
341         viff_info.color_space_model=ReadBlobMSBLong(image);
342       }
343     for (i=0; i < 420; i++)
344       (void) ReadBlobByte(image);
345     image->columns=viff_info.rows;
346     image->rows=viff_info.columns;
347     image->depth=viff_info.x_bits_per_pixel <= 8 ? 8UL :
348       MAGICKCORE_QUANTUM_DEPTH;
349     /*
350       Verify that we can read this VIFF image.
351     */
352     number_pixels=(MagickSizeType) viff_info.columns*viff_info.rows;
353     if (number_pixels != (size_t) number_pixels)
354       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
355     if (number_pixels == 0)
356       ThrowReaderException(CoderError,"ImageColumnOrRowSizeIsNotSupported");
357     if ((viff_info.number_data_bands < 1) || (viff_info.number_data_bands > 4))
358       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
359     if ((viff_info.data_storage_type != VFF_TYP_BIT) &&
360         (viff_info.data_storage_type != VFF_TYP_1_BYTE) &&
361         (viff_info.data_storage_type != VFF_TYP_2_BYTE) &&
362         (viff_info.data_storage_type != VFF_TYP_4_BYTE) &&
363         (viff_info.data_storage_type != VFF_TYP_FLOAT) &&
364         (viff_info.data_storage_type != VFF_TYP_DOUBLE))
365       ThrowReaderException(CoderError,"DataStorageTypeIsNotSupported");
366     if (viff_info.data_encode_scheme != VFF_DES_RAW)
367       ThrowReaderException(CoderError,"DataEncodingSchemeIsNotSupported");
368     if ((viff_info.map_storage_type != VFF_MAPTYP_NONE) &&
369         (viff_info.map_storage_type != VFF_MAPTYP_1_BYTE) &&
370         (viff_info.map_storage_type != VFF_MAPTYP_2_BYTE) &&
371         (viff_info.map_storage_type != VFF_MAPTYP_4_BYTE) &&
372         (viff_info.map_storage_type != VFF_MAPTYP_FLOAT) &&
373         (viff_info.map_storage_type != VFF_MAPTYP_DOUBLE))
374       ThrowReaderException(CoderError,"MapStorageTypeIsNotSupported");
375     if ((viff_info.color_space_model != VFF_CM_NONE) &&
376         (viff_info.color_space_model != VFF_CM_ntscRGB) &&
377         (viff_info.color_space_model != VFF_CM_genericRGB))
378       ThrowReaderException(CoderError,"ColorspaceModelIsNotSupported");
379     if (viff_info.location_type != VFF_LOC_IMPLICIT)
380       ThrowReaderException(CoderError,"LocationTypeIsNotSupported");
381     if (viff_info.number_of_images != 1)
382       ThrowReaderException(CoderError,"NumberOfImagesIsNotSupported");
383     if (viff_info.map_rows == 0)
384       viff_info.map_scheme=VFF_MS_NONE;
385     switch ((int) viff_info.map_scheme)
386     {
387       case VFF_MS_NONE:
388       {
389         if (viff_info.number_data_bands < 3)
390           {
391             /*
392               Create linear color ramp.
393             */
394             image->colors=image->depth <= 8 ? 256UL : 65536UL;
395             if (viff_info.data_storage_type == VFF_TYP_BIT)
396               image->colors=2;
397             if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
398               ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
399           }
400         break;
401       }
402       case VFF_MS_ONEPERBAND:
403       case VFF_MS_SHARED:
404       {
405         unsigned char
406           *viff_colormap;
407
408         /*
409           Allocate VIFF colormap.
410         */
411         switch ((int) viff_info.map_storage_type)
412         {
413           case VFF_MAPTYP_1_BYTE: bytes_per_pixel=1; break;
414           case VFF_MAPTYP_2_BYTE: bytes_per_pixel=2; break;
415           case VFF_MAPTYP_4_BYTE: bytes_per_pixel=4; break;
416           case VFF_MAPTYP_FLOAT: bytes_per_pixel=4; break;
417           case VFF_MAPTYP_DOUBLE: bytes_per_pixel=8; break;
418           default: bytes_per_pixel=1; break;
419         }
420         image->colors=viff_info.map_columns;
421         if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
422           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
423         viff_colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
424           viff_info.map_rows*bytes_per_pixel*sizeof(*viff_colormap));
425         if (viff_colormap == (unsigned char *) NULL)
426           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
427         /*
428           Read VIFF raster colormap.
429         */
430         count=ReadBlob(image,bytes_per_pixel*image->colors*viff_info.map_rows,
431           viff_colormap);
432         lsb_first=1;
433         if (*(char *) &lsb_first &&
434             ((viff_info.machine_dependency != VFF_DEP_DECORDER) &&
435              (viff_info.machine_dependency != VFF_DEP_NSORDER)))
436           switch ((int) viff_info.map_storage_type)
437           {
438             case VFF_MAPTYP_2_BYTE:
439             {
440               MSBOrderShort(viff_colormap,(bytes_per_pixel*image->colors*
441                 viff_info.map_rows));
442               break;
443             }
444             case VFF_MAPTYP_4_BYTE:
445             case VFF_MAPTYP_FLOAT:
446             {
447               MSBOrderLong(viff_colormap,(bytes_per_pixel*image->colors*
448                 viff_info.map_rows));
449               break;
450             }
451             default: break;
452           }
453         for (i=0; i < (ssize_t) (viff_info.map_rows*image->colors); i++)
454         {
455           switch ((int) viff_info.map_storage_type)
456           {
457             case VFF_MAPTYP_2_BYTE: value=1.0*((short *) viff_colormap)[i]; break;
458             case VFF_MAPTYP_4_BYTE: value=1.0*((int *) viff_colormap)[i]; break;
459             case VFF_MAPTYP_FLOAT: value=((float *) viff_colormap)[i]; break;
460             case VFF_MAPTYP_DOUBLE: value=((double *) viff_colormap)[i]; break;
461             default: value=1.0*viff_colormap[i]; break;
462           }
463           if (i < (ssize_t) image->colors)
464             {
465               image->colormap[i].red=ScaleCharToQuantum((unsigned char) value);
466               image->colormap[i].green=
467                 ScaleCharToQuantum((unsigned char) value);
468               image->colormap[i].blue=ScaleCharToQuantum((unsigned char) value);
469             }
470           else
471             if (i < (ssize_t) (2*image->colors))
472               image->colormap[i % image->colors].green=
473                 ScaleCharToQuantum((unsigned char) value);
474             else
475               if (i < (ssize_t) (3*image->colors))
476                 image->colormap[i % image->colors].blue=
477                   ScaleCharToQuantum((unsigned char) value);
478         }
479         viff_colormap=(unsigned char *) RelinquishMagickMemory(viff_colormap);
480         break;
481       }
482       default:
483         ThrowReaderException(CoderError,"ColormapTypeNotSupported");
484     }
485     /*
486       Initialize image structure.
487     */
488     image->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,exception);
619         (void) SetImageType(image,PaletteType,exception);
620         for (y=0; y < (ssize_t) image->rows; y++)
621         {
622           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
623           if (q == (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 == (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 == (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,exception);
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,exception);
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,ExceptionInfo *exception)
849 %
850 %  A description of each parameter follows.
851 %
852 %    o image_info: the image info.
853 %
854 %    o image:  The image.
855 %
856 %    o exception: return any errors or warnings in this structure.
857 %
858 */
859
860 static inline size_t MagickMin(const size_t x,const size_t y)
861 {
862   if (x < y)
863     return(x);
864   return(y);
865 }
866
867 static MagickBooleanType WriteVIFFImage(const ImageInfo *image_info,
868   Image *image,ExceptionInfo *exception)
869 {
870 #define VFF_CM_genericRGB  15
871 #define VFF_CM_NONE  0
872 #define VFF_DEP_IEEEORDER  0x2
873 #define VFF_DES_RAW  0
874 #define VFF_LOC_IMPLICIT  1
875 #define VFF_MAPTYP_NONE  0
876 #define VFF_MAPTYP_1_BYTE  1
877 #define VFF_MS_NONE  0
878 #define VFF_MS_ONEPERBAND  1
879 #define VFF_TYP_BIT  0
880 #define VFF_TYP_1_BYTE  1
881
882   typedef struct _ViffInfo
883   {
884     char
885       identifier,
886       file_type,
887       release,
888       version,
889       machine_dependency,
890       reserve[3],
891       comment[512];
892
893     size_t
894       rows,
895       columns,
896       subrows;
897
898     int
899       x_offset,
900       y_offset;
901
902     unsigned int
903       x_bits_per_pixel,
904       y_bits_per_pixel,
905       location_type,
906       location_dimension,
907       number_of_images,
908       number_data_bands,
909       data_storage_type,
910       data_encode_scheme,
911       map_scheme,
912       map_storage_type,
913       map_rows,
914       map_columns,
915       map_subrows,
916       map_enable,
917       maps_per_cycle,
918       color_space_model;
919   } ViffInfo;
920
921   const char
922     *value;
923
924   MagickBooleanType
925     status;
926
927   MagickOffsetType
928     scene;
929
930   MagickSizeType
931     number_pixels,
932     packets;
933
934   register const Quantum
935     *p;
936
937   register ssize_t
938     x;
939
940   register ssize_t
941     i;
942
943   register unsigned char
944     *q;
945
946   ssize_t
947     y;
948
949   unsigned char
950     buffer[8],
951     *viff_pixels;
952
953   ViffInfo
954     viff_info;
955
956   /*
957     Open output image file.
958   */
959   assert(image_info != (const ImageInfo *) NULL);
960   assert(image_info->signature == MagickSignature);
961   assert(image != (Image *) NULL);
962   assert(image->signature == MagickSignature);
963   if (image->debug != MagickFalse)
964     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
965   assert(exception != (ExceptionInfo *) NULL);
966   assert(exception->signature == MagickSignature);
967   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
968   if (status == MagickFalse)
969     return(status);
970   (void) ResetMagickMemory(&viff_info,0,sizeof(ViffInfo));
971   scene=0;
972   do
973   {
974     /*
975       Initialize VIFF image structure.
976     */
977     if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
978       (void) TransformImageColorspace(image,sRGBColorspace,exception);
979     viff_info.identifier=(char) 0xab;
980     viff_info.file_type=1;
981     viff_info.release=1;
982     viff_info.version=3;
983     viff_info.machine_dependency=VFF_DEP_IEEEORDER;  /* IEEE byte ordering */
984     *viff_info.comment='\0';
985     value=GetImageProperty(image,"comment",exception);
986     if (value != (const char *) NULL)
987       (void) CopyMagickString(viff_info.comment,value,MagickMin(strlen(value),
988         511)+1);
989     viff_info.rows=image->columns;
990     viff_info.columns=image->rows;
991     viff_info.subrows=0;
992     viff_info.x_offset=(~0);
993     viff_info.y_offset=(~0);
994     viff_info.x_bits_per_pixel=0;
995     viff_info.y_bits_per_pixel=0;
996     viff_info.location_type=VFF_LOC_IMPLICIT;
997     viff_info.location_dimension=0;
998     viff_info.number_of_images=1;
999     viff_info.data_encode_scheme=VFF_DES_RAW;
1000     viff_info.map_scheme=VFF_MS_NONE;
1001     viff_info.map_storage_type=VFF_MAPTYP_NONE;
1002     viff_info.map_rows=0;
1003     viff_info.map_columns=0;
1004     viff_info.map_subrows=0;
1005     viff_info.map_enable=1;  /* no colormap */
1006     viff_info.maps_per_cycle=0;
1007     number_pixels=(MagickSizeType) image->columns*image->rows;
1008     if (image->storage_class == DirectClass)
1009       {
1010         /*
1011           Full color VIFF raster.
1012         */
1013         viff_info.number_data_bands=image->matte ? 4UL : 3UL;
1014         viff_info.color_space_model=VFF_CM_genericRGB;
1015         viff_info.data_storage_type=VFF_TYP_1_BYTE;
1016         packets=viff_info.number_data_bands*number_pixels;
1017       }
1018     else
1019       {
1020         viff_info.number_data_bands=1;
1021         viff_info.color_space_model=VFF_CM_NONE;
1022         viff_info.data_storage_type=VFF_TYP_1_BYTE;
1023         packets=number_pixels;
1024         if (IsImageGray(image,exception) == MagickFalse)
1025           {
1026             /*
1027               Colormapped VIFF raster.
1028             */
1029             viff_info.map_scheme=VFF_MS_ONEPERBAND;
1030             viff_info.map_storage_type=VFF_MAPTYP_1_BYTE;
1031             viff_info.map_rows=3;
1032             viff_info.map_columns=(unsigned int) image->colors;
1033           }
1034         else
1035           if (image->colors <= 2)
1036             {
1037               /*
1038                 Monochrome VIFF raster.
1039               */
1040               viff_info.data_storage_type=VFF_TYP_BIT;
1041               packets=((image->columns+7) >> 3)*image->rows;
1042             }
1043       }
1044     /*
1045       Write VIFF image header (pad to 1024 bytes).
1046     */
1047     buffer[0]=(unsigned char) viff_info.identifier;
1048     buffer[1]=(unsigned char) viff_info.file_type;
1049     buffer[2]=(unsigned char) viff_info.release;
1050     buffer[3]=(unsigned char) viff_info.version;
1051     buffer[4]=(unsigned char) viff_info.machine_dependency;
1052     buffer[5]=(unsigned char) viff_info.reserve[0];
1053     buffer[6]=(unsigned char) viff_info.reserve[1];
1054     buffer[7]=(unsigned char) viff_info.reserve[2];
1055     (void) WriteBlob(image,8,buffer);
1056     (void) WriteBlob(image,512,(unsigned char *) viff_info.comment);
1057     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.rows);
1058     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.columns);
1059     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.subrows);
1060     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.x_offset);
1061     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.y_offset);
1062     viff_info.x_bits_per_pixel=1U*(63 << 24) | (128 << 16);
1063     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.x_bits_per_pixel);
1064     viff_info.y_bits_per_pixel=1U*(63 << 24) | (128 << 16);
1065     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.y_bits_per_pixel);
1066     (void) WriteBlobMSBLong(image,viff_info.location_type);
1067     (void) WriteBlobMSBLong(image,viff_info.location_dimension);
1068     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.number_of_images);
1069     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.number_data_bands);
1070     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.data_storage_type);
1071     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.data_encode_scheme);
1072     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_scheme);
1073     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_storage_type);
1074     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_rows);
1075     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_columns);
1076     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_subrows);
1077     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_enable);
1078     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.maps_per_cycle);
1079     (void) WriteBlobMSBLong(image,(unsigned int) viff_info.color_space_model);
1080     for (i=0; i < 420; i++)
1081       (void) WriteBlobByte(image,'\0');
1082     /*
1083       Convert MIFF to VIFF raster pixels.
1084     */
1085     viff_pixels=(unsigned char *) AcquireQuantumMemory((size_t) packets,
1086       sizeof(*viff_pixels));
1087     if (viff_pixels == (unsigned char *) NULL)
1088       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1089     q=viff_pixels;
1090     if (image->storage_class == DirectClass)
1091       {
1092         /*
1093           Convert DirectClass packet to VIFF RGB pixel.
1094         */
1095         number_pixels=(MagickSizeType) image->columns*image->rows;
1096         for (y=0; y < (ssize_t) image->rows; y++)
1097         {
1098           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1099           if (p == (const Quantum *) NULL)
1100             break;
1101           for (x=0; x < (ssize_t) image->columns; x++)
1102           {
1103             *q=ScaleQuantumToChar(GetPixelRed(image,p));
1104             *(q+number_pixels)=ScaleQuantumToChar(GetPixelGreen(image,p));
1105             *(q+number_pixels*2)=ScaleQuantumToChar(GetPixelBlue(image,p));
1106             if (image->matte != MagickFalse)
1107               *(q+number_pixels*3)=ScaleQuantumToChar((Quantum)
1108                 (GetPixelAlpha(image,p)));
1109             p+=GetPixelChannels(image);
1110             q++;
1111           }
1112           if (image->previous == (Image *) NULL)
1113             {
1114               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1115                 image->rows);
1116               if (status == MagickFalse)
1117                 break;
1118             }
1119         }
1120       }
1121     else
1122       if (IsImageGray(image,exception) == MagickFalse)
1123         {
1124           unsigned char
1125             *viff_colormap;
1126
1127           /*
1128             Dump colormap to file.
1129           */
1130           viff_colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
1131             3*sizeof(*viff_colormap));
1132           if (viff_colormap == (unsigned char *) NULL)
1133             ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1134           q=viff_colormap;
1135           for (i=0; i < (ssize_t) image->colors; i++)
1136             *q++=ScaleQuantumToChar(image->colormap[i].red);
1137           for (i=0; i < (ssize_t) image->colors; i++)
1138             *q++=ScaleQuantumToChar(image->colormap[i].green);
1139           for (i=0; i < (ssize_t) image->colors; i++)
1140             *q++=ScaleQuantumToChar(image->colormap[i].blue);
1141           (void) WriteBlob(image,3*image->colors,viff_colormap);
1142           viff_colormap=(unsigned char *) RelinquishMagickMemory(viff_colormap);
1143           /*
1144             Convert PseudoClass packet to VIFF colormapped pixels.
1145           */
1146           q=viff_pixels;
1147           for (y=0; y < (ssize_t) image->rows; y++)
1148           {
1149             p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1150             if (p == (const Quantum *) NULL)
1151               break;
1152             for (x=0; x < (ssize_t) image->columns; x++)
1153             {
1154               *q++=(unsigned char) GetPixelIndex(image,p);
1155               p+=GetPixelChannels(image);
1156             }
1157             if (image->previous == (Image *) NULL)
1158               {
1159                 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1160                 image->rows);
1161                 if (status == MagickFalse)
1162                   break;
1163               }
1164           }
1165         }
1166       else
1167         if (image->colors <= 2)
1168           {
1169             ssize_t
1170               x,
1171               y;
1172
1173             register unsigned char
1174               bit,
1175               byte;
1176
1177             /*
1178               Convert PseudoClass image to a VIFF monochrome image.
1179             */
1180             (void) SetImageType(image,BilevelType,exception);
1181             for (y=0; y < (ssize_t) image->rows; y++)
1182             {
1183               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1184               if (p == (const Quantum *) NULL)
1185                 break;
1186               bit=0;
1187               byte=0;
1188               for (x=0; x < (ssize_t) image->columns; x++)
1189               {
1190                 byte>>=1;
1191                 if (GetPixelIntensity(image,p) < ((MagickRealType) QuantumRange/2.0))
1192                   byte|=0x80;
1193                 bit++;
1194                 if (bit == 8)
1195                   {
1196                     *q++=byte;
1197                     bit=0;
1198                     byte=0;
1199                   }
1200                 p+=GetPixelChannels(image);
1201               }
1202               if (bit != 0)
1203                 *q++=byte >> (8-bit);
1204               if (image->previous == (Image *) NULL)
1205                 {
1206                   status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1207                     y,image->rows);
1208                   if (status == MagickFalse)
1209                     break;
1210                 }
1211             }
1212           }
1213         else
1214           {
1215             /*
1216               Convert PseudoClass packet to VIFF grayscale pixel.
1217             */
1218             for (y=0; y < (ssize_t) image->rows; y++)
1219             {
1220               p=GetVirtualPixels(image,0,y,image->columns,1,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 }