blob: 0904294cf91cef7eabbb3c387b9219b29c9b3ad7 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
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 %
cristyde984cd2013-12-01 14:49:27 +000016% Cristy %
cristy3ed852e2009-09-05 21:47:34 +000017% July 1992 %
18% %
19% %
cristyb56bb242014-11-25 17:12:48 +000020% Copyright 1999-2015 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% 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
39/*
40 Include declarations.
41*/
cristy4c08aed2011-07-01 19:47:50 +000042#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"
cristye5d21382014-11-29 15:28:30 +000050#include "MagickCore/colormap-private.h"
cristy4c08aed2011-07-01 19:47:50 +000051#include "MagickCore/colorspace.h"
cristy510d06a2011-07-06 23:43:54 +000052#include "MagickCore/colorspace-private.h"
cristy4c08aed2011-07-01 19:47:50 +000053#include "MagickCore/exception.h"
54#include "MagickCore/exception-private.h"
55#include "MagickCore/image.h"
56#include "MagickCore/image-private.h"
57#include "MagickCore/list.h"
58#include "MagickCore/magick.h"
59#include "MagickCore/memory_.h"
60#include "MagickCore/monitor.h"
61#include "MagickCore/monitor-private.h"
62#include "MagickCore/pixel-accessor.h"
63#include "MagickCore/property.h"
64#include "MagickCore/quantum-private.h"
65#include "MagickCore/static.h"
66#include "MagickCore/string_.h"
67#include "MagickCore/module.h"
cristy3ed852e2009-09-05 21:47:34 +000068
69/*
70 Forward declarations.
71*/
72static MagickBooleanType
cristy3a37efd2011-08-28 20:31:03 +000073 WriteVIFFImage(const ImageInfo *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +000074
75/*
76%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
77% %
78% %
79% %
80% I s V I F F %
81% %
82% %
83% %
84%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
85%
86% IsVIFF() returns MagickTrue if the image format type, identified by the
87% magick string, is VIFF.
88%
89% The format of the IsVIFF method is:
90%
91% MagickBooleanType IsVIFF(const unsigned char *magick,const size_t length)
92%
93% A description of each parameter follows:
94%
95% o magick: compare image format pattern against these bytes.
96%
97% o length: Specifies the length of the magick string.
98%
cristy3ed852e2009-09-05 21:47:34 +000099*/
100static MagickBooleanType IsVIFF(const unsigned char *magick,const size_t length)
101{
102 if (length < 2)
103 return(MagickFalse);
104 if (memcmp(magick,"\253\001",2) == 0)
105 return(MagickTrue);
106 return(MagickFalse);
107}
108
109/*
110%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
111% %
112% %
113% %
114% R e a d V I F F I m a g e %
115% %
116% %
117% %
118%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
119%
120% ReadVIFFImage() reads a Khoros Visualization image file and returns
121% it. It allocates the memory necessary for the new Image structure and
122% returns a pointer to the new image.
123%
124% The format of the ReadVIFFImage method is:
125%
126% Image *ReadVIFFImage(const ImageInfo *image_info,
127% ExceptionInfo *exception)
128%
129% A description of each parameter follows:
130%
131% o image: Method ReadVIFFImage returns a pointer to the image after
132% reading. A null image is returned if there is a memory shortage or if
133% the image cannot be read.
134%
135% o image_info: the image info.
136%
137% o exception: return any errors or warnings in this structure.
138%
139*/
140static Image *ReadVIFFImage(const ImageInfo *image_info,
141 ExceptionInfo *exception)
142{
143#define VFF_CM_genericRGB 15
144#define VFF_CM_ntscRGB 1
145#define VFF_CM_NONE 0
146#define VFF_DEP_DECORDER 0x4
147#define VFF_DEP_NSORDER 0x8
148#define VFF_DES_RAW 0
149#define VFF_LOC_IMPLICIT 1
150#define VFF_MAPTYP_NONE 0
151#define VFF_MAPTYP_1_BYTE 1
152#define VFF_MAPTYP_2_BYTE 2
153#define VFF_MAPTYP_4_BYTE 4
154#define VFF_MAPTYP_FLOAT 5
155#define VFF_MAPTYP_DOUBLE 7
156#define VFF_MS_NONE 0
157#define VFF_MS_ONEPERBAND 1
158#define VFF_MS_SHARED 3
159#define VFF_TYP_BIT 0
160#define VFF_TYP_1_BYTE 1
161#define VFF_TYP_2_BYTE 2
162#define VFF_TYP_4_BYTE 4
163#define VFF_TYP_FLOAT 5
164#define VFF_TYP_DOUBLE 9
165
166 typedef struct _ViffInfo
167 {
168 unsigned char
169 identifier,
170 file_type,
171 release,
172 version,
173 machine_dependency,
174 reserve[3];
175
176 char
177 comment[512];
178
cristy5d89f432010-05-30 00:00:26 +0000179 unsigned int
cristy3ed852e2009-09-05 21:47:34 +0000180 rows,
181 columns,
182 subrows;
183
cristyeaedf062010-05-29 22:36:02 +0000184 int
cristy3ed852e2009-09-05 21:47:34 +0000185 x_offset,
186 y_offset;
187
188 float
189 x_bits_per_pixel,
190 y_bits_per_pixel;
191
cristyeaedf062010-05-29 22:36:02 +0000192 unsigned int
cristy3ed852e2009-09-05 21:47:34 +0000193 location_type,
194 location_dimension,
195 number_of_images,
196 number_data_bands,
197 data_storage_type,
198 data_encode_scheme,
199 map_scheme,
200 map_storage_type,
201 map_rows,
202 map_columns,
203 map_subrows,
204 map_enable,
205 maps_per_cycle,
206 color_space_model;
207 } ViffInfo;
208
209 double
210 min_value,
211 scale_factor,
212 value;
213
214 Image
215 *image;
216
217 int
218 bit;
219
cristy3ed852e2009-09-05 21:47:34 +0000220 MagickBooleanType
221 status;
222
223 MagickSizeType
224 number_pixels;
225
cristybb503372010-05-27 20:51:26 +0000226 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000227 x;
228
cristy4c08aed2011-07-01 19:47:50 +0000229 register Quantum
cristy3ed852e2009-09-05 21:47:34 +0000230 *q;
231
cristybb503372010-05-27 20:51:26 +0000232 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000233 i;
234
235 register unsigned char
236 *p;
237
cristybb503372010-05-27 20:51:26 +0000238 size_t
cristy3ed852e2009-09-05 21:47:34 +0000239 bytes_per_pixel,
240 lsb_first,
241 max_packets,
242 quantum;
243
cristyc6da28e2011-04-28 01:41:35 +0000244 ssize_t
245 count,
246 y;
247
248 unsigned char
cristy5def2032013-06-30 17:44:08 +0000249 *pixels;
cristyc6da28e2011-04-28 01:41:35 +0000250
cristy3ed852e2009-09-05 21:47:34 +0000251 ViffInfo
252 viff_info;
253
254 /*
255 Open image file.
256 */
257 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000258 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000259 if (image_info->debug != MagickFalse)
260 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
261 image_info->filename);
262 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000263 assert(exception->signature == MagickCoreSignature);
cristy9950d572011-10-01 18:22:35 +0000264 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000265 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 */
cristy22e13062015-01-03 18:09:40 +0000280 if ((count != 1) || ((unsigned char) viff_info.identifier != 0xab))
cristy3ed852e2009-09-05 21:47:34 +0000281 ThrowReaderException(CorruptImageError,"NotAVIFFImage");
282 /*
283 Initialize VIFF image.
284 */
cristy0f18a502014-11-28 14:16:00 +0000285 (void) ReadBlob(image,sizeof(viff_info.file_type),&viff_info.file_type);
286 (void) ReadBlob(image,sizeof(viff_info.release),&viff_info.release);
287 (void) ReadBlob(image,sizeof(viff_info.version),&viff_info.version);
288 (void) ReadBlob(image,sizeof(viff_info.machine_dependency),
289 &viff_info.machine_dependency);
290 (void) ReadBlob(image,sizeof(viff_info.reserve),viff_info.reserve);
cristy3ed852e2009-09-05 21:47:34 +0000291 count=ReadBlob(image,512,(unsigned char *) viff_info.comment);
292 viff_info.comment[511]='\0';
293 if (strlen(viff_info.comment) > 4)
cristyd15e6592011-10-15 00:13:06 +0000294 (void) SetImageProperty(image,"comment",viff_info.comment,exception);
cristy3ed852e2009-09-05 21:47:34 +0000295 if ((viff_info.machine_dependency == VFF_DEP_DECORDER) ||
296 (viff_info.machine_dependency == VFF_DEP_NSORDER))
cristy0f18a502014-11-28 14:16:00 +0000297 image->endian=LSBEndian;
cristy3ed852e2009-09-05 21:47:34 +0000298 else
cristy0f18a502014-11-28 14:16:00 +0000299 image->endian=MSBEndian;
300 viff_info.rows=ReadBlobLong(image);
301 viff_info.columns=ReadBlobLong(image);
302 viff_info.subrows=ReadBlobLong(image);
303 viff_info.x_offset=(int) ReadBlobLong(image);
304 viff_info.y_offset=(int) ReadBlobLong(image);
305 viff_info.x_bits_per_pixel=(float) ReadBlobLong(image);
306 viff_info.y_bits_per_pixel=(float) ReadBlobLong(image);
307 viff_info.location_type=ReadBlobLong(image);
308 viff_info.location_dimension=ReadBlobLong(image);
309 viff_info.number_of_images=ReadBlobLong(image);
310 viff_info.number_data_bands=ReadBlobLong(image);
311 viff_info.data_storage_type=ReadBlobLong(image);
312 viff_info.data_encode_scheme=ReadBlobLong(image);
313 viff_info.map_scheme=ReadBlobLong(image);
314 viff_info.map_storage_type=ReadBlobLong(image);
315 viff_info.map_rows=ReadBlobLong(image);
316 viff_info.map_columns=ReadBlobLong(image);
317 viff_info.map_subrows=ReadBlobLong(image);
318 viff_info.map_enable=ReadBlobLong(image);
319 viff_info.maps_per_cycle=ReadBlobLong(image);
320 viff_info.color_space_model=ReadBlobLong(image);
cristy3ed852e2009-09-05 21:47:34 +0000321 for (i=0; i < 420; i++)
322 (void) ReadBlobByte(image);
cristy32afe8c2015-01-03 18:09:13 +0000323 if (EOFBlob(image) != MagickFalse)
324 ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
cristy3ed852e2009-09-05 21:47:34 +0000325 image->columns=viff_info.rows;
326 image->rows=viff_info.columns;
cristyc6da28e2011-04-28 01:41:35 +0000327 image->depth=viff_info.x_bits_per_pixel <= 8 ? 8UL :
328 MAGICKCORE_QUANTUM_DEPTH;
cristy3ed852e2009-09-05 21:47:34 +0000329 /*
330 Verify that we can read this VIFF image.
331 */
332 number_pixels=(MagickSizeType) viff_info.columns*viff_info.rows;
333 if (number_pixels != (size_t) number_pixels)
334 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
335 if (number_pixels == 0)
336 ThrowReaderException(CoderError,"ImageColumnOrRowSizeIsNotSupported");
337 if ((viff_info.number_data_bands < 1) || (viff_info.number_data_bands > 4))
338 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
339 if ((viff_info.data_storage_type != VFF_TYP_BIT) &&
340 (viff_info.data_storage_type != VFF_TYP_1_BYTE) &&
341 (viff_info.data_storage_type != VFF_TYP_2_BYTE) &&
342 (viff_info.data_storage_type != VFF_TYP_4_BYTE) &&
343 (viff_info.data_storage_type != VFF_TYP_FLOAT) &&
344 (viff_info.data_storage_type != VFF_TYP_DOUBLE))
345 ThrowReaderException(CoderError,"DataStorageTypeIsNotSupported");
346 if (viff_info.data_encode_scheme != VFF_DES_RAW)
347 ThrowReaderException(CoderError,"DataEncodingSchemeIsNotSupported");
348 if ((viff_info.map_storage_type != VFF_MAPTYP_NONE) &&
349 (viff_info.map_storage_type != VFF_MAPTYP_1_BYTE) &&
350 (viff_info.map_storage_type != VFF_MAPTYP_2_BYTE) &&
351 (viff_info.map_storage_type != VFF_MAPTYP_4_BYTE) &&
352 (viff_info.map_storage_type != VFF_MAPTYP_FLOAT) &&
353 (viff_info.map_storage_type != VFF_MAPTYP_DOUBLE))
354 ThrowReaderException(CoderError,"MapStorageTypeIsNotSupported");
355 if ((viff_info.color_space_model != VFF_CM_NONE) &&
356 (viff_info.color_space_model != VFF_CM_ntscRGB) &&
357 (viff_info.color_space_model != VFF_CM_genericRGB))
358 ThrowReaderException(CoderError,"ColorspaceModelIsNotSupported");
359 if (viff_info.location_type != VFF_LOC_IMPLICIT)
360 ThrowReaderException(CoderError,"LocationTypeIsNotSupported");
361 if (viff_info.number_of_images != 1)
362 ThrowReaderException(CoderError,"NumberOfImagesIsNotSupported");
363 if (viff_info.map_rows == 0)
364 viff_info.map_scheme=VFF_MS_NONE;
365 switch ((int) viff_info.map_scheme)
366 {
367 case VFF_MS_NONE:
368 {
369 if (viff_info.number_data_bands < 3)
370 {
371 /*
372 Create linear color ramp.
373 */
cristy3ed852e2009-09-05 21:47:34 +0000374 if (viff_info.data_storage_type == VFF_TYP_BIT)
375 image->colors=2;
dirk549cd1f2013-09-19 19:03:25 +0000376 else
cristy1b1868b2014-05-18 11:37:46 +0000377 if (viff_info.data_storage_type == VFF_MAPTYP_1_BYTE)
378 image->colors=256UL;
379 else
380 image->colors=image->depth <= 8 ? 256UL : 65536UL;
381 status=AcquireImageColormap(image,image->colors,exception);
382 if (status == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000383 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
384 }
385 break;
386 }
387 case VFF_MS_ONEPERBAND:
388 case VFF_MS_SHARED:
389 {
390 unsigned char
391 *viff_colormap;
392
393 /*
394 Allocate VIFF colormap.
395 */
396 switch ((int) viff_info.map_storage_type)
397 {
398 case VFF_MAPTYP_1_BYTE: bytes_per_pixel=1; break;
399 case VFF_MAPTYP_2_BYTE: bytes_per_pixel=2; break;
400 case VFF_MAPTYP_4_BYTE: bytes_per_pixel=4; break;
401 case VFF_MAPTYP_FLOAT: bytes_per_pixel=4; break;
402 case VFF_MAPTYP_DOUBLE: bytes_per_pixel=8; break;
403 default: bytes_per_pixel=1; break;
404 }
405 image->colors=viff_info.map_columns;
cristy018f07f2011-09-04 21:15:19 +0000406 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000407 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
408 viff_colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
409 viff_info.map_rows*bytes_per_pixel*sizeof(*viff_colormap));
410 if (viff_colormap == (unsigned char *) NULL)
411 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
412 /*
413 Read VIFF raster colormap.
414 */
415 count=ReadBlob(image,bytes_per_pixel*image->colors*viff_info.map_rows,
416 viff_colormap);
417 lsb_first=1;
418 if (*(char *) &lsb_first &&
419 ((viff_info.machine_dependency != VFF_DEP_DECORDER) &&
420 (viff_info.machine_dependency != VFF_DEP_NSORDER)))
421 switch ((int) viff_info.map_storage_type)
422 {
423 case VFF_MAPTYP_2_BYTE:
424 {
425 MSBOrderShort(viff_colormap,(bytes_per_pixel*image->colors*
426 viff_info.map_rows));
427 break;
428 }
429 case VFF_MAPTYP_4_BYTE:
430 case VFF_MAPTYP_FLOAT:
431 {
432 MSBOrderLong(viff_colormap,(bytes_per_pixel*image->colors*
433 viff_info.map_rows));
434 break;
435 }
436 default: break;
437 }
cristybb503372010-05-27 20:51:26 +0000438 for (i=0; i < (ssize_t) (viff_info.map_rows*image->colors); i++)
cristy3ed852e2009-09-05 21:47:34 +0000439 {
440 switch ((int) viff_info.map_storage_type)
441 {
442 case VFF_MAPTYP_2_BYTE: value=1.0*((short *) viff_colormap)[i]; break;
443 case VFF_MAPTYP_4_BYTE: value=1.0*((int *) viff_colormap)[i]; break;
444 case VFF_MAPTYP_FLOAT: value=((float *) viff_colormap)[i]; break;
445 case VFF_MAPTYP_DOUBLE: value=((double *) viff_colormap)[i]; break;
446 default: value=1.0*viff_colormap[i]; break;
447 }
cristybb503372010-05-27 20:51:26 +0000448 if (i < (ssize_t) image->colors)
cristy3ed852e2009-09-05 21:47:34 +0000449 {
450 image->colormap[i].red=ScaleCharToQuantum((unsigned char) value);
451 image->colormap[i].green=
452 ScaleCharToQuantum((unsigned char) value);
453 image->colormap[i].blue=ScaleCharToQuantum((unsigned char) value);
454 }
455 else
cristybb503372010-05-27 20:51:26 +0000456 if (i < (ssize_t) (2*image->colors))
cristy3ed852e2009-09-05 21:47:34 +0000457 image->colormap[i % image->colors].green=
458 ScaleCharToQuantum((unsigned char) value);
459 else
cristybb503372010-05-27 20:51:26 +0000460 if (i < (ssize_t) (3*image->colors))
cristy3ed852e2009-09-05 21:47:34 +0000461 image->colormap[i % image->colors].blue=
462 ScaleCharToQuantum((unsigned char) value);
463 }
464 viff_colormap=(unsigned char *) RelinquishMagickMemory(viff_colormap);
465 break;
466 }
467 default:
468 ThrowReaderException(CoderError,"ColormapTypeNotSupported");
469 }
470 /*
471 Initialize image structure.
472 */
cristyb0a657e2012-08-29 00:45:37 +0000473 image->alpha_trait=viff_info.number_data_bands == 4 ? BlendPixelTrait :
474 UndefinedPixelTrait;
475 image->storage_class=(viff_info.number_data_bands < 3 ? PseudoClass :
476 DirectClass);
cristy3ed852e2009-09-05 21:47:34 +0000477 image->columns=viff_info.rows;
478 image->rows=viff_info.columns;
479 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
480 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
481 break;
cristyacabb842014-12-14 23:36:33 +0000482 status=SetImageExtent(image,image->columns,image->rows,exception);
483 if (status == MagickFalse)
484 return(DestroyImageList(image));
cristy3ed852e2009-09-05 21:47:34 +0000485 /*
486 Allocate VIFF pixels.
487 */
488 switch ((int) viff_info.data_storage_type)
489 {
490 case VFF_TYP_2_BYTE: bytes_per_pixel=2; break;
491 case VFF_TYP_4_BYTE: bytes_per_pixel=4; break;
492 case VFF_TYP_FLOAT: bytes_per_pixel=4; break;
493 case VFF_TYP_DOUBLE: bytes_per_pixel=8; break;
494 default: bytes_per_pixel=1; break;
495 }
496 if (viff_info.data_storage_type == VFF_TYP_BIT)
497 max_packets=((image->columns+7UL) >> 3UL)*image->rows;
498 else
cristybb503372010-05-27 20:51:26 +0000499 max_packets=(size_t) (number_pixels*viff_info.number_data_bands);
cristy5def2032013-06-30 17:44:08 +0000500 pixels=(unsigned char *) AcquireQuantumMemory(max_packets,
501 bytes_per_pixel*sizeof(*pixels));
502 if (pixels == (unsigned char *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000503 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
cristy5def2032013-06-30 17:44:08 +0000504 count=ReadBlob(image,bytes_per_pixel*max_packets,pixels);
cristy3ed852e2009-09-05 21:47:34 +0000505 lsb_first=1;
506 if (*(char *) &lsb_first &&
507 ((viff_info.machine_dependency != VFF_DEP_DECORDER) &&
508 (viff_info.machine_dependency != VFF_DEP_NSORDER)))
509 switch ((int) viff_info.data_storage_type)
510 {
511 case VFF_TYP_2_BYTE:
512 {
cristy5def2032013-06-30 17:44:08 +0000513 MSBOrderShort(pixels,bytes_per_pixel*max_packets);
cristy3ed852e2009-09-05 21:47:34 +0000514 break;
515 }
516 case VFF_TYP_4_BYTE:
517 case VFF_TYP_FLOAT:
518 {
cristy5def2032013-06-30 17:44:08 +0000519 MSBOrderLong(pixels,bytes_per_pixel*max_packets);
cristy3ed852e2009-09-05 21:47:34 +0000520 break;
521 }
522 default: break;
523 }
524 min_value=0.0;
525 scale_factor=1.0;
526 if ((viff_info.data_storage_type != VFF_TYP_1_BYTE) &&
527 (viff_info.map_scheme == VFF_MS_NONE))
528 {
529 double
530 max_value;
531
532 /*
533 Determine scale factor.
534 */
535 switch ((int) viff_info.data_storage_type)
536 {
cristy5def2032013-06-30 17:44:08 +0000537 case VFF_TYP_2_BYTE: value=1.0*((short *) pixels)[0]; break;
538 case VFF_TYP_4_BYTE: value=1.0*((int *) pixels)[0]; break;
539 case VFF_TYP_FLOAT: value=((float *) pixels)[0]; break;
540 case VFF_TYP_DOUBLE: value=((double *) pixels)[0]; break;
541 default: value=1.0*pixels[0]; break;
cristy3ed852e2009-09-05 21:47:34 +0000542 }
543 max_value=value;
544 min_value=value;
cristybb503372010-05-27 20:51:26 +0000545 for (i=0; i < (ssize_t) max_packets; i++)
cristy3ed852e2009-09-05 21:47:34 +0000546 {
547 switch ((int) viff_info.data_storage_type)
548 {
cristy5def2032013-06-30 17:44:08 +0000549 case VFF_TYP_2_BYTE: value=1.0*((short *) pixels)[i]; break;
550 case VFF_TYP_4_BYTE: value=1.0*((int *) pixels)[i]; break;
551 case VFF_TYP_FLOAT: value=((float *) pixels)[i]; break;
552 case VFF_TYP_DOUBLE: value=((double *) pixels)[i]; break;
553 default: value=1.0*pixels[i]; break;
cristy3ed852e2009-09-05 21:47:34 +0000554 }
555 if (value > max_value)
556 max_value=value;
557 else
558 if (value < min_value)
559 min_value=value;
560 }
561 if ((min_value == 0) && (max_value == 0))
562 scale_factor=0;
563 else
564 if (min_value == max_value)
565 {
cristya19f1d72012-08-07 18:24:38 +0000566 scale_factor=(double) QuantumRange/min_value;
cristy3ed852e2009-09-05 21:47:34 +0000567 min_value=0;
568 }
569 else
cristya19f1d72012-08-07 18:24:38 +0000570 scale_factor=(double) QuantumRange/(max_value-min_value);
cristy3ed852e2009-09-05 21:47:34 +0000571 }
572 /*
573 Convert pixels to Quantum size.
574 */
cristy5def2032013-06-30 17:44:08 +0000575 p=(unsigned char *) pixels;
cristybb503372010-05-27 20:51:26 +0000576 for (i=0; i < (ssize_t) max_packets; i++)
cristy3ed852e2009-09-05 21:47:34 +0000577 {
578 switch ((int) viff_info.data_storage_type)
579 {
cristy5def2032013-06-30 17:44:08 +0000580 case VFF_TYP_2_BYTE: value=1.0*((short *) pixels)[i]; break;
581 case VFF_TYP_4_BYTE: value=1.0*((int *) pixels)[i]; break;
582 case VFF_TYP_FLOAT: value=((float *) pixels)[i]; break;
583 case VFF_TYP_DOUBLE: value=((double *) pixels)[i]; break;
584 default: value=1.0*pixels[i]; break;
cristy3ed852e2009-09-05 21:47:34 +0000585 }
586 if (viff_info.map_scheme == VFF_MS_NONE)
587 {
588 value=(value-min_value)*scale_factor;
589 if (value > QuantumRange)
590 value=QuantumRange;
591 else
592 if (value < 0)
593 value=0;
594 }
cristy23389822015-07-19 12:58:13 +0000595 *p=(unsigned char) ((Quantum) value);
cristy3ed852e2009-09-05 21:47:34 +0000596 p++;
597 }
598 /*
599 Convert VIFF raster image to pixel packets.
600 */
cristy5def2032013-06-30 17:44:08 +0000601 p=(unsigned char *) pixels;
cristy3ed852e2009-09-05 21:47:34 +0000602 if (viff_info.data_storage_type == VFF_TYP_BIT)
603 {
604 /*
605 Convert bitmap scanline.
606 */
cristybb503372010-05-27 20:51:26 +0000607 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000608 {
609 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000610 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000611 break;
cristybb503372010-05-27 20:51:26 +0000612 for (x=0; x < (ssize_t) (image->columns-7); x+=8)
cristy3ed852e2009-09-05 21:47:34 +0000613 {
614 for (bit=0; bit < 8; bit++)
cristy4c08aed2011-07-01 19:47:50 +0000615 {
cristy0f18a502014-11-28 14:16:00 +0000616 quantum=(size_t) ((*p) & (0x01 << bit) ? 0 : 1);
cristy822251f2015-01-01 00:28:58 +0000617 SetPixelRed(image,quantum == 0 ? 0 : QuantumRange,q);
618 SetPixelGreen(image,quantum == 0 ? 0 : QuantumRange,q);
619 SetPixelBlue(image,quantum == 0 ? 0 : QuantumRange,q);
620 if (image->storage_class == PseudoClass)
621 SetPixelIndex(image,quantum,q);
cristyed231572011-07-14 02:18:59 +0000622 q+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +0000623 }
cristy3ed852e2009-09-05 21:47:34 +0000624 p++;
625 }
626 if ((image->columns % 8) != 0)
627 {
cristy0f18a502014-11-28 14:16:00 +0000628 for (bit=0; bit < (int) (image->columns % 8); bit++)
cristy940942b2014-05-18 11:32:34 +0000629 {
cristy0f18a502014-11-28 14:16:00 +0000630 quantum=(size_t) ((*p) & (0x01 << bit) ? 0 : 1);
cristy822251f2015-01-01 00:28:58 +0000631 SetPixelRed(image,quantum == 0 ? 0 : QuantumRange,q);
632 SetPixelGreen(image,quantum == 0 ? 0 : QuantumRange,q);
633 SetPixelBlue(image,quantum == 0 ? 0 : QuantumRange,q);
634 if (image->storage_class == PseudoClass)
635 SetPixelIndex(image,quantum,q);
cristy940942b2014-05-18 11:32:34 +0000636 q+=GetPixelChannels(image);
637 }
cristy3ed852e2009-09-05 21:47:34 +0000638 p++;
639 }
640 if (SyncAuthenticPixels(image,exception) == MagickFalse)
641 break;
642 if (image->previous == (Image *) NULL)
643 {
cristycee97112010-05-28 00:44:52 +0000644 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
645 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000646 if (status == MagickFalse)
647 break;
648 }
649 }
650 }
651 else
652 if (image->storage_class == PseudoClass)
cristybb503372010-05-27 20:51:26 +0000653 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000654 {
655 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000656 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000657 break;
cristybb503372010-05-27 20:51:26 +0000658 for (x=0; x < (ssize_t) image->columns; x++)
cristy4c08aed2011-07-01 19:47:50 +0000659 {
660 SetPixelIndex(image,*p++,q);
cristyed231572011-07-14 02:18:59 +0000661 q+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +0000662 }
cristy3ed852e2009-09-05 21:47:34 +0000663 if (SyncAuthenticPixels(image,exception) == MagickFalse)
664 break;
665 if (image->previous == (Image *) NULL)
666 {
cristycee97112010-05-28 00:44:52 +0000667 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
668 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000669 if (status == MagickFalse)
670 break;
671 }
672 }
673 else
674 {
675 /*
676 Convert DirectColor scanline.
677 */
678 number_pixels=(MagickSizeType) image->columns*image->rows;
cristybb503372010-05-27 20:51:26 +0000679 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000680 {
681 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000682 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000683 break;
cristybb503372010-05-27 20:51:26 +0000684 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000685 {
cristy4c08aed2011-07-01 19:47:50 +0000686 SetPixelRed(image,ScaleCharToQuantum(*p),q);
687 SetPixelGreen(image,ScaleCharToQuantum(*(p+number_pixels)),q);
688 SetPixelBlue(image,ScaleCharToQuantum(*(p+2*number_pixels)),q);
cristy3ed852e2009-09-05 21:47:34 +0000689 if (image->colors != 0)
690 {
cristye5d21382014-11-29 15:28:30 +0000691 ssize_t
692 index;
693
694 index=(ssize_t) GetPixelRed(image,q);
695 SetPixelRed(image,image->colormap[
696 ConstrainColormapIndex(image,index,exception)].red,q);
697 index=(ssize_t) GetPixelGreen(image,q);
698 SetPixelGreen(image,image->colormap[
699 ConstrainColormapIndex(image,index,exception)].green,q);
700 index=(ssize_t) GetPixelBlue(image,q);
701 SetPixelBlue(image,image->colormap[
702 ConstrainColormapIndex(image,index,exception)].blue,q);
cristy3ed852e2009-09-05 21:47:34 +0000703 }
cristy17f11b02014-12-20 19:37:04 +0000704 SetPixelAlpha(image,image->alpha_trait != UndefinedPixelTrait ?
cristy4c08aed2011-07-01 19:47:50 +0000705 ScaleCharToQuantum(*(p+number_pixels*3)) : OpaqueAlpha,q);
cristy3ed852e2009-09-05 21:47:34 +0000706 p++;
cristyed231572011-07-14 02:18:59 +0000707 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000708 }
709 if (SyncAuthenticPixels(image,exception) == MagickFalse)
710 break;
711 if (image->previous == (Image *) NULL)
712 {
cristycee97112010-05-28 00:44:52 +0000713 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
714 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000715 if (status == MagickFalse)
716 break;
717 }
718 }
719 }
cristy5def2032013-06-30 17:44:08 +0000720 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
cristy3ed852e2009-09-05 21:47:34 +0000721 if (image->storage_class == PseudoClass)
cristyea1a8aa2011-10-20 13:24:06 +0000722 (void) SyncImage(image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000723 if (EOFBlob(image) != MagickFalse)
724 {
725 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
726 image->filename);
727 break;
728 }
729 /*
730 Proceed to next image.
731 */
732 if (image_info->number_scenes != 0)
733 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
734 break;
735 count=ReadBlob(image,1,&viff_info.identifier);
736 if ((count != 0) && (viff_info.identifier == 0xab))
737 {
738 /*
739 Allocate next image structure.
740 */
cristy9950d572011-10-01 18:22:35 +0000741 AcquireNextImage(image_info,image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000742 if (GetNextImageInList(image) == (Image *) NULL)
743 {
744 image=DestroyImageList(image);
745 return((Image *) NULL);
746 }
747 image=SyncNextImageInList(image);
748 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
749 GetBlobSize(image));
750 if (status == MagickFalse)
751 break;
752 }
753 } while ((count != 0) && (viff_info.identifier == 0xab));
754 (void) CloseBlob(image);
755 return(GetFirstImageInList(image));
756}
757
758/*
759%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
760% %
761% %
762% %
763% R e g i s t e r V I F F I m a g e %
764% %
765% %
766% %
767%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
768%
769% RegisterVIFFImage() adds properties for the VIFF image format to
770% the list of supported formats. The properties include the image format
771% tag, a method to read and/or write the format, whether the format
772% supports the saving of more than one frame to the same file or blob,
773% whether the format supports native in-memory I/O, and a brief
774% description of the format.
775%
776% The format of the RegisterVIFFImage method is:
777%
cristybb503372010-05-27 20:51:26 +0000778% size_t RegisterVIFFImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000779%
780*/
cristybb503372010-05-27 20:51:26 +0000781ModuleExport size_t RegisterVIFFImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000782{
783 MagickInfo
784 *entry;
785
dirk06b627a2015-04-06 18:59:17 +0000786 entry=AcquireMagickInfo("VIFF","VIFF","Khoros Visualization image");
cristy3ed852e2009-09-05 21:47:34 +0000787 entry->decoder=(DecodeImageHandler *) ReadVIFFImage;
788 entry->encoder=(EncodeImageHandler *) WriteVIFFImage;
789 entry->magick=(IsImageFormatHandler *) IsVIFF;
cristy3ed852e2009-09-05 21:47:34 +0000790 (void) RegisterMagickInfo(entry);
dirk06b627a2015-04-06 18:59:17 +0000791 entry=AcquireMagickInfo("VIFF","XV","Khoros Visualization image");
cristy3ed852e2009-09-05 21:47:34 +0000792 entry->decoder=(DecodeImageHandler *) ReadVIFFImage;
793 entry->encoder=(EncodeImageHandler *) WriteVIFFImage;
cristy3ed852e2009-09-05 21:47:34 +0000794 (void) RegisterMagickInfo(entry);
795 return(MagickImageCoderSignature);
796}
797
798/*
799%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
800% %
801% %
802% %
803% U n r e g i s t e r V I F F I m a g e %
804% %
805% %
806% %
807%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
808%
809% UnregisterVIFFImage() removes format registrations made by the
810% VIFF module from the list of supported formats.
811%
812% The format of the UnregisterVIFFImage method is:
813%
814% UnregisterVIFFImage(void)
815%
816*/
817ModuleExport void UnregisterVIFFImage(void)
818{
819 (void) UnregisterMagickInfo("VIFF");
820 (void) UnregisterMagickInfo("XV");
821}
822
823/*
824%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
825% %
826% %
827% %
828% W r i t e V I F F I m a g e %
829% %
830% %
831% %
832%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
833%
834% WriteVIFFImage() writes an image to a file in the VIFF image format.
835%
836% The format of the WriteVIFFImage method is:
837%
838% MagickBooleanType WriteVIFFImage(const ImageInfo *image_info,
cristy3a37efd2011-08-28 20:31:03 +0000839% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000840%
841% A description of each parameter follows.
842%
843% o image_info: the image info.
844%
845% o image: The image.
846%
cristy3a37efd2011-08-28 20:31:03 +0000847% o exception: return any errors or warnings in this structure.
848%
cristy3ed852e2009-09-05 21:47:34 +0000849*/
cristy3ed852e2009-09-05 21:47:34 +0000850static MagickBooleanType WriteVIFFImage(const ImageInfo *image_info,
cristy3a37efd2011-08-28 20:31:03 +0000851 Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000852{
853#define VFF_CM_genericRGB 15
854#define VFF_CM_NONE 0
855#define VFF_DEP_IEEEORDER 0x2
856#define VFF_DES_RAW 0
857#define VFF_LOC_IMPLICIT 1
858#define VFF_MAPTYP_NONE 0
859#define VFF_MAPTYP_1_BYTE 1
860#define VFF_MS_NONE 0
861#define VFF_MS_ONEPERBAND 1
862#define VFF_TYP_BIT 0
863#define VFF_TYP_1_BYTE 1
864
865 typedef struct _ViffInfo
866 {
867 char
868 identifier,
869 file_type,
870 release,
871 version,
872 machine_dependency,
873 reserve[3],
874 comment[512];
875
cristybb503372010-05-27 20:51:26 +0000876 size_t
cristy3ed852e2009-09-05 21:47:34 +0000877 rows,
878 columns,
879 subrows;
880
cristy5d89f432010-05-30 00:00:26 +0000881 int
cristy3ed852e2009-09-05 21:47:34 +0000882 x_offset,
883 y_offset;
884
885 unsigned int
886 x_bits_per_pixel,
cristy5d89f432010-05-30 00:00:26 +0000887 y_bits_per_pixel,
cristy3ed852e2009-09-05 21:47:34 +0000888 location_type,
889 location_dimension,
890 number_of_images,
891 number_data_bands,
892 data_storage_type,
893 data_encode_scheme,
894 map_scheme,
895 map_storage_type,
896 map_rows,
897 map_columns,
898 map_subrows,
899 map_enable,
900 maps_per_cycle,
901 color_space_model;
902 } ViffInfo;
903
904 const char
905 *value;
906
cristy3ed852e2009-09-05 21:47:34 +0000907 MagickBooleanType
908 status;
909
910 MagickOffsetType
911 scene;
912
913 MagickSizeType
914 number_pixels,
915 packets;
916
cristy5def2032013-06-30 17:44:08 +0000917 MemoryInfo
918 *pixel_info;
919
cristy4c08aed2011-07-01 19:47:50 +0000920 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000921 *p;
922
cristybb503372010-05-27 20:51:26 +0000923 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000924 x;
925
cristybb503372010-05-27 20:51:26 +0000926 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000927 i;
928
929 register unsigned char
930 *q;
931
cristyc6da28e2011-04-28 01:41:35 +0000932 ssize_t
933 y;
934
cristy3ed852e2009-09-05 21:47:34 +0000935 unsigned char
cristy5def2032013-06-30 17:44:08 +0000936 *pixels;
cristy3ed852e2009-09-05 21:47:34 +0000937
938 ViffInfo
939 viff_info;
940
941 /*
942 Open output image file.
943 */
944 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000945 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000946 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000947 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000948 if (image->debug != MagickFalse)
949 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +0000950 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000951 assert(exception->signature == MagickCoreSignature);
cristy3a37efd2011-08-28 20:31:03 +0000952 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000953 if (status == MagickFalse)
954 return(status);
955 (void) ResetMagickMemory(&viff_info,0,sizeof(ViffInfo));
956 scene=0;
957 do
958 {
959 /*
960 Initialize VIFF image structure.
961 */
cristyaf8d3912014-02-21 14:50:33 +0000962 (void) TransformImageColorspace(image,sRGBColorspace,exception);
dirk93b02b72013-11-16 16:03:36 +0000963DisableMSCWarning(4310)
cristy3ed852e2009-09-05 21:47:34 +0000964 viff_info.identifier=(char) 0xab;
dirk93b02b72013-11-16 16:03:36 +0000965RestoreMSCWarning
cristy3ed852e2009-09-05 21:47:34 +0000966 viff_info.file_type=1;
967 viff_info.release=1;
968 viff_info.version=3;
969 viff_info.machine_dependency=VFF_DEP_IEEEORDER; /* IEEE byte ordering */
970 *viff_info.comment='\0';
cristyd15e6592011-10-15 00:13:06 +0000971 value=GetImageProperty(image,"comment",exception);
cristy3ed852e2009-09-05 21:47:34 +0000972 if (value != (const char *) NULL)
cristyc6da28e2011-04-28 01:41:35 +0000973 (void) CopyMagickString(viff_info.comment,value,MagickMin(strlen(value),
974 511)+1);
cristy3ed852e2009-09-05 21:47:34 +0000975 viff_info.rows=image->columns;
976 viff_info.columns=image->rows;
977 viff_info.subrows=0;
978 viff_info.x_offset=(~0);
979 viff_info.y_offset=(~0);
980 viff_info.x_bits_per_pixel=0;
981 viff_info.y_bits_per_pixel=0;
982 viff_info.location_type=VFF_LOC_IMPLICIT;
983 viff_info.location_dimension=0;
984 viff_info.number_of_images=1;
985 viff_info.data_encode_scheme=VFF_DES_RAW;
986 viff_info.map_scheme=VFF_MS_NONE;
987 viff_info.map_storage_type=VFF_MAPTYP_NONE;
988 viff_info.map_rows=0;
989 viff_info.map_columns=0;
990 viff_info.map_subrows=0;
991 viff_info.map_enable=1; /* no colormap */
992 viff_info.maps_per_cycle=0;
993 number_pixels=(MagickSizeType) image->columns*image->rows;
994 if (image->storage_class == DirectClass)
995 {
996 /*
997 Full color VIFF raster.
998 */
cristy0f18a502014-11-28 14:16:00 +0000999 viff_info.number_data_bands=image->alpha_trait ? 4U : 3U;
cristy3ed852e2009-09-05 21:47:34 +00001000 viff_info.color_space_model=VFF_CM_genericRGB;
1001 viff_info.data_storage_type=VFF_TYP_1_BYTE;
1002 packets=viff_info.number_data_bands*number_pixels;
1003 }
1004 else
1005 {
1006 viff_info.number_data_bands=1;
1007 viff_info.color_space_model=VFF_CM_NONE;
1008 viff_info.data_storage_type=VFF_TYP_1_BYTE;
1009 packets=number_pixels;
dirkf1d85482015-04-06 00:36:00 +00001010 if (SetImageGray(image,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001011 {
1012 /*
1013 Colormapped VIFF raster.
1014 */
1015 viff_info.map_scheme=VFF_MS_ONEPERBAND;
1016 viff_info.map_storage_type=VFF_MAPTYP_1_BYTE;
1017 viff_info.map_rows=3;
cristy0b29b252010-05-30 01:59:46 +00001018 viff_info.map_columns=(unsigned int) image->colors;
cristy3ed852e2009-09-05 21:47:34 +00001019 }
1020 else
1021 if (image->colors <= 2)
1022 {
1023 /*
1024 Monochrome VIFF raster.
1025 */
1026 viff_info.data_storage_type=VFF_TYP_BIT;
1027 packets=((image->columns+7) >> 3)*image->rows;
1028 }
1029 }
1030 /*
1031 Write VIFF image header (pad to 1024 bytes).
1032 */
cristy0f18a502014-11-28 14:16:00 +00001033 (void) WriteBlob(image,sizeof(viff_info.identifier),(unsigned char *)
1034 &viff_info.identifier);
1035 (void) WriteBlob(image,sizeof(viff_info.file_type),(unsigned char *)
1036 &viff_info.file_type);
1037 (void) WriteBlob(image,sizeof(viff_info.release),(unsigned char *)
1038 &viff_info.release);
1039 (void) WriteBlob(image,sizeof(viff_info.version),(unsigned char *)
1040 &viff_info.version);
1041 (void) WriteBlob(image,sizeof(viff_info.machine_dependency),
1042 (unsigned char *) &viff_info.machine_dependency);
1043 (void) WriteBlob(image,sizeof(viff_info.reserve),(unsigned char *)
1044 viff_info.reserve);
cristy3ed852e2009-09-05 21:47:34 +00001045 (void) WriteBlob(image,512,(unsigned char *) viff_info.comment);
cristy0b29b252010-05-30 01:59:46 +00001046 (void) WriteBlobMSBLong(image,(unsigned int) viff_info.rows);
1047 (void) WriteBlobMSBLong(image,(unsigned int) viff_info.columns);
cristyf6fe0a12010-05-30 00:44:47 +00001048 (void) WriteBlobMSBLong(image,(unsigned int) viff_info.subrows);
1049 (void) WriteBlobMSBLong(image,(unsigned int) viff_info.x_offset);
1050 (void) WriteBlobMSBLong(image,(unsigned int) viff_info.y_offset);
cristy0f18a502014-11-28 14:16:00 +00001051 viff_info.x_bits_per_pixel=(unsigned int) ((63 << 24) | (128 << 16));
cristyf6fe0a12010-05-30 00:44:47 +00001052 (void) WriteBlobMSBLong(image,(unsigned int) viff_info.x_bits_per_pixel);
cristy0f18a502014-11-28 14:16:00 +00001053 viff_info.y_bits_per_pixel=(unsigned int) ((63 << 24) | (128 << 16));
cristyf6fe0a12010-05-30 00:44:47 +00001054 (void) WriteBlobMSBLong(image,(unsigned int) viff_info.y_bits_per_pixel);
cristy3ed852e2009-09-05 21:47:34 +00001055 (void) WriteBlobMSBLong(image,viff_info.location_type);
1056 (void) WriteBlobMSBLong(image,viff_info.location_dimension);
cristyf6fe0a12010-05-30 00:44:47 +00001057 (void) WriteBlobMSBLong(image,(unsigned int) viff_info.number_of_images);
1058 (void) WriteBlobMSBLong(image,(unsigned int) viff_info.number_data_bands);
1059 (void) WriteBlobMSBLong(image,(unsigned int) viff_info.data_storage_type);
1060 (void) WriteBlobMSBLong(image,(unsigned int) viff_info.data_encode_scheme);
1061 (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_scheme);
1062 (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_storage_type);
1063 (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_rows);
1064 (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_columns);
1065 (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_subrows);
1066 (void) WriteBlobMSBLong(image,(unsigned int) viff_info.map_enable);
1067 (void) WriteBlobMSBLong(image,(unsigned int) viff_info.maps_per_cycle);
1068 (void) WriteBlobMSBLong(image,(unsigned int) viff_info.color_space_model);
cristy3ed852e2009-09-05 21:47:34 +00001069 for (i=0; i < 420; i++)
1070 (void) WriteBlobByte(image,'\0');
1071 /*
1072 Convert MIFF to VIFF raster pixels.
1073 */
cristy5def2032013-06-30 17:44:08 +00001074 pixel_info=AcquireVirtualMemory((size_t) packets,sizeof(*pixels));
1075 if (pixel_info == (MemoryInfo *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001076 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
cristy5def2032013-06-30 17:44:08 +00001077 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
1078 q=pixels;
cristy3ed852e2009-09-05 21:47:34 +00001079 if (image->storage_class == DirectClass)
1080 {
1081 /*
1082 Convert DirectClass packet to VIFF RGB pixel.
1083 */
1084 number_pixels=(MagickSizeType) image->columns*image->rows;
cristybb503372010-05-27 20:51:26 +00001085 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001086 {
cristy3a37efd2011-08-28 20:31:03 +00001087 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001088 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001089 break;
cristybb503372010-05-27 20:51:26 +00001090 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001091 {
cristy4c08aed2011-07-01 19:47:50 +00001092 *q=ScaleQuantumToChar(GetPixelRed(image,p));
1093 *(q+number_pixels)=ScaleQuantumToChar(GetPixelGreen(image,p));
1094 *(q+number_pixels*2)=ScaleQuantumToChar(GetPixelBlue(image,p));
cristy17f11b02014-12-20 19:37:04 +00001095 if (image->alpha_trait != UndefinedPixelTrait)
cristy3ed852e2009-09-05 21:47:34 +00001096 *(q+number_pixels*3)=ScaleQuantumToChar((Quantum)
cristy4c08aed2011-07-01 19:47:50 +00001097 (GetPixelAlpha(image,p)));
cristyed231572011-07-14 02:18:59 +00001098 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001099 q++;
1100 }
1101 if (image->previous == (Image *) NULL)
1102 {
cristycee97112010-05-28 00:44:52 +00001103 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1104 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001105 if (status == MagickFalse)
1106 break;
1107 }
1108 }
1109 }
1110 else
dirkf1d85482015-04-06 00:36:00 +00001111 if (SetImageGray(image,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001112 {
1113 unsigned char
1114 *viff_colormap;
1115
1116 /*
1117 Dump colormap to file.
1118 */
1119 viff_colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
1120 3*sizeof(*viff_colormap));
1121 if (viff_colormap == (unsigned char *) NULL)
1122 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1123 q=viff_colormap;
cristybb503372010-05-27 20:51:26 +00001124 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00001125 *q++=ScaleQuantumToChar(image->colormap[i].red);
cristybb503372010-05-27 20:51:26 +00001126 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00001127 *q++=ScaleQuantumToChar(image->colormap[i].green);
cristybb503372010-05-27 20:51:26 +00001128 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00001129 *q++=ScaleQuantumToChar(image->colormap[i].blue);
1130 (void) WriteBlob(image,3*image->colors,viff_colormap);
1131 viff_colormap=(unsigned char *) RelinquishMagickMemory(viff_colormap);
1132 /*
1133 Convert PseudoClass packet to VIFF colormapped pixels.
1134 */
cristy5def2032013-06-30 17:44:08 +00001135 q=pixels;
cristybb503372010-05-27 20:51:26 +00001136 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001137 {
cristy3a37efd2011-08-28 20:31:03 +00001138 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001139 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001140 break;
cristybb503372010-05-27 20:51:26 +00001141 for (x=0; x < (ssize_t) image->columns; x++)
cristy4c08aed2011-07-01 19:47:50 +00001142 {
1143 *q++=(unsigned char) GetPixelIndex(image,p);
cristyed231572011-07-14 02:18:59 +00001144 p+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +00001145 }
cristy3ed852e2009-09-05 21:47:34 +00001146 if (image->previous == (Image *) NULL)
1147 {
cristycee97112010-05-28 00:44:52 +00001148 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1149 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001150 if (status == MagickFalse)
1151 break;
1152 }
1153 }
1154 }
1155 else
1156 if (image->colors <= 2)
1157 {
cristybb503372010-05-27 20:51:26 +00001158 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001159 x,
1160 y;
1161
1162 register unsigned char
1163 bit,
1164 byte;
1165
1166 /*
1167 Convert PseudoClass image to a VIFF monochrome image.
1168 */
cristy018f07f2011-09-04 21:15:19 +00001169 (void) SetImageType(image,BilevelType,exception);
cristybb503372010-05-27 20:51:26 +00001170 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001171 {
cristy3a37efd2011-08-28 20:31:03 +00001172 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001173 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001174 break;
cristy3ed852e2009-09-05 21:47:34 +00001175 bit=0;
1176 byte=0;
cristybb503372010-05-27 20:51:26 +00001177 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001178 {
1179 byte>>=1;
cristyd0323222013-04-07 16:13:21 +00001180 if (GetPixelLuma(image,p) < (QuantumRange/2.0))
cristy3ed852e2009-09-05 21:47:34 +00001181 byte|=0x80;
1182 bit++;
1183 if (bit == 8)
1184 {
1185 *q++=byte;
1186 bit=0;
1187 byte=0;
1188 }
cristyed231572011-07-14 02:18:59 +00001189 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001190 }
1191 if (bit != 0)
1192 *q++=byte >> (8-bit);
1193 if (image->previous == (Image *) NULL)
1194 {
cristy5d89f432010-05-30 00:00:26 +00001195 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1196 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001197 if (status == MagickFalse)
1198 break;
1199 }
1200 }
1201 }
1202 else
1203 {
1204 /*
1205 Convert PseudoClass packet to VIFF grayscale pixel.
1206 */
cristybb503372010-05-27 20:51:26 +00001207 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001208 {
cristy3a37efd2011-08-28 20:31:03 +00001209 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00001210 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001211 break;
cristybb503372010-05-27 20:51:26 +00001212 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001213 {
cristyd0323222013-04-07 16:13:21 +00001214 *q++=(unsigned char) ClampToQuantum(GetPixelLuma(image,p));
cristyed231572011-07-14 02:18:59 +00001215 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001216 }
1217 if (image->previous == (Image *) NULL)
1218 {
cristy5d89f432010-05-30 00:00:26 +00001219 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
1220 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001221 if (status == MagickFalse)
1222 break;
1223 }
1224 }
1225 }
cristy5def2032013-06-30 17:44:08 +00001226 (void) WriteBlob(image,(size_t) packets,pixels);
1227 pixel_info=RelinquishVirtualMemory(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +00001228 if (GetNextImageInList(image) == (Image *) NULL)
1229 break;
1230 image=SyncNextImageInList(image);
1231 status=SetImageProgress(image,SaveImagesTag,scene++,
1232 GetImageListLength(image));
1233 if (status == MagickFalse)
1234 break;
1235 } while (image_info->adjoin != MagickFalse);
1236 (void) CloseBlob(image);
1237 return(MagickTrue);
1238}