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