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