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