1 /* 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 % % 4 % % 5 % % 6 % Y Y U U V V % 7 % Y Y U U V V % 8 % Y U U V V % 9 % Y U U V V % 10 % Y UUU V % 11 % % 12 % % 13 % Read/Write Raw CCIR 601 4:1:1 or 4:2:2 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 /* 41 Include declarations. 42 */ 43 #include "MagickCore/studio.h" 44 #include "MagickCore/blob.h" 45 #include "MagickCore/blob-private.h" 46 #include "MagickCore/cache.h" 47 #include "MagickCore/colorspace.h" 48 #include "MagickCore/constitute.h" 49 #include "MagickCore/exception.h" 50 #include "MagickCore/exception-private.h" 51 #include "MagickCore/geometry.h" 52 #include "MagickCore/image.h" 53 #include "MagickCore/image-private.h" 54 #include "MagickCore/list.h" 55 #include "MagickCore/magick.h" 56 #include "MagickCore/memory_.h" 57 #include "MagickCore/monitor.h" 58 #include "MagickCore/monitor-private.h" 59 #include "MagickCore/pixel-accessor.h" 60 #include "MagickCore/resize.h" 61 #include "MagickCore/quantum-private.h" 62 #include "MagickCore/static.h" 63 #include "MagickCore/string_.h" 64 #include "MagickCore/module.h" 65 #include "MagickCore/utility.h" 66 67 /* 69 Forward declarations. 70 */ 71 static MagickBooleanType 72 WriteYUVImage(const ImageInfo *,Image *,ExceptionInfo *); 73 74 /* 76 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 77 % % 78 % % 79 % % 80 % R e a d Y U V I m a g e % 81 % % 82 % % 83 % % 84 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 85 % 86 % ReadYUVImage() reads an image with digital YUV (CCIR 601 4:1:1, plane 87 % or partition interlaced, or 4:2:2 plane, partition interlaced or 88 % noninterlaced) bytes and returns it. It allocates the memory necessary 89 % for the new Image structure and returns a pointer to the new image. 90 % 91 % The format of the ReadYUVImage method is: 92 % 93 % Image *ReadYUVImage(const ImageInfo *image_info,ExceptionInfo *exception) 94 % 95 % A description of each parameter follows: 96 % 97 % o image_info: the image info. 98 % 99 % o exception: return any errors or warnings in this structure. 100 % 101 */ 102 static Image *ReadYUVImage(const ImageInfo *image_info,ExceptionInfo *exception) 103 { 104 Image 105 *chroma_image, 106 *image, 107 *resize_image; 108 109 InterlaceType 110 interlace; 111 112 MagickBooleanType 113 status; 114 115 register const Quantum 116 *chroma_pixels; 117 118 register ssize_t 119 x; 120 121 register Quantum 122 *q; 123 124 register unsigned char 125 *p; 126 127 ssize_t 128 count, 129 horizontal_factor, 130 quantum, 131 vertical_factor, 132 y; 133 134 unsigned char 135 *scanline; 136 137 /* 138 Allocate image structure. 139 */ 140 assert(image_info != (const ImageInfo *) NULL); 141 assert(image_info->signature == MagickCoreSignature); 142 if (image_info->debug != MagickFalse) 143 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 144 image_info->filename); 145 assert(exception != (ExceptionInfo *) NULL); 146 assert(exception->signature == MagickCoreSignature); 147 image=AcquireImage(image_info,exception); 148 if ((image->columns == 0) || (image->rows == 0)) 149 ThrowReaderException(OptionError,"MustSpecifyImageSize"); 150 status=SetImageExtent(image,image->columns,image->rows,exception); 151 if (status == MagickFalse) 152 return(DestroyImageList(image)); 153 quantum=image->depth <= 8 ? 1 : 2; 154 interlace=image_info->interlace; 155 horizontal_factor=2; 156 vertical_factor=2; 157 if (image_info->sampling_factor != (char *) NULL) 158 { 159 GeometryInfo 160 geometry_info; 161 162 MagickStatusType 163 flags; 164 165 flags=ParseGeometry(image_info->sampling_factor,&geometry_info); 166 horizontal_factor=(ssize_t) geometry_info.rho; 167 vertical_factor=(ssize_t) geometry_info.sigma; 168 if ((flags & SigmaValue) == 0) 169 vertical_factor=horizontal_factor; 170 if ((horizontal_factor != 1) && (horizontal_factor != 2) && 171 (vertical_factor != 1) && (vertical_factor != 2)) 172 ThrowReaderException(CorruptImageError,"UnexpectedSamplingFactor"); 173 } 174 if ((interlace == UndefinedInterlace) || 175 ((interlace == NoInterlace) && (vertical_factor == 2))) 176 { 177 interlace=NoInterlace; /* CCIR 4:2:2 */ 178 if (vertical_factor == 2) 179 interlace=PlaneInterlace; /* CCIR 4:1:1 */ 180 } 181 if (interlace != PartitionInterlace) 182 { 183 /* 184 Open image file. 185 */ 186 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 187 if (status == MagickFalse) 188 { 189 image=DestroyImageList(image); 190 return((Image *) NULL); 191 } 192 if (DiscardBlobBytes(image,image->offset) == MagickFalse) 193 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", 194 image->filename); 195 } 196 /* 197 Allocate memory for a scanline. 198 */ 199 if (interlace == NoInterlace) 200 scanline=(unsigned char *) AcquireQuantumMemory((size_t) 2UL* 201 image->columns+2UL,quantum*sizeof(*scanline)); 202 else 203 scanline=(unsigned char *) AcquireQuantumMemory(image->columns, 204 quantum*sizeof(*scanline)); 205 if (scanline == (unsigned char *) NULL) 206 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 207 do 208 { 209 chroma_image=CloneImage(image,(image->columns+horizontal_factor-1)/ 210 horizontal_factor,(image->rows+vertical_factor-1)/vertical_factor, 211 MagickTrue,exception); 212 if (chroma_image == (Image *) NULL) 213 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 214 /* 215 Convert raster image to pixel packets. 216 */ 217 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0)) 218 if (image->scene >= (image_info->scene+image_info->number_scenes-1)) 219 break; 220 status=SetImageExtent(image,image->columns,image->rows,exception); 221 if (status == MagickFalse) 222 return(DestroyImageList(image)); 223 if (interlace == PartitionInterlace) 224 { 225 AppendImageFormat("Y",image->filename); 226 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 227 if (status == MagickFalse) 228 { 229 image=DestroyImageList(image); 230 return((Image *) NULL); 231 } 232 } 233 for (y=0; y < (ssize_t) image->rows; y++) 234 { 235 register Quantum 236 *chroma_pixels; 237 238 if (interlace == NoInterlace) 239 { 240 if ((y > 0) || (GetPreviousImageInList(image) == (Image *) NULL)) 241 count=ReadBlob(image,(size_t) (2*quantum*image->columns),scanline); 242 p=scanline; 243 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 244 if (q == (Quantum *) NULL) 245 break; 246 chroma_pixels=QueueAuthenticPixels(chroma_image,0,y, 247 chroma_image->columns,1,exception); 248 if (chroma_pixels == (Quantum *) NULL) 249 break; 250 for (x=0; x < (ssize_t) image->columns; x+=2) 251 { 252 SetPixelRed(image,0,chroma_pixels); 253 if (quantum == 1) 254 SetPixelGreen(image,ScaleCharToQuantum(*p++),chroma_pixels); 255 else 256 { 257 SetPixelGreen(image,ScaleShortToQuantum(((*p) << 8) | *(p+1)), 258 chroma_pixels); 259 p+=2; 260 } 261 if (quantum == 1) 262 SetPixelRed(image,ScaleCharToQuantum(*p++),q); 263 else 264 { 265 SetPixelRed(image,ScaleShortToQuantum(((*p) << 8) | *(p+1)),q); 266 p+=2; 267 } 268 SetPixelGreen(image,0,q); 269 SetPixelBlue(image,0,q); 270 q+=GetPixelChannels(image); 271 SetPixelGreen(image,0,q); 272 SetPixelBlue(image,0,q); 273 if (quantum == 1) 274 SetPixelBlue(image,ScaleCharToQuantum(*p++),chroma_pixels); 275 else 276 { 277 SetPixelBlue(image,ScaleShortToQuantum(((*p) << 8) | *(p+1)), 278 chroma_pixels); 279 p+=2; 280 } 281 if (quantum == 1) 282 SetPixelRed(image,ScaleCharToQuantum(*p++),q); 283 else 284 { 285 SetPixelRed(image,ScaleShortToQuantum(((*p) << 8) | *(p+1)),q); 286 p+=2; 287 } 288 chroma_pixels++; 289 q+=GetPixelChannels(image); 290 } 291 } 292 else 293 { 294 if ((y > 0) || (GetPreviousImageInList(image) == (Image *) NULL)) 295 count=ReadBlob(image,(size_t) quantum*image->columns,scanline); 296 p=scanline; 297 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 298 if (q == (Quantum *) NULL) 299 break; 300 for (x=0; x < (ssize_t) image->columns; x++) 301 { 302 if (quantum == 1) 303 SetPixelRed(image,ScaleCharToQuantum(*p++),q); 304 else 305 { 306 SetPixelRed(image,ScaleShortToQuantum(((*p) << 8) | *(p+1)),q); 307 p+=2; 308 } 309 SetPixelGreen(image,0,q); 310 SetPixelBlue(image,0,q); 311 q+=GetPixelChannels(image); 312 } 313 } 314 if (SyncAuthenticPixels(image,exception) == MagickFalse) 315 break; 316 if (interlace == NoInterlace) 317 if (SyncAuthenticPixels(chroma_image,exception) == MagickFalse) 318 break; 319 if (image->previous == (Image *) NULL) 320 { 321 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, 322 image->rows); 323 if (status == MagickFalse) 324 break; 325 } 326 } 327 if (interlace == PartitionInterlace) 328 { 329 (void) CloseBlob(image); 330 AppendImageFormat("U",image->filename); 331 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 332 if (status == MagickFalse) 333 { 334 image=DestroyImageList(image); 335 return((Image *) NULL); 336 } 337 } 338 if (interlace != NoInterlace) 339 { 340 for (y=0; y < (ssize_t) chroma_image->rows; y++) 341 { 342 count=ReadBlob(image,(size_t) quantum*chroma_image->columns,scanline); 343 p=scanline; 344 q=QueueAuthenticPixels(chroma_image,0,y,chroma_image->columns,1, 345 exception); 346 if (q == (Quantum *) NULL) 347 break; 348 for (x=0; x < (ssize_t) chroma_image->columns; x++) 349 { 350 SetPixelRed(chroma_image,0,q); 351 if (quantum == 1) 352 SetPixelGreen(chroma_image,ScaleCharToQuantum(*p++),q); 353 else 354 { 355 SetPixelGreen(chroma_image,ScaleShortToQuantum(((*p) << 8) | 356 *(p+1)),q); 357 p+=2; 358 } 359 SetPixelBlue(chroma_image,0,q); 360 q+=GetPixelChannels(chroma_image); 361 } 362 if (SyncAuthenticPixels(chroma_image,exception) == MagickFalse) 363 break; 364 } 365 if (interlace == PartitionInterlace) 366 { 367 (void) CloseBlob(image); 368 AppendImageFormat("V",image->filename); 369 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 370 if (status == MagickFalse) 371 { 372 image=DestroyImageList(image); 373 return((Image *) NULL); 374 } 375 } 376 for (y=0; y < (ssize_t) chroma_image->rows; y++) 377 { 378 count=ReadBlob(image,(size_t) quantum*chroma_image->columns,scanline); 379 p=scanline; 380 q=GetAuthenticPixels(chroma_image,0,y,chroma_image->columns,1, 381 exception); 382 if (q == (Quantum *) NULL) 383 break; 384 for (x=0; x < (ssize_t) chroma_image->columns; x++) 385 { 386 if (quantum == 1) 387 SetPixelBlue(chroma_image,ScaleCharToQuantum(*p++),q); 388 else 389 { 390 SetPixelBlue(chroma_image,ScaleShortToQuantum(((*p) << 8) | 391 *(p+1)),q); 392 p+=2; 393 } 394 q+=GetPixelChannels(chroma_image); 395 } 396 if (SyncAuthenticPixels(chroma_image,exception) == MagickFalse) 397 break; 398 } 399 } 400 /* 401 Scale image. 402 */ 403 resize_image=ResizeImage(chroma_image,image->columns,image->rows, 404 TriangleFilter,exception); 405 chroma_image=DestroyImage(chroma_image); 406 if (resize_image == (Image *) NULL) 407 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 408 for (y=0; y < (ssize_t) image->rows; y++) 409 { 410 q=GetAuthenticPixels(image,0,y,image->columns,1,exception); 411 chroma_pixels=GetVirtualPixels(resize_image,0,y,resize_image->columns,1, 412 exception); 413 if ((q == (Quantum *) NULL) || 414 (chroma_pixels == (const Quantum *) NULL)) 415 break; 416 for (x=0; x < (ssize_t) image->columns; x++) 417 { 418 SetPixelGreen(image,GetPixelGreen(image,chroma_pixels),q); 419 SetPixelBlue(image,GetPixelBlue(image,chroma_pixels),q); 420 chroma_pixels++; 421 q+=GetPixelChannels(image); 422 } 423 if (SyncAuthenticPixels(image,exception) == MagickFalse) 424 break; 425 } 426 resize_image=DestroyImage(resize_image); 427 SetImageColorspace(image,YCbCrColorspace,exception); 428 if (interlace == PartitionInterlace) 429 (void) CopyMagickString(image->filename,image_info->filename, 430 MagickPathExtent); 431 if (EOFBlob(image) != MagickFalse) 432 { 433 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", 434 image->filename); 435 break; 436 } 437 /* 438 Proceed to next image. 439 */ 440 if (image_info->number_scenes != 0) 441 if (image->scene >= (image_info->scene+image_info->number_scenes-1)) 442 break; 443 if (interlace == NoInterlace) 444 count=ReadBlob(image,(size_t) (2*quantum*image->columns),scanline); 445 else 446 count=ReadBlob(image,(size_t) quantum*image->columns,scanline); 447 if (count != 0) 448 { 449 /* 450 Allocate next image structure. 451 */ 452 AcquireNextImage(image_info,image,exception); 453 if (GetNextImageInList(image) == (Image *) NULL) 454 { 455 image=DestroyImageList(image); 456 return((Image *) NULL); 457 } 458 image=SyncNextImageInList(image); 459 status=SetImageProgress(image,LoadImagesTag,TellBlob(image), 460 GetBlobSize(image)); 461 if (status == MagickFalse) 462 break; 463 } 464 } while (count != 0); 465 scanline=(unsigned char *) RelinquishMagickMemory(scanline); 466 (void) CloseBlob(image); 467 return(GetFirstImageInList(image)); 468 } 469 470 /* 472 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 473 % % 474 % % 475 % % 476 % R e g i s t e r Y U V I m a g e % 477 % % 478 % % 479 % % 480 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 481 % 482 % RegisterYUVImage() adds attributes for the YUV image format to 483 % the list of supported formats. The attributes include the image format 484 % tag, a method to read and/or write the format, whether the format 485 % supports the saving of more than one frame to the same file or blob, 486 % whether the format supports native in-memory I/O, and a brief 487 % description of the format. 488 % 489 % The format of the RegisterYUVImage method is: 490 % 491 % size_t RegisterYUVImage(void) 492 % 493 */ 494 ModuleExport size_t RegisterYUVImage(void) 495 { 496 MagickInfo 497 *entry; 498 499 entry=AcquireMagickInfo("YUV","YUV","CCIR 601 4:1:1 or 4:2:2"); 500 entry->decoder=(DecodeImageHandler *) ReadYUVImage; 501 entry->encoder=(EncodeImageHandler *) WriteYUVImage; 502 entry->flags^=CoderAdjoinFlag; 503 entry->flags|=CoderRawSupportFlag; 504 (void) RegisterMagickInfo(entry); 505 return(MagickImageCoderSignature); 506 } 507 508 /* 510 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 511 % % 512 % % 513 % % 514 % U n r e g i s t e r Y U V I m a g e % 515 % % 516 % % 517 % % 518 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 519 % 520 % UnregisterYUVImage() removes format registrations made by the 521 % YUV module from the list of supported formats. 522 % 523 % The format of the UnregisterYUVImage method is: 524 % 525 % UnregisterYUVImage(void) 526 % 527 */ 528 ModuleExport void UnregisterYUVImage(void) 529 { 530 (void) UnregisterMagickInfo("YUV"); 531 } 532 533 /* 535 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 536 % % 537 % % 538 % % 539 % W r i t e Y U V I m a g e % 540 % % 541 % % 542 % % 543 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 544 % 545 % WriteYUVImage() writes an image to a file in the digital YUV 546 % (CCIR 601 4:1:1, plane or partition interlaced, or 4:2:2 plane, partition 547 % interlaced or noninterlaced) bytes and returns it. 548 % 549 % The format of the WriteYUVImage method is: 550 % 551 % MagickBooleanType WriteYUVImage(const ImageInfo *image_info, 552 % Image *image,ExceptionInfo *exception) 553 % 554 % A description of each parameter follows. 555 % 556 % o image_info: the image info. 557 % 558 % o image: The image. 559 % 560 % o exception: return any errors or warnings in this structure. 561 % 562 */ 563 static MagickBooleanType WriteYUVImage(const ImageInfo *image_info,Image *image, 564 ExceptionInfo *exception) 565 { 566 Image 567 *chroma_image, 568 *yuv_image; 569 570 InterlaceType 571 interlace; 572 573 MagickBooleanType 574 status; 575 576 MagickOffsetType 577 scene; 578 579 register const Quantum 580 *p, 581 *s; 582 583 register ssize_t 584 x; 585 586 size_t 587 height, 588 quantum, 589 width; 590 591 ssize_t 592 horizontal_factor, 593 vertical_factor, 594 y; 595 596 assert(image_info != (const ImageInfo *) NULL); 597 assert(image_info->signature == MagickCoreSignature); 598 assert(image != (Image *) NULL); 599 assert(image->signature == MagickCoreSignature); 600 if (image->debug != MagickFalse) 601 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 602 quantum=(size_t) (image->depth <= 8 ? 1 : 2); 603 interlace=image->interlace; 604 horizontal_factor=2; 605 vertical_factor=2; 606 if (image_info->sampling_factor != (char *) NULL) 607 { 608 GeometryInfo 609 geometry_info; 610 611 MagickStatusType 612 flags; 613 614 flags=ParseGeometry(image_info->sampling_factor,&geometry_info); 615 horizontal_factor=(ssize_t) geometry_info.rho; 616 vertical_factor=(ssize_t) geometry_info.sigma; 617 if ((flags & SigmaValue) == 0) 618 vertical_factor=horizontal_factor; 619 if ((horizontal_factor != 1) && (horizontal_factor != 2) && 620 (vertical_factor != 1) && (vertical_factor != 2)) 621 ThrowWriterException(CorruptImageError,"UnexpectedSamplingFactor"); 622 } 623 if ((interlace == UndefinedInterlace) || 624 ((interlace == NoInterlace) && (vertical_factor == 2))) 625 { 626 interlace=NoInterlace; /* CCIR 4:2:2 */ 627 if (vertical_factor == 2) 628 interlace=PlaneInterlace; /* CCIR 4:1:1 */ 629 } 630 if (interlace != PartitionInterlace) 631 { 632 /* 633 Open output image file. 634 */ 635 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 636 if (status == MagickFalse) 637 return(status); 638 } 639 else 640 { 641 AppendImageFormat("Y",image->filename); 642 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 643 if (status == MagickFalse) 644 return(status); 645 } 646 scene=0; 647 do 648 { 649 /* 650 Sample image to an even width and height, if necessary. 651 */ 652 image->depth=(size_t) (quantum == 1 ? 8 : 16); 653 width=image->columns+(image->columns & (horizontal_factor-1)); 654 height=image->rows+(image->rows & (vertical_factor-1)); 655 yuv_image=ResizeImage(image,width,height,TriangleFilter,exception); 656 if (yuv_image == (Image *) NULL) 657 { 658 (void) CloseBlob(image); 659 return(MagickFalse); 660 } 661 (void) TransformImageColorspace(yuv_image,YCbCrColorspace,exception); 662 /* 663 Downsample image. 664 */ 665 chroma_image=ResizeImage(image,width/horizontal_factor, 666 height/vertical_factor,TriangleFilter,exception); 667 if (chroma_image == (Image *) NULL) 668 { 669 (void) CloseBlob(image); 670 return(MagickFalse); 671 } 672 (void) TransformImageColorspace(chroma_image,YCbCrColorspace,exception); 673 if (interlace == NoInterlace) 674 { 675 /* 676 Write noninterlaced YUV. 677 */ 678 for (y=0; y < (ssize_t) yuv_image->rows; y++) 679 { 680 p=GetVirtualPixels(yuv_image,0,y,yuv_image->columns,1,exception); 681 if (p == (const Quantum *) NULL) 682 break; 683 s=GetVirtualPixels(chroma_image,0,y,chroma_image->columns,1, 684 exception); 685 if (s == (const Quantum *) NULL) 686 break; 687 for (x=0; x < (ssize_t) yuv_image->columns; x++) 688 { 689 if (quantum == 1) 690 { 691 (void) WriteBlobByte(image,ScaleQuantumToChar( 692 GetPixelGreen(yuv_image,s))); 693 (void) WriteBlobByte(image,ScaleQuantumToChar( 694 GetPixelRed(yuv_image,p))); 695 p+=GetPixelChannels(yuv_image); 696 (void) WriteBlobByte(image,ScaleQuantumToChar( 697 GetPixelBlue(yuv_image,s))); 698 (void) WriteBlobByte(image,ScaleQuantumToChar( 699 GetPixelRed(yuv_image,p))); 700 } 701 else 702 { 703 (void) WriteBlobByte(image,ScaleQuantumToChar( 704 GetPixelGreen(yuv_image,s))); 705 (void) WriteBlobShort(image,ScaleQuantumToShort( 706 GetPixelRed(yuv_image,p))); 707 p+=GetPixelChannels(yuv_image); 708 (void) WriteBlobByte(image,ScaleQuantumToChar( 709 GetPixelBlue(yuv_image,s))); 710 (void) WriteBlobShort(image,ScaleQuantumToShort( 711 GetPixelRed(yuv_image,p))); 712 } 713 p+=GetPixelChannels(yuv_image); 714 s++; 715 x++; 716 } 717 if (image->previous == (Image *) NULL) 718 { 719 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 720 image->rows); 721 if (status == MagickFalse) 722 break; 723 } 724 } 725 yuv_image=DestroyImage(yuv_image); 726 } 727 else 728 { 729 /* 730 Initialize Y channel. 731 */ 732 for (y=0; y < (ssize_t) yuv_image->rows; y++) 733 { 734 p=GetVirtualPixels(yuv_image,0,y,yuv_image->columns,1,exception); 735 if (p == (const Quantum *) NULL) 736 break; 737 for (x=0; x < (ssize_t) yuv_image->columns; x++) 738 { 739 if (quantum == 1) 740 (void) WriteBlobByte(image,ScaleQuantumToChar( 741 GetPixelRed(yuv_image,p))); 742 else 743 (void) WriteBlobShort(image,ScaleQuantumToShort( 744 GetPixelRed(yuv_image,p))); 745 p+=GetPixelChannels(yuv_image); 746 } 747 if (image->previous == (Image *) NULL) 748 { 749 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 750 image->rows); 751 if (status == MagickFalse) 752 break; 753 } 754 } 755 yuv_image=DestroyImage(yuv_image); 756 if (image->previous == (Image *) NULL) 757 { 758 status=SetImageProgress(image,SaveImageTag,1,3); 759 if (status == MagickFalse) 760 break; 761 } 762 /* 763 Initialize U channel. 764 */ 765 if (interlace == PartitionInterlace) 766 { 767 (void) CloseBlob(image); 768 AppendImageFormat("U",image->filename); 769 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 770 if (status == MagickFalse) 771 return(status); 772 } 773 for (y=0; y < (ssize_t) chroma_image->rows; y++) 774 { 775 p=GetVirtualPixels(chroma_image,0,y,chroma_image->columns,1, 776 exception); 777 if (p == (const Quantum *) NULL) 778 break; 779 for (x=0; x < (ssize_t) chroma_image->columns; x++) 780 { 781 if (quantum == 1) 782 (void) WriteBlobByte(image,ScaleQuantumToChar( 783 GetPixelGreen(chroma_image,p))); 784 else 785 (void) WriteBlobShort(image,ScaleQuantumToShort( 786 GetPixelGreen(chroma_image,p))); 787 p+=GetPixelChannels(chroma_image); 788 } 789 } 790 if (image->previous == (Image *) NULL) 791 { 792 status=SetImageProgress(image,SaveImageTag,2,3); 793 if (status == MagickFalse) 794 break; 795 } 796 /* 797 Initialize V channel. 798 */ 799 if (interlace == PartitionInterlace) 800 { 801 (void) CloseBlob(image); 802 AppendImageFormat("V",image->filename); 803 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 804 if (status == MagickFalse) 805 return(status); 806 } 807 for (y=0; y < (ssize_t) chroma_image->rows; y++) 808 { 809 p=GetVirtualPixels(chroma_image,0,y,chroma_image->columns,1, 810 exception); 811 if (p == (const Quantum *) NULL) 812 break; 813 for (x=0; x < (ssize_t) chroma_image->columns; x++) 814 { 815 if (quantum == 1) 816 (void) WriteBlobByte(image,ScaleQuantumToChar( 817 GetPixelBlue(chroma_image,p))); 818 else 819 (void) WriteBlobShort(image,ScaleQuantumToShort( 820 GetPixelBlue(chroma_image,p))); 821 p+=GetPixelChannels(chroma_image); 822 } 823 } 824 if (image->previous == (Image *) NULL) 825 { 826 status=SetImageProgress(image,SaveImageTag,2,3); 827 if (status == MagickFalse) 828 break; 829 } 830 } 831 chroma_image=DestroyImage(chroma_image); 832 if (interlace == PartitionInterlace) 833 (void) CopyMagickString(image->filename,image_info->filename, 834 MagickPathExtent); 835 if (GetNextImageInList(image) == (Image *) NULL) 836 break; 837 image=SyncNextImageInList(image); 838 status=SetImageProgress(image,SaveImagesTag,scene++, 839 GetImageListLength(image)); 840 if (status == MagickFalse) 841 break; 842 } while (image_info->adjoin != MagickFalse); 843 (void) CloseBlob(image); 844 return(MagickTrue); 845 } 846