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