1/* 2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3% % 4% % 5% % 6% CCCC IIIII N N % 7% C I NN N % 8% C I N N N % 9% C I N NN % 10% CCCC IIIII N N % 11% % 12% % 13% Read/Write Kodak Cineon Image Format % 14% Cineon Image Format is a subset of SMTPE CIN % 15% % 16% % 17% Software Design % 18% Cristy % 19% Kelly Bergougnoux % 20% October 2003 % 21% % 22% % 23% Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization % 24% dedicated to making software imaging solutions freely available. % 25% % 26% You may not use this file except in compliance with the License. You may % 27% obtain a copy of the License at % 28% % 29% http://www.imagemagick.org/script/license.php % 30% % 31% Unless required by applicable law or agreed to in writing, software % 32% distributed under the License is distributed on an "AS IS" BASIS, % 33% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 34% See the License for the specific language governing permissions and % 35% limitations under the License. % 36% % 37% % 38%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 39% 40% Cineon image file format draft is available at 41% http://www.cineon.com/ff_draft.php. 42% 43% 44*/ 45 46/* 47 Include declarations. 48*/ 49#include "MagickCore/studio.h" 50#include "MagickCore/artifact.h" 51#include "MagickCore/blob.h" 52#include "MagickCore/blob-private.h" 53#include "MagickCore/cache.h" 54#include "MagickCore/colorspace.h" 55#include "MagickCore/exception.h" 56#include "MagickCore/exception-private.h" 57#include "MagickCore/image.h" 58#include "MagickCore/image-private.h" 59#include "MagickCore/list.h" 60#include "MagickCore/magick.h" 61#include "MagickCore/memory_.h" 62#include "MagickCore/monitor.h" 63#include "MagickCore/monitor-private.h" 64#include "MagickCore/option.h" 65#include "MagickCore/profile.h" 66#include "MagickCore/property.h" 67#include "MagickCore/quantum-private.h" 68#include "MagickCore/quantum-private.h" 69#include "MagickCore/static.h" 70#include "MagickCore/string_.h" 71#include "MagickCore/string-private.h" 72#include "MagickCore/module.h" 73 74/* 75 Typedef declaration. 76*/ 77typedef struct _CINDataFormatInfo 78{ 79 unsigned char 80 interleave, 81 packing, 82 sign, 83 sense; 84 85 size_t 86 line_pad, 87 channel_pad; 88 89 unsigned char 90 reserve[20]; 91} CINDataFormatInfo; 92 93typedef struct _CINFileInfo 94{ 95 size_t 96 magic, 97 image_offset, 98 generic_length, 99 industry_length, 100 user_length, 101 file_size; 102 103 char 104 version[8], 105 filename[100], 106 create_date[12], 107 create_time[12], 108 reserve[36]; 109} CINFileInfo; 110 111typedef struct _CINFilmInfo 112{ 113 char 114 id, 115 type, 116 offset, 117 reserve1; 118 119 size_t 120 prefix, 121 count; 122 123 char 124 format[32]; 125 126 size_t 127 frame_position; 128 129 float 130 frame_rate; 131 132 char 133 frame_id[32], 134 slate_info[200], 135 reserve[740]; 136} CINFilmInfo; 137 138typedef struct _CINImageChannel 139{ 140 unsigned char 141 designator[2], 142 bits_per_pixel, 143 reserve; 144 145 size_t 146 pixels_per_line, 147 lines_per_image; 148 149 float 150 min_data, 151 min_quantity, 152 max_data, 153 max_quantity; 154} CINImageChannel; 155 156typedef struct _CINImageInfo 157{ 158 unsigned char 159 orientation, 160 number_channels, 161 reserve1[2]; 162 163 CINImageChannel 164 channel[8]; 165 166 float 167 white_point[2], 168 red_primary_chromaticity[2], 169 green_primary_chromaticity[2], 170 blue_primary_chromaticity[2]; 171 172 char 173 label[200], 174 reserve[28]; 175} CINImageInfo; 176 177typedef struct _CINOriginationInfo 178{ 179 ssize_t 180 x_offset, 181 y_offset; 182 183 char 184 filename[100], 185 create_date[12], 186 create_time[12], 187 device[64], 188 model[32], 189 serial[32]; 190 191 float 192 x_pitch, 193 y_pitch, 194 gamma; 195 196 char 197 reserve[40]; 198} CINOriginationInfo; 199 200typedef struct _CINUserInfo 201{ 202 char 203 id[32]; 204} CINUserInfo; 205 206typedef struct CINInfo 207{ 208 CINFileInfo 209 file; 210 211 CINImageInfo 212 image; 213 214 CINDataFormatInfo 215 data_format; 216 217 CINOriginationInfo 218 origination; 219 220 CINFilmInfo 221 film; 222 223 CINUserInfo 224 user; 225} CINInfo; 226 227/* 228 Forward declaractions. 229*/ 230static MagickBooleanType 231 WriteCINImage(const ImageInfo *,Image *,ExceptionInfo *); 232 233/* 234%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 235% % 236% % 237% % 238% I s C I N E O N % 239% % 240% % 241% % 242%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 243% 244% IsCIN() returns MagickTrue if the image format type, identified by the magick 245% string, is CIN. 246% 247% The format of the IsCIN method is: 248% 249% MagickBooleanType IsCIN(const unsigned char *magick,const size_t length) 250% 251% A description of each parameter follows: 252% 253% o magick: compare image format pattern against these bytes. 254% 255% o length: Specifies the length of the magick string. 256% 257*/ 258static MagickBooleanType IsCIN(const unsigned char *magick,const size_t length) 259{ 260 if (length < 4) 261 return(MagickFalse); 262 if (memcmp(magick,"\200\052\137\327",4) == 0) 263 return(MagickTrue); 264 return(MagickFalse); 265} 266 267/* 268%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 269% % 270% % 271% % 272% R e a d C I N E O N I m a g e % 273% % 274% % 275% % 276%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 277% 278% ReadCINImage() reads an CIN X image file and returns it. It allocates 279% the memory necessary for the new Image structure and returns a point to the 280% new image. 281% 282% The format of the ReadCINImage method is: 283% 284% Image *ReadCINImage(const ImageInfo *image_info, 285% ExceptionInfo *exception) 286% 287% A description of each parameter follows: 288% 289% o image_info: the image info. 290% 291% o exception: return any errors or warnings in this structure. 292% 293*/ 294 295static size_t GetBytesPerRow(size_t columns, 296 size_t samples_per_pixel,size_t bits_per_pixel, 297 MagickBooleanType pad) 298{ 299 size_t 300 bytes_per_row; 301 302 switch (bits_per_pixel) 303 { 304 case 1: 305 { 306 bytes_per_row=4*(((size_t) samples_per_pixel*columns* 307 bits_per_pixel+31)/32); 308 break; 309 } 310 case 8: 311 default: 312 { 313 bytes_per_row=4*(((size_t) samples_per_pixel*columns* 314 bits_per_pixel+31)/32); 315 break; 316 } 317 case 10: 318 { 319 if (pad == MagickFalse) 320 { 321 bytes_per_row=4*(((size_t) samples_per_pixel*columns* 322 bits_per_pixel+31)/32); 323 break; 324 } 325 bytes_per_row=4*(((size_t) (32*((samples_per_pixel*columns+2)/3))+31)/32); 326 break; 327 } 328 case 12: 329 { 330 if (pad == MagickFalse) 331 { 332 bytes_per_row=4*(((size_t) samples_per_pixel*columns* 333 bits_per_pixel+31)/32); 334 break; 335 } 336 bytes_per_row=2*(((size_t) (16*samples_per_pixel*columns)+15)/16); 337 break; 338 } 339 case 16: 340 { 341 bytes_per_row=2*(((size_t) samples_per_pixel*columns* 342 bits_per_pixel+8)/16); 343 break; 344 } 345 case 32: 346 { 347 bytes_per_row=4*(((size_t) samples_per_pixel*columns* 348 bits_per_pixel+31)/32); 349 break; 350 } 351 case 64: 352 { 353 bytes_per_row=8*(((size_t) samples_per_pixel*columns* 354 bits_per_pixel+63)/64); 355 break; 356 } 357 } 358 return(bytes_per_row); 359} 360 361static inline MagickBooleanType IsFloatDefined(const float value) 362{ 363 union 364 { 365 unsigned int 366 unsigned_value; 367 368 double 369 float_value; 370 } quantum; 371 372 quantum.unsigned_value=0U; 373 quantum.float_value=value; 374 if (quantum.unsigned_value == 0U) 375 return(MagickFalse); 376 return(MagickTrue); 377} 378 379static Image *ReadCINImage(const ImageInfo *image_info,ExceptionInfo *exception) 380{ 381#define MonoColorType 1 382#define RGBColorType 3 383 384 char 385 property[MagickPathExtent]; 386 387 CINInfo 388 cin; 389 390 const unsigned char 391 *pixels; 392 393 Image 394 *image; 395 396 MagickBooleanType 397 status; 398 399 MagickOffsetType 400 offset; 401 402 QuantumInfo 403 *quantum_info; 404 405 QuantumType 406 quantum_type; 407 408 register ssize_t 409 i; 410 411 register Quantum 412 *q; 413 414 size_t 415 length; 416 417 ssize_t 418 count, 419 y; 420 421 unsigned char 422 magick[4]; 423 424 /* 425 Open image file. 426 */ 427 assert(image_info != (const ImageInfo *) NULL); 428 assert(image_info->signature == MagickCoreSignature); 429 if (image_info->debug != MagickFalse) 430 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 431 image_info->filename); 432 assert(exception != (ExceptionInfo *) NULL); 433 assert(exception->signature == MagickCoreSignature); 434 image=AcquireImage(image_info,exception); 435 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 436 if (status == MagickFalse) 437 { 438 image=DestroyImageList(image); 439 return((Image *) NULL); 440 } 441 /* 442 File information. 443 */ 444 offset=0; 445 count=ReadBlob(image,4,magick); 446 offset+=count; 447 if ((count != 4) || 448 ((LocaleNCompare((char *) magick,"\200\052\137\327",4) != 0))) 449 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 450 image->endian=(magick[0] == 0x80) && (magick[1] == 0x2a) && 451 (magick[2] == 0x5f) && (magick[3] == 0xd7) ? MSBEndian : LSBEndian; 452 cin.file.image_offset=ReadBlobLong(image); 453 offset+=4; 454 cin.file.generic_length=ReadBlobLong(image); 455 offset+=4; 456 cin.file.industry_length=ReadBlobLong(image); 457 offset+=4; 458 cin.file.user_length=ReadBlobLong(image); 459 offset+=4; 460 cin.file.file_size=ReadBlobLong(image); 461 offset+=4; 462 offset+=ReadBlob(image,sizeof(cin.file.version),(unsigned char *) 463 cin.file.version); 464 (void) CopyMagickString(property,cin.file.version,sizeof(cin.file.version)); 465 (void) SetImageProperty(image,"dpx:file.version",property,exception); 466 offset+=ReadBlob(image,sizeof(cin.file.filename),(unsigned char *) 467 cin.file.filename); 468 (void) CopyMagickString(property,cin.file.filename,sizeof(cin.file.filename)); 469 (void) SetImageProperty(image,"dpx:file.filename",property,exception); 470 offset+=ReadBlob(image,sizeof(cin.file.create_date),(unsigned char *) 471 cin.file.create_date); 472 (void) CopyMagickString(property,cin.file.create_date, 473 sizeof(cin.file.create_date)); 474 (void) SetImageProperty(image,"dpx:file.create_date",property,exception); 475 offset+=ReadBlob(image,sizeof(cin.file.create_time),(unsigned char *) 476 cin.file.create_time); 477 (void) CopyMagickString(property,cin.file.create_time, 478 sizeof(cin.file.create_time)); 479 (void) SetImageProperty(image,"dpx:file.create_time",property,exception); 480 offset+=ReadBlob(image,sizeof(cin.file.reserve),(unsigned char *) 481 cin.file.reserve); 482 /* 483 Image information. 484 */ 485 cin.image.orientation=(unsigned char) ReadBlobByte(image); 486 offset++; 487 if (cin.image.orientation != (unsigned char) (~0)) 488 (void) FormatImageProperty(image,"dpx:image.orientation","%d", 489 cin.image.orientation); 490 switch (cin.image.orientation) 491 { 492 default: 493 case 0: image->orientation=TopLeftOrientation; break; 494 case 1: image->orientation=TopRightOrientation; break; 495 case 2: image->orientation=BottomLeftOrientation; break; 496 case 3: image->orientation=BottomRightOrientation; break; 497 case 4: image->orientation=LeftTopOrientation; break; 498 case 5: image->orientation=RightTopOrientation; break; 499 case 6: image->orientation=LeftBottomOrientation; break; 500 case 7: image->orientation=RightBottomOrientation; break; 501 } 502 cin.image.number_channels=(unsigned char) ReadBlobByte(image); 503 offset++; 504 offset+=ReadBlob(image,sizeof(cin.image.reserve1),(unsigned char *) 505 cin.image.reserve1); 506 for (i=0; i < 8; i++) 507 { 508 cin.image.channel[i].designator[0]=(unsigned char) ReadBlobByte(image); 509 offset++; 510 cin.image.channel[i].designator[1]=(unsigned char) ReadBlobByte(image); 511 offset++; 512 cin.image.channel[i].bits_per_pixel=(unsigned char) ReadBlobByte(image); 513 offset++; 514 cin.image.channel[i].reserve=(unsigned char) ReadBlobByte(image); 515 offset++; 516 cin.image.channel[i].pixels_per_line=ReadBlobLong(image); 517 offset+=4; 518 cin.image.channel[i].lines_per_image=ReadBlobLong(image); 519 offset+=4; 520 cin.image.channel[i].min_data=ReadBlobFloat(image); 521 offset+=4; 522 cin.image.channel[i].min_quantity=ReadBlobFloat(image); 523 offset+=4; 524 cin.image.channel[i].max_data=ReadBlobFloat(image); 525 offset+=4; 526 cin.image.channel[i].max_quantity=ReadBlobFloat(image); 527 offset+=4; 528 } 529 cin.image.white_point[0]=ReadBlobFloat(image); 530 offset+=4; 531 if (IsFloatDefined(cin.image.white_point[0]) != MagickFalse) 532 image->chromaticity.white_point.x=cin.image.white_point[0]; 533 cin.image.white_point[1]=ReadBlobFloat(image); 534 offset+=4; 535 if (IsFloatDefined(cin.image.white_point[1]) != MagickFalse) 536 image->chromaticity.white_point.y=cin.image.white_point[1]; 537 cin.image.red_primary_chromaticity[0]=ReadBlobFloat(image); 538 offset+=4; 539 if (IsFloatDefined(cin.image.red_primary_chromaticity[0]) != MagickFalse) 540 image->chromaticity.red_primary.x=cin.image.red_primary_chromaticity[0]; 541 cin.image.red_primary_chromaticity[1]=ReadBlobFloat(image); 542 offset+=4; 543 if (IsFloatDefined(cin.image.red_primary_chromaticity[1]) != MagickFalse) 544 image->chromaticity.red_primary.y=cin.image.red_primary_chromaticity[1]; 545 cin.image.green_primary_chromaticity[0]=ReadBlobFloat(image); 546 offset+=4; 547 if (IsFloatDefined(cin.image.green_primary_chromaticity[0]) != MagickFalse) 548 image->chromaticity.red_primary.x=cin.image.green_primary_chromaticity[0]; 549 cin.image.green_primary_chromaticity[1]=ReadBlobFloat(image); 550 offset+=4; 551 if (IsFloatDefined(cin.image.green_primary_chromaticity[1]) != MagickFalse) 552 image->chromaticity.green_primary.y=cin.image.green_primary_chromaticity[1]; 553 cin.image.blue_primary_chromaticity[0]=ReadBlobFloat(image); 554 offset+=4; 555 if (IsFloatDefined(cin.image.blue_primary_chromaticity[0]) != MagickFalse) 556 image->chromaticity.blue_primary.x=cin.image.blue_primary_chromaticity[0]; 557 cin.image.blue_primary_chromaticity[1]=ReadBlobFloat(image); 558 offset+=4; 559 if (IsFloatDefined(cin.image.blue_primary_chromaticity[1]) != MagickFalse) 560 image->chromaticity.blue_primary.y=cin.image.blue_primary_chromaticity[1]; 561 offset+=ReadBlob(image,sizeof(cin.image.label),(unsigned char *) 562 cin.image.label); 563 (void) CopyMagickString(property,cin.image.label,sizeof(cin.image.label)); 564 (void) SetImageProperty(image,"dpx:image.label",property,exception); 565 offset+=ReadBlob(image,sizeof(cin.image.reserve),(unsigned char *) 566 cin.image.reserve); 567 /* 568 Image data format information. 569 */ 570 cin.data_format.interleave=(unsigned char) ReadBlobByte(image); 571 offset++; 572 cin.data_format.packing=(unsigned char) ReadBlobByte(image); 573 offset++; 574 cin.data_format.sign=(unsigned char) ReadBlobByte(image); 575 offset++; 576 cin.data_format.sense=(unsigned char) ReadBlobByte(image); 577 offset++; 578 cin.data_format.line_pad=ReadBlobLong(image); 579 offset+=4; 580 cin.data_format.channel_pad=ReadBlobLong(image); 581 offset+=4; 582 offset+=ReadBlob(image,sizeof(cin.data_format.reserve),(unsigned char *) 583 cin.data_format.reserve); 584 /* 585 Image origination information. 586 */ 587 cin.origination.x_offset=ReadBlobSignedLong(image); 588 offset+=4; 589 if ((size_t) cin.origination.x_offset != ~0UL) 590 (void) FormatImageProperty(image,"dpx:origination.x_offset","%.20g", 591 (double) cin.origination.x_offset); 592 cin.origination.y_offset=(ssize_t) ReadBlobLong(image); 593 offset+=4; 594 if ((size_t) cin.origination.y_offset != ~0UL) 595 (void) FormatImageProperty(image,"dpx:origination.y_offset","%.20g", 596 (double) cin.origination.y_offset); 597 offset+=ReadBlob(image,sizeof(cin.origination.filename),(unsigned char *) 598 cin.origination.filename); 599 (void) CopyMagickString(property,cin.origination.filename, 600 sizeof(cin.origination.filename)); 601 (void) SetImageProperty(image,"dpx:origination.filename",property,exception); 602 offset+=ReadBlob(image,sizeof(cin.origination.create_date),(unsigned char *) 603 cin.origination.create_date); 604 (void) CopyMagickString(property,cin.origination.create_date, 605 sizeof(cin.origination.create_date)); 606 (void) SetImageProperty(image,"dpx:origination.create_date",property, 607 exception); 608 offset+=ReadBlob(image,sizeof(cin.origination.create_time),(unsigned char *) 609 cin.origination.create_time); 610 (void) CopyMagickString(property,cin.origination.create_time, 611 sizeof(cin.origination.create_time)); 612 (void) SetImageProperty(image,"dpx:origination.create_time",property, 613 exception); 614 offset+=ReadBlob(image,sizeof(cin.origination.device),(unsigned char *) 615 cin.origination.device); 616 (void) CopyMagickString(property,cin.origination.device, 617 sizeof(cin.origination.device)); 618 (void) SetImageProperty(image,"dpx:origination.device",property,exception); 619 offset+=ReadBlob(image,sizeof(cin.origination.model),(unsigned char *) 620 cin.origination.model); 621 (void) CopyMagickString(property,cin.origination.model, 622 sizeof(cin.origination.model)); 623 (void) SetImageProperty(image,"dpx:origination.model",property,exception); 624 (void) ResetMagickMemory(cin.origination.serial,0, 625 sizeof(cin.origination.serial)); 626 offset+=ReadBlob(image,sizeof(cin.origination.serial),(unsigned char *) 627 cin.origination.serial); 628 (void) CopyMagickString(property,cin.origination.serial, 629 sizeof(cin.origination.serial)); 630 (void) SetImageProperty(image,"dpx:origination.serial",property,exception); 631 cin.origination.x_pitch=ReadBlobFloat(image); 632 offset+=4; 633 cin.origination.y_pitch=ReadBlobFloat(image); 634 offset+=4; 635 cin.origination.gamma=ReadBlobFloat(image); 636 offset+=4; 637 if (IsFloatDefined(cin.origination.gamma) != MagickFalse) 638 image->gamma=cin.origination.gamma; 639 offset+=ReadBlob(image,sizeof(cin.origination.reserve),(unsigned char *) 640 cin.origination.reserve); 641 if ((cin.file.image_offset > 2048) && (cin.file.user_length != 0)) 642 { 643 int 644 c; 645 646 /* 647 Image film information. 648 */ 649 cin.film.id=ReadBlobByte(image); 650 offset++; 651 c=cin.film.id; 652 if (c != ~0) 653 (void) FormatImageProperty(image,"dpx:film.id","%d",cin.film.id); 654 cin.film.type=ReadBlobByte(image); 655 offset++; 656 c=cin.film.type; 657 if (c != ~0) 658 (void) FormatImageProperty(image,"dpx:film.type","%d",cin.film.type); 659 cin.film.offset=ReadBlobByte(image); 660 offset++; 661 c=cin.film.offset; 662 if (c != ~0) 663 (void) FormatImageProperty(image,"dpx:film.offset","%d", 664 cin.film.offset); 665 cin.film.reserve1=ReadBlobByte(image); 666 offset++; 667 cin.film.prefix=ReadBlobLong(image); 668 offset+=4; 669 if (cin.film.prefix != ~0UL) 670 (void) FormatImageProperty(image,"dpx:film.prefix","%.20g",(double) 671 cin.film.prefix); 672 cin.film.count=ReadBlobLong(image); 673 offset+=4; 674 offset+=ReadBlob(image,sizeof(cin.film.format),(unsigned char *) 675 cin.film.format); 676 (void) CopyMagickString(property,cin.film.format,sizeof(cin.film.format)); 677 (void) SetImageProperty(image,"dpx:film.format",property,exception); 678 cin.film.frame_position=ReadBlobLong(image); 679 offset+=4; 680 if (cin.film.frame_position != ~0UL) 681 (void) FormatImageProperty(image,"dpx:film.frame_position","%.20g", 682 (double) cin.film.frame_position); 683 cin.film.frame_rate=ReadBlobFloat(image); 684 offset+=4; 685 if (IsFloatDefined(cin.film.frame_rate) != MagickFalse) 686 (void) FormatImageProperty(image,"dpx:film.frame_rate","%g", 687 cin.film.frame_rate); 688 offset+=ReadBlob(image,sizeof(cin.film.frame_id),(unsigned char *) 689 cin.film.frame_id); 690 (void) CopyMagickString(property,cin.film.frame_id, 691 sizeof(cin.film.frame_id)); 692 (void) SetImageProperty(image,"dpx:film.frame_id",property,exception); 693 offset+=ReadBlob(image,sizeof(cin.film.slate_info),(unsigned char *) 694 cin.film.slate_info); 695 (void) CopyMagickString(property,cin.film.slate_info, 696 sizeof(cin.film.slate_info)); 697 (void) SetImageProperty(image,"dpx:film.slate_info",property,exception); 698 offset+=ReadBlob(image,sizeof(cin.film.reserve),(unsigned char *) 699 cin.film.reserve); 700 } 701 if ((cin.file.image_offset > 2048) && (cin.file.user_length != 0)) 702 { 703 StringInfo 704 *profile; 705 706 /* 707 User defined data. 708 */ 709 profile=BlobToStringInfo((const unsigned char *) NULL,cin.file.user_length); 710 if (profile == (StringInfo *) NULL) 711 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 712 offset+=ReadBlob(image,GetStringInfoLength(profile), 713 GetStringInfoDatum(profile)); 714 (void) SetImageProfile(image,"dpx:user.data",profile,exception); 715 profile=DestroyStringInfo(profile); 716 } 717 image->depth=cin.image.channel[0].bits_per_pixel; 718 image->columns=cin.image.channel[0].pixels_per_line; 719 image->rows=cin.image.channel[0].lines_per_image; 720 if (image_info->ping != MagickFalse) 721 { 722 (void) CloseBlob(image); 723 return(image); 724 } 725 for ( ; offset < (MagickOffsetType) cin.file.image_offset; offset++) 726 { 727 int 728 c; 729 730 c=ReadBlobByte(image); 731 if (c == EOF) 732 break; 733 } 734 if (offset < (MagickOffsetType) cin.file.image_offset) 735 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 736 status=SetImageExtent(image,image->columns,image->rows,exception); 737 if (status == MagickFalse) 738 return(DestroyImageList(image)); 739 /* 740 Convert CIN raster image to pixel packets. 741 */ 742 quantum_info=AcquireQuantumInfo(image_info,image); 743 if (quantum_info == (QuantumInfo *) NULL) 744 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 745 quantum_info->quantum=32; 746 quantum_info->pack=MagickFalse; 747 quantum_type=RGBQuantum; 748 length=GetQuantumExtent(image,quantum_info,quantum_type); 749 length=GetBytesPerRow(image->columns,3,image->depth,MagickTrue); 750 if (cin.image.number_channels == 1) 751 { 752 quantum_type=GrayQuantum; 753 length=GetBytesPerRow(image->columns,1,image->depth,MagickTrue); 754 } 755 for (y=0; y < (ssize_t) image->rows; y++) 756 { 757 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 758 if (q == (Quantum *) NULL) 759 break; 760 pixels=(const unsigned char *) ReadBlobStream(image,length, 761 GetQuantumPixels(quantum_info),&count); 762 if ((size_t) count != length) 763 break; 764 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info, 765 quantum_type,pixels,exception); 766 if (SyncAuthenticPixels(image,exception) == MagickFalse) 767 break; 768 if (image->previous == (Image *) NULL) 769 { 770 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, 771 image->rows); 772 if (status == MagickFalse) 773 break; 774 } 775 } 776 SetQuantumImageType(image,quantum_type); 777 quantum_info=DestroyQuantumInfo(quantum_info); 778 if (EOFBlob(image) != MagickFalse) 779 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", 780 image->filename); 781 SetImageColorspace(image,LogColorspace,exception); 782 (void) CloseBlob(image); 783 return(GetFirstImageInList(image)); 784} 785 786/* 787%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 788% % 789% % 790% % 791% R e g i s t e r C I N E O N I m a g e % 792% % 793% % 794% % 795%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 796% 797% RegisterCINImage() adds attributes for the CIN image format to the list of 798% of supported formats. The attributes include the image format tag, a method 799% to read and/or write the format, whether the format supports the saving of 800% more than one frame to the same file or blob, whether the format supports 801% native in-memory I/O, and a brief description of the format. 802% 803% The format of the RegisterCINImage method is: 804% 805% size_t RegisterCINImage(void) 806% 807*/ 808ModuleExport size_t RegisterCINImage(void) 809{ 810 MagickInfo 811 *entry; 812 813 entry=AcquireMagickInfo("CIN","CIN","Cineon Image File"); 814 entry->decoder=(DecodeImageHandler *) ReadCINImage; 815 entry->encoder=(EncodeImageHandler *) WriteCINImage; 816 entry->magick=(IsImageFormatHandler *) IsCIN; 817 entry->flags^=CoderAdjoinFlag; 818 (void) RegisterMagickInfo(entry); 819 return(MagickImageCoderSignature); 820} 821 822/* 823%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 824% % 825% % 826% % 827% U n r e g i s t e r C I N E O N I m a g e % 828% % 829% % 830% % 831%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 832% 833% UnregisterCINImage() removes format registrations made by the CIN module 834% from the list of supported formats. 835% 836% The format of the UnregisterCINImage method is: 837% 838% UnregisterCINImage(void) 839% 840*/ 841ModuleExport void UnregisterCINImage(void) 842{ 843 (void) UnregisterMagickInfo("CINEON"); 844} 845 846/* 847%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 848% % 849% % 850% % 851% W r i t e C I N E O N I m a g e % 852% % 853% % 854% % 855%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 856% 857% WriteCINImage() writes an image in CIN encoded image format. 858% 859% The format of the WriteCINImage method is: 860% 861% MagickBooleanType WriteCINImage(const ImageInfo *image_info, 862% Image *image,ExceptionInfo *exception) 863% 864% A description of each parameter follows. 865% 866% o image_info: the image info. 867% 868% o image: The image. 869% 870% o exception: return any errors or warnings in this structure. 871% 872*/ 873 874static inline const char *GetCINProperty(const ImageInfo *image_info, 875 const Image *image,const char *property,ExceptionInfo *exception) 876{ 877 const char 878 *value; 879 880 value=GetImageOption(image_info,property); 881 if (value != (const char *) NULL) 882 return(value); 883 return(GetImageProperty(image,property,exception)); 884} 885 886static MagickBooleanType WriteCINImage(const ImageInfo *image_info,Image *image, 887 ExceptionInfo *exception) 888{ 889 char 890 timestamp[MagickPathExtent]; 891 892 const char 893 *value; 894 895 CINInfo 896 cin; 897 898 const StringInfo 899 *profile; 900 901 MagickBooleanType 902 status; 903 904 MagickOffsetType 905 offset; 906 907 QuantumInfo 908 *quantum_info; 909 910 QuantumType 911 quantum_type; 912 913 register const Quantum 914 *p; 915 916 register ssize_t 917 i; 918 919 size_t 920 length; 921 922 ssize_t 923 count, 924 y; 925 926 struct tm 927 local_time; 928 929 time_t 930 seconds; 931 932 unsigned char 933 *pixels; 934 935 /* 936 Open output image file. 937 */ 938 assert(image_info != (const ImageInfo *) NULL); 939 assert(image_info->signature == MagickCoreSignature); 940 assert(image != (Image *) NULL); 941 assert(image->signature == MagickCoreSignature); 942 if (image->debug != MagickFalse) 943 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 944 assert(exception != (ExceptionInfo *) NULL); 945 assert(exception->signature == MagickCoreSignature); 946 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 947 if (status == MagickFalse) 948 return(status); 949 if (image->colorspace != LogColorspace) 950 (void) TransformImageColorspace(image,LogColorspace,exception); 951 /* 952 Write image information. 953 */ 954 (void) ResetMagickMemory(&cin,0,sizeof(cin)); 955 offset=0; 956 cin.file.magic=0x802A5FD7UL; 957 offset+=WriteBlobLong(image,(unsigned int) cin.file.magic); 958 cin.file.image_offset=0x800; 959 offset+=WriteBlobLong(image,(unsigned int) cin.file.image_offset); 960 cin.file.generic_length=0x400; 961 offset+=WriteBlobLong(image,(unsigned int) cin.file.generic_length); 962 cin.file.industry_length=0x400; 963 offset+=WriteBlobLong(image,(unsigned int) cin.file.industry_length); 964 cin.file.user_length=0x00; 965 profile=GetImageProfile(image,"dpx:user.data"); 966 if (profile != (StringInfo *) NULL) 967 { 968 cin.file.user_length+=(size_t) GetStringInfoLength(profile); 969 cin.file.user_length=(((cin.file.user_length+0x2000-1)/0x2000)*0x2000); 970 } 971 offset+=WriteBlobLong(image,(unsigned int) cin.file.user_length); 972 cin.file.file_size=4*image->columns*image->rows+0x2000; 973 offset+=WriteBlobLong(image,(unsigned int) cin.file.file_size); 974 (void) CopyMagickString(cin.file.version,"V4.5",sizeof(cin.file.version)); 975 offset+=WriteBlob(image,sizeof(cin.file.version),(unsigned char *) 976 cin.file.version); 977 value=GetCINProperty(image_info,image,"dpx:file.filename",exception); 978 if (value != (const char *) NULL) 979 (void) CopyMagickString(cin.file.filename,value,sizeof(cin.file.filename)); 980 else 981 (void) CopyMagickString(cin.file.filename,image->filename, 982 sizeof(cin.file.filename)); 983 offset+=WriteBlob(image,sizeof(cin.file.filename),(unsigned char *) 984 cin.file.filename); 985 seconds=time((time_t *) NULL); 986#if defined(MAGICKCORE_HAVE_LOCALTIME_R) 987 (void) localtime_r(&seconds,&local_time); 988#else 989 (void) memcpy(&local_time,localtime(&seconds),sizeof(local_time)); 990#endif 991 (void) memset(timestamp,0,sizeof(timestamp)); 992 (void) strftime(timestamp,MagickPathExtent,"%Y:%m:%d:%H:%M:%S%Z",&local_time); 993 (void) memset(cin.file.create_date,0,sizeof(cin.file.create_date)); 994 (void) CopyMagickString(cin.file.create_date,timestamp,11); 995 offset+=WriteBlob(image,sizeof(cin.file.create_date),(unsigned char *) 996 cin.file.create_date); 997 (void) memset(cin.file.create_time,0,sizeof(cin.file.create_time)); 998 (void) CopyMagickString(cin.file.create_time,timestamp+11,11); 999 offset+=WriteBlob(image,sizeof(cin.file.create_time),(unsigned char *) 1000 cin.file.create_time); 1001 offset+=WriteBlob(image,sizeof(cin.file.reserve),(unsigned char *) 1002 cin.file.reserve); 1003 cin.image.orientation=0x00; 1004 offset+=WriteBlobByte(image,cin.image.orientation); 1005 cin.image.number_channels=3; 1006 offset+=WriteBlobByte(image,cin.image.number_channels); 1007 offset+=WriteBlob(image,sizeof(cin.image.reserve1),(unsigned char *) 1008 cin.image.reserve1); 1009 for (i=0; i < 8; i++) 1010 { 1011 cin.image.channel[i].designator[0]=0; /* universal metric */ 1012 offset+=WriteBlobByte(image,cin.image.channel[0].designator[0]); 1013 cin.image.channel[i].designator[1]=(unsigned char) (i > 3 ? 0 : i+1); /* channel color */; 1014 offset+=WriteBlobByte(image,cin.image.channel[1].designator[0]); 1015 cin.image.channel[i].bits_per_pixel=(unsigned char) image->depth; 1016 offset+=WriteBlobByte(image,cin.image.channel[0].bits_per_pixel); 1017 offset+=WriteBlobByte(image,cin.image.channel[0].reserve); 1018 cin.image.channel[i].pixels_per_line=image->columns; 1019 offset+=WriteBlobLong(image,(unsigned int) 1020 cin.image.channel[0].pixels_per_line); 1021 cin.image.channel[i].lines_per_image=image->rows; 1022 offset+=WriteBlobLong(image,(unsigned int) 1023 cin.image.channel[0].lines_per_image); 1024 cin.image.channel[i].min_data=0; 1025 offset+=WriteBlobFloat(image,cin.image.channel[0].min_data); 1026 cin.image.channel[i].min_quantity=0.0; 1027 offset+=WriteBlobFloat(image,cin.image.channel[0].min_quantity); 1028 cin.image.channel[i].max_data=(float) ((MagickOffsetType) 1029 GetQuantumRange(image->depth)); 1030 offset+=WriteBlobFloat(image,cin.image.channel[0].max_data); 1031 cin.image.channel[i].max_quantity=2.048f; 1032 offset+=WriteBlobFloat(image,cin.image.channel[0].max_quantity); 1033 } 1034 offset+=WriteBlobFloat(image,image->chromaticity.white_point.x); 1035 offset+=WriteBlobFloat(image,image->chromaticity.white_point.y); 1036 offset+=WriteBlobFloat(image,image->chromaticity.red_primary.x); 1037 offset+=WriteBlobFloat(image,image->chromaticity.red_primary.y); 1038 offset+=WriteBlobFloat(image,image->chromaticity.green_primary.x); 1039 offset+=WriteBlobFloat(image,image->chromaticity.green_primary.y); 1040 offset+=WriteBlobFloat(image,image->chromaticity.blue_primary.x); 1041 offset+=WriteBlobFloat(image,image->chromaticity.blue_primary.y); 1042 value=GetCINProperty(image_info,image,"dpx:image.label",exception); 1043 if (value != (const char *) NULL) 1044 (void) CopyMagickString(cin.image.label,value,sizeof(cin.image.label)); 1045 offset+=WriteBlob(image,sizeof(cin.image.label),(unsigned char *) 1046 cin.image.label); 1047 offset+=WriteBlob(image,sizeof(cin.image.reserve),(unsigned char *) 1048 cin.image.reserve); 1049 /* 1050 Write data format information. 1051 */ 1052 cin.data_format.interleave=0; /* pixel interleave (rgbrgbr...) */ 1053 offset+=WriteBlobByte(image,cin.data_format.interleave); 1054 cin.data_format.packing=5; /* packing ssize_tword (32bit) boundaries */ 1055 offset+=WriteBlobByte(image,cin.data_format.packing); 1056 cin.data_format.sign=0; /* unsigned data */ 1057 offset+=WriteBlobByte(image,cin.data_format.sign); 1058 cin.data_format.sense=0; /* image sense: positive image */ 1059 offset+=WriteBlobByte(image,cin.data_format.sense); 1060 cin.data_format.line_pad=0; 1061 offset+=WriteBlobLong(image,(unsigned int) cin.data_format.line_pad); 1062 cin.data_format.channel_pad=0; 1063 offset+=WriteBlobLong(image,(unsigned int) cin.data_format.channel_pad); 1064 offset+=WriteBlob(image,sizeof(cin.data_format.reserve),(unsigned char *) 1065 cin.data_format.reserve); 1066 /* 1067 Write origination information. 1068 */ 1069 cin.origination.x_offset=0UL; 1070 value=GetCINProperty(image_info,image,"dpx:origination.x_offset",exception); 1071 if (value != (const char *) NULL) 1072 cin.origination.x_offset=(ssize_t) StringToLong(value); 1073 offset+=WriteBlobLong(image,(unsigned int) cin.origination.x_offset); 1074 cin.origination.y_offset=0UL; 1075 value=GetCINProperty(image_info,image,"dpx:origination.y_offset",exception); 1076 if (value != (const char *) NULL) 1077 cin.origination.y_offset=(ssize_t) StringToLong(value); 1078 offset+=WriteBlobLong(image,(unsigned int) cin.origination.y_offset); 1079 value=GetCINProperty(image_info,image,"dpx:origination.filename",exception); 1080 if (value != (const char *) NULL) 1081 (void) CopyMagickString(cin.origination.filename,value, 1082 sizeof(cin.origination.filename)); 1083 else 1084 (void) CopyMagickString(cin.origination.filename,image->filename, 1085 sizeof(cin.origination.filename)); 1086 offset+=WriteBlob(image,sizeof(cin.origination.filename),(unsigned char *) 1087 cin.origination.filename); 1088 seconds=time((time_t *) NULL); 1089 (void) memset(timestamp,0,sizeof(timestamp)); 1090 (void) strftime(timestamp,MagickPathExtent,"%Y:%m:%d:%H:%M:%S%Z",&local_time); 1091 (void) memset(cin.origination.create_date,0, 1092 sizeof(cin.origination.create_date)); 1093 (void) CopyMagickString(cin.origination.create_date,timestamp,11); 1094 offset+=WriteBlob(image,sizeof(cin.origination.create_date),(unsigned char *) 1095 cin.origination.create_date); 1096 (void) memset(cin.origination.create_time,0, 1097 sizeof(cin.origination.create_time)); 1098 (void) CopyMagickString(cin.origination.create_time,timestamp+11,15); 1099 offset+=WriteBlob(image,sizeof(cin.origination.create_time),(unsigned char *) 1100 cin.origination.create_time); 1101 value=GetCINProperty(image_info,image,"dpx:origination.device",exception); 1102 if (value != (const char *) NULL) 1103 (void) CopyMagickString(cin.origination.device,value, 1104 sizeof(cin.origination.device)); 1105 offset+=WriteBlob(image,sizeof(cin.origination.device),(unsigned char *) 1106 cin.origination.device); 1107 value=GetCINProperty(image_info,image,"dpx:origination.model",exception); 1108 if (value != (const char *) NULL) 1109 (void) CopyMagickString(cin.origination.model,value, 1110 sizeof(cin.origination.model)); 1111 offset+=WriteBlob(image,sizeof(cin.origination.model),(unsigned char *) 1112 cin.origination.model); 1113 value=GetCINProperty(image_info,image,"dpx:origination.serial",exception); 1114 if (value != (const char *) NULL) 1115 (void) CopyMagickString(cin.origination.serial,value, 1116 sizeof(cin.origination.serial)); 1117 offset+=WriteBlob(image,sizeof(cin.origination.serial),(unsigned char *) 1118 cin.origination.serial); 1119 cin.origination.x_pitch=0.0f; 1120 value=GetCINProperty(image_info,image,"dpx:origination.x_pitch",exception); 1121 if (value != (const char *) NULL) 1122 cin.origination.x_pitch=StringToDouble(value,(char **) NULL); 1123 offset+=WriteBlobFloat(image,cin.origination.x_pitch); 1124 cin.origination.y_pitch=0.0f; 1125 value=GetCINProperty(image_info,image,"dpx:origination.y_pitch",exception); 1126 if (value != (const char *) NULL) 1127 cin.origination.y_pitch=StringToDouble(value,(char **) NULL); 1128 offset+=WriteBlobFloat(image,cin.origination.y_pitch); 1129 cin.origination.gamma=image->gamma; 1130 offset+=WriteBlobFloat(image,cin.origination.gamma); 1131 offset+=WriteBlob(image,sizeof(cin.origination.reserve),(unsigned char *) 1132 cin.origination.reserve); 1133 /* 1134 Image film information. 1135 */ 1136 cin.film.id=0; 1137 value=GetCINProperty(image_info,image,"dpx:film.id",exception); 1138 if (value != (const char *) NULL) 1139 cin.film.id=(char) StringToLong(value); 1140 offset+=WriteBlobByte(image,(unsigned char) cin.film.id); 1141 cin.film.type=0; 1142 value=GetCINProperty(image_info,image,"dpx:film.type",exception); 1143 if (value != (const char *) NULL) 1144 cin.film.type=(char) StringToLong(value); 1145 offset+=WriteBlobByte(image,(unsigned char) cin.film.type); 1146 cin.film.offset=0; 1147 value=GetCINProperty(image_info,image,"dpx:film.offset",exception); 1148 if (value != (const char *) NULL) 1149 cin.film.offset=(char) StringToLong(value); 1150 offset+=WriteBlobByte(image,(unsigned char) cin.film.offset); 1151 offset+=WriteBlobByte(image,(unsigned char) cin.film.reserve1); 1152 cin.film.prefix=0UL; 1153 value=GetCINProperty(image_info,image,"dpx:film.prefix",exception); 1154 if (value != (const char *) NULL) 1155 cin.film.prefix=StringToUnsignedLong(value); 1156 offset+=WriteBlobLong(image,(unsigned int) cin.film.prefix); 1157 cin.film.count=0UL; 1158 value=GetCINProperty(image_info,image,"dpx:film.count",exception); 1159 if (value != (const char *) NULL) 1160 cin.film.count=StringToUnsignedLong(value); 1161 offset+=WriteBlobLong(image,(unsigned int) cin.film.count); 1162 value=GetCINProperty(image_info,image,"dpx:film.format",exception); 1163 if (value != (const char *) NULL) 1164 (void) CopyMagickString(cin.film.format,value,sizeof(cin.film.format)); 1165 offset+=WriteBlob(image,sizeof(cin.film.format),(unsigned char *) 1166 cin.film.format); 1167 cin.film.frame_position=0UL; 1168 value=GetCINProperty(image_info,image,"dpx:film.frame_position",exception); 1169 if (value != (const char *) NULL) 1170 cin.film.frame_position=StringToUnsignedLong(value); 1171 offset+=WriteBlobLong(image,(unsigned int) cin.film.frame_position); 1172 cin.film.frame_rate=0.0f; 1173 value=GetCINProperty(image_info,image,"dpx:film.frame_rate",exception); 1174 if (value != (const char *) NULL) 1175 cin.film.frame_rate=StringToDouble(value,(char **) NULL); 1176 offset+=WriteBlobFloat(image,cin.film.frame_rate); 1177 value=GetCINProperty(image_info,image,"dpx:film.frame_id",exception); 1178 if (value != (const char *) NULL) 1179 (void) CopyMagickString(cin.film.frame_id,value,sizeof(cin.film.frame_id)); 1180 offset+=WriteBlob(image,sizeof(cin.film.frame_id),(unsigned char *) 1181 cin.film.frame_id); 1182 value=GetCINProperty(image_info,image,"dpx:film.slate_info",exception); 1183 if (value != (const char *) NULL) 1184 (void) CopyMagickString(cin.film.slate_info,value, 1185 sizeof(cin.film.slate_info)); 1186 offset+=WriteBlob(image,sizeof(cin.film.slate_info),(unsigned char *) 1187 cin.film.slate_info); 1188 offset+=WriteBlob(image,sizeof(cin.film.reserve),(unsigned char *) 1189 cin.film.reserve); 1190 if (profile != (StringInfo *) NULL) 1191 offset+=WriteBlob(image,GetStringInfoLength(profile), 1192 GetStringInfoDatum(profile)); 1193 while (offset < (MagickOffsetType) cin.file.image_offset) 1194 offset+=WriteBlobByte(image,0x00); 1195 /* 1196 Convert pixel packets to CIN raster image. 1197 */ 1198 quantum_info=AcquireQuantumInfo(image_info,image); 1199 if (quantum_info == (QuantumInfo *) NULL) 1200 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 1201 quantum_info->quantum=32; 1202 quantum_info->pack=MagickFalse; 1203 quantum_type=RGBQuantum; 1204 pixels=(unsigned char *) GetQuantumPixels(quantum_info); 1205 length=GetBytesPerRow(image->columns,3,image->depth,MagickTrue); 1206DisableMSCWarning(4127) 1207 if (0) 1208RestoreMSCWarning 1209 { 1210 quantum_type=GrayQuantum; 1211 length=GetBytesPerRow(image->columns,1,image->depth,MagickTrue); 1212 } 1213 for (y=0; y < (ssize_t) image->rows; y++) 1214 { 1215 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 1216 if (p == (const Quantum *) NULL) 1217 break; 1218 (void) ExportQuantumPixels(image,(CacheView *) NULL,quantum_info, 1219 quantum_type,pixels,exception); 1220 count=WriteBlob(image,length,pixels); 1221 if (count != (ssize_t) length) 1222 break; 1223 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 1224 image->rows); 1225 if (status == MagickFalse) 1226 break; 1227 } 1228 quantum_info=DestroyQuantumInfo(quantum_info); 1229 (void) CloseBlob(image); 1230 return(status); 1231} 1232