blob: 936e69a8670844c2809ea35d94d60005bbe1eecf [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
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% John Cristy %
17% July 1992 %
18% %
19% %
cristy7e41fe82010-12-04 23:12:08 +000020% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% 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 "magick/studio.h"
43#include "magick/blob.h"
44#include "magick/blob-private.h"
45#include "magick/cache.h"
46#include "magick/colorspace.h"
47#include "magick/constitute.h"
48#include "magick/exception.h"
49#include "magick/exception-private.h"
50#include "magick/geometry.h"
51#include "magick/image.h"
52#include "magick/image-private.h"
53#include "magick/list.h"
54#include "magick/magick.h"
55#include "magick/memory_.h"
56#include "magick/monitor.h"
57#include "magick/monitor-private.h"
58#include "magick/resize.h"
59#include "magick/quantum-private.h"
60#include "magick/static.h"
61#include "magick/string_.h"
62#include "magick/module.h"
63#include "magick/utility.h"
64
65/*
66 Forward declarations.
67*/
68static MagickBooleanType
69 WriteYUVImage(const ImageInfo *,Image *);
70
71/*
72%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
73% %
74% %
75% %
76% R e a d Y U V I m a g e %
77% %
78% %
79% %
80%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
81%
82% ReadYUVImage() reads an image with digital YUV (CCIR 601 4:1:1, plane
83% or partition interlaced, or 4:2:2 plane, partition interlaced or
84% noninterlaced) bytes and returns it. It allocates the memory necessary
85% for the new Image structure and returns a pointer to the new image.
86%
87% The format of the ReadYUVImage method is:
88%
89% Image *ReadYUVImage(const ImageInfo *image_info,ExceptionInfo *exception)
90%
91% A description of each parameter follows:
92%
93% o image_info: the image info.
94%
95% o exception: return any errors or warnings in this structure.
96%
97*/
98static Image *ReadYUVImage(const ImageInfo *image_info,ExceptionInfo *exception)
99{
100 Image
101 *chroma_image,
102 *image,
103 *resize_image;
104
105 InterlaceType
106 interlace;
107
cristybb503372010-05-27 20:51:26 +0000108 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000109 horizontal_factor,
110 vertical_factor,
111 y;
112
113 MagickBooleanType
114 status;
115
116 register const PixelPacket
117 *chroma_pixels;
118
cristybb503372010-05-27 20:51:26 +0000119 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000120 x;
121
122 register PixelPacket
123 *q;
124
cristy3ed852e2009-09-05 21:47:34 +0000125 register unsigned char
126 *p;
127
128 ssize_t
cristy292ebf12011-02-08 20:21:31 +0000129 quantum;
130
131 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000132 count;
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 == MagickSignature);
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 == MagickSignature);
147 image=AcquireImage(image_info);
148 if ((image->columns == 0) || (image->rows == 0))
149 ThrowReaderException(OptionError,"MustSpecifyImageSize");
cristy292ebf12011-02-08 20:21:31 +0000150 quantum=image->depth <= 8 ? 1 : 2;
cristy3ed852e2009-09-05 21:47:34 +0000151 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);
cristybb503372010-05-27 20:51:26 +0000163 horizontal_factor=(ssize_t) geometry_info.rho;
164 vertical_factor=(ssize_t) geometry_info.sigma;
cristy3ed852e2009-09-05 21:47:34 +0000165 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 }
cristyd4297022010-09-16 22:59:09 +0000189 if (DiscardBlobBytes(image,image->offset) == MagickFalse)
190 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
191 image->filename);
cristy3ed852e2009-09-05 21:47:34 +0000192 }
193 /*
194 Allocate memory for a scanline.
195 */
196 if (interlace == NoInterlace)
197 scanline=(unsigned char *) AcquireQuantumMemory((size_t) 2UL*
cristy292ebf12011-02-08 20:21:31 +0000198 image->columns+2UL,quantum*sizeof(*scanline));
cristy3ed852e2009-09-05 21:47:34 +0000199 else
200 scanline=(unsigned char *) AcquireQuantumMemory((size_t) image->columns,
cristy292ebf12011-02-08 20:21:31 +0000201 quantum*sizeof(*scanline));
cristy3ed852e2009-09-05 21:47:34 +0000202 if (scanline == (unsigned char *) NULL)
203 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
204 do
205 {
206 chroma_image=CloneImage(image,image->columns/horizontal_factor,
207 image->rows/vertical_factor,MagickTrue,exception);
208 if (chroma_image == (Image *) NULL)
209 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
210 /*
211 Convert raster image to pixel packets.
212 */
213 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
214 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
215 break;
216 if (interlace == PartitionInterlace)
217 {
218 AppendImageFormat("Y",image->filename);
219 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
220 if (status == MagickFalse)
221 {
222 image=DestroyImageList(image);
223 return((Image *) NULL);
224 }
225 }
cristybb503372010-05-27 20:51:26 +0000226 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000227 {
228 register PixelPacket
229 *chroma_pixels;
230
231 if (interlace == NoInterlace)
232 {
233 if ((y > 0) || (GetPreviousImageInList(image) == (Image *) NULL))
cristy292ebf12011-02-08 20:21:31 +0000234 count=ReadBlob(image,(size_t) (2*quantum*image->columns),scanline);
cristy3ed852e2009-09-05 21:47:34 +0000235 p=scanline;
236 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
237 if (q == (PixelPacket *) NULL)
238 break;
239 chroma_pixels=QueueAuthenticPixels(chroma_image,0,y,
240 chroma_image->columns,1,exception);
241 if (chroma_pixels == (PixelPacket *) NULL)
242 break;
cristybb503372010-05-27 20:51:26 +0000243 for (x=0; x < (ssize_t) image->columns; x+=2)
cristy3ed852e2009-09-05 21:47:34 +0000244 {
245 chroma_pixels->red=(Quantum) 0;
cristy292ebf12011-02-08 20:21:31 +0000246 if (quantum == 1)
247 chroma_pixels->green=ScaleCharToQuantum(*p++);
248 else
249 {
250 chroma_pixels->green=ScaleShortToQuantum(((*p) << 8) | *(p+1));
251 p+=2;
252 }
253 if (quantum == 1)
254 q->red=ScaleCharToQuantum(*p++);
255 else
256 {
257 q->red=ScaleShortToQuantum(((*p) << 8) | *(p+1));
258 p+=2;
259 }
cristy3ed852e2009-09-05 21:47:34 +0000260 q->green=(Quantum) 0;
261 q->blue=(Quantum) 0;
262 q++;
263 q->green=0;
264 q->blue=0;
cristy292ebf12011-02-08 20:21:31 +0000265 if (quantum == 1)
266 chroma_pixels->blue=ScaleCharToQuantum(*p++);
267 else
268 {
269 chroma_pixels->blue=ScaleShortToQuantum(((*p) << 8) | *(p+1));
270 p+=2;
271 }
272 if (quantum == 1)
273 q->red=ScaleCharToQuantum(*p++);
274 else
275 {
276 q->red=ScaleShortToQuantum(((*p) << 8) | *(p+1));
277 p+=2;
278 }
cristy3ed852e2009-09-05 21:47:34 +0000279 chroma_pixels++;
280 q++;
281 }
282 }
283 else
284 {
285 if ((y > 0) || (GetPreviousImageInList(image) == (Image *) NULL))
cristy292ebf12011-02-08 20:21:31 +0000286 count=ReadBlob(image,(size_t) quantum*image->columns,scanline);
cristy3ed852e2009-09-05 21:47:34 +0000287 p=scanline;
288 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
289 if (q == (PixelPacket *) NULL)
290 break;
cristybb503372010-05-27 20:51:26 +0000291 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000292 {
cristy292ebf12011-02-08 20:21:31 +0000293 if (quantum == 1)
294 q->red=ScaleCharToQuantum(*p++);
295 else
296 {
297 q->red=ScaleShortToQuantum(((*p) << 8) | *(p+1));
298 p+=2;
299 }
cristy3ed852e2009-09-05 21:47:34 +0000300 q->green=0;
301 q->blue=0;
302 q++;
303 }
304 }
305 if (SyncAuthenticPixels(image,exception) == MagickFalse)
306 break;
307 if (interlace == NoInterlace)
308 if (SyncAuthenticPixels(chroma_image,exception) == MagickFalse)
309 break;
310 if (image->previous == (Image *) NULL)
311 {
cristycee97112010-05-28 00:44:52 +0000312 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
cristy292ebf12011-02-08 20:21:31 +0000313 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000314 if (status == MagickFalse)
315 break;
316 }
317 }
318 if (interlace == PartitionInterlace)
319 {
320 (void) CloseBlob(image);
321 AppendImageFormat("U",image->filename);
322 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
323 if (status == MagickFalse)
324 {
325 image=DestroyImageList(image);
326 return((Image *) NULL);
327 }
328 }
329 if (interlace != NoInterlace)
330 {
cristybb503372010-05-27 20:51:26 +0000331 for (y=0; y < (ssize_t) chroma_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000332 {
cristy292ebf12011-02-08 20:21:31 +0000333 count=ReadBlob(image,(size_t) quantum*chroma_image->columns,scanline);
cristy3ed852e2009-09-05 21:47:34 +0000334 p=scanline;
335 q=QueueAuthenticPixels(chroma_image,0,y,chroma_image->columns,1,
336 exception);
337 if (q == (PixelPacket *) NULL)
338 break;
cristybb503372010-05-27 20:51:26 +0000339 for (x=0; x < (ssize_t) chroma_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000340 {
341 q->red=(Quantum) 0;
cristy292ebf12011-02-08 20:21:31 +0000342 if (quantum == 1)
343 q->green=ScaleCharToQuantum(*p++);
344 else
345 {
346 q->green=ScaleShortToQuantum(((*p) << 8) | *(p+1));
347 p+=2;
348 }
cristy3ed852e2009-09-05 21:47:34 +0000349 q->blue=(Quantum) 0;
350 q++;
351 }
352 if (SyncAuthenticPixels(chroma_image,exception) == MagickFalse)
353 break;
354 }
355 if (interlace == PartitionInterlace)
356 {
357 (void) CloseBlob(image);
358 AppendImageFormat("V",image->filename);
359 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
360 if (status == MagickFalse)
361 {
362 image=DestroyImageList(image);
363 return((Image *) NULL);
364 }
365 }
cristybb503372010-05-27 20:51:26 +0000366 for (y=0; y < (ssize_t) chroma_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000367 {
cristy292ebf12011-02-08 20:21:31 +0000368 count=ReadBlob(image,(size_t) quantum*chroma_image->columns,scanline);
cristy3ed852e2009-09-05 21:47:34 +0000369 p=scanline;
370 q=GetAuthenticPixels(chroma_image,0,y,chroma_image->columns,1,
371 exception);
372 if (q == (PixelPacket *) NULL)
373 break;
cristybb503372010-05-27 20:51:26 +0000374 for (x=0; x < (ssize_t) chroma_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000375 {
cristy292ebf12011-02-08 20:21:31 +0000376 if (quantum == 1)
377 q->blue=ScaleCharToQuantum(*p++);
378 else
379 {
380 q->blue=ScaleShortToQuantum(((*p) << 8) | *(p+1));
381 p+=2;
382 }
cristy3ed852e2009-09-05 21:47:34 +0000383 q++;
384 }
385 if (SyncAuthenticPixels(chroma_image,exception) == MagickFalse)
386 break;
387 }
388 }
389 /*
390 Scale image.
391 */
392 resize_image=ResizeImage(chroma_image,image->columns,image->rows,
393 TriangleFilter,1.0,exception);
394 chroma_image=DestroyImage(chroma_image);
395 if (resize_image == (Image *) NULL)
396 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000397 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000398 {
399 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
400 chroma_pixels=GetVirtualPixels(resize_image,0,y,resize_image->columns,1,
401 &resize_image->exception);
402 if ((q == (PixelPacket *) NULL) ||
403 (chroma_pixels == (const PixelPacket *) NULL))
404 break;
cristybb503372010-05-27 20:51:26 +0000405 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000406 {
407 q->green=chroma_pixels->green;
408 q->blue=chroma_pixels->blue;
409 chroma_pixels++;
410 q++;
411 }
412 if (SyncAuthenticPixels(image,exception) == MagickFalse)
413 break;
414 }
415 resize_image=DestroyImage(resize_image);
416 image->colorspace=YCbCrColorspace;
417 if (interlace == PartitionInterlace)
418 (void) CopyMagickString(image->filename,image_info->filename,
419 MaxTextExtent);
420 if (EOFBlob(image) != MagickFalse)
421 {
422 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
423 image->filename);
424 break;
425 }
426 /*
427 Proceed to next image.
428 */
429 if (image_info->number_scenes != 0)
430 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
431 break;
432 if (interlace == NoInterlace)
cristy292ebf12011-02-08 20:21:31 +0000433 count=ReadBlob(image,(size_t) (2*quantum*image->columns),scanline);
cristy3ed852e2009-09-05 21:47:34 +0000434 else
cristy292ebf12011-02-08 20:21:31 +0000435 count=ReadBlob(image,(size_t) quantum*image->columns,scanline);
cristy3ed852e2009-09-05 21:47:34 +0000436 if (count != 0)
437 {
438 /*
439 Allocate next image structure.
440 */
441 AcquireNextImage(image_info,image);
442 if (GetNextImageInList(image) == (Image *) NULL)
443 {
444 image=DestroyImageList(image);
445 return((Image *) NULL);
446 }
447 image=SyncNextImageInList(image);
448 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
449 GetBlobSize(image));
450 if (status == MagickFalse)
451 break;
452 }
453 } while (count != 0);
454 scanline=(unsigned char *) RelinquishMagickMemory(scanline);
455 (void) CloseBlob(image);
456 return(GetFirstImageInList(image));
457}
458
459/*
460%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
461% %
462% %
463% %
464% R e g i s t e r Y U V I m a g e %
465% %
466% %
467% %
468%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
469%
470% RegisterYUVImage() adds attributes for the YUV image format to
471% the list of supported formats. The attributes include the image format
472% tag, a method to read and/or write the format, whether the format
473% supports the saving of more than one frame to the same file or blob,
474% whether the format supports native in-memory I/O, and a brief
475% description of the format.
476%
477% The format of the RegisterYUVImage method is:
478%
cristybb503372010-05-27 20:51:26 +0000479% size_t RegisterYUVImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000480%
481*/
cristybb503372010-05-27 20:51:26 +0000482ModuleExport size_t RegisterYUVImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000483{
484 MagickInfo
485 *entry;
486
487 entry=SetMagickInfo("YUV");
488 entry->decoder=(DecodeImageHandler *) ReadYUVImage;
489 entry->encoder=(EncodeImageHandler *) WriteYUVImage;
490 entry->adjoin=MagickFalse;
491 entry->raw=MagickTrue;
492 entry->description=ConstantString("CCIR 601 4:1:1 or 4:2:2");
493 entry->module=ConstantString("YUV");
494 (void) RegisterMagickInfo(entry);
495 return(MagickImageCoderSignature);
496}
497
498/*
499%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
500% %
501% %
502% %
503% U n r e g i s t e r Y U V I m a g e %
504% %
505% %
506% %
507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
508%
509% UnregisterYUVImage() removes format registrations made by the
510% YUV module from the list of supported formats.
511%
512% The format of the UnregisterYUVImage method is:
513%
514% UnregisterYUVImage(void)
515%
516*/
517ModuleExport void UnregisterYUVImage(void)
518{
519 (void) UnregisterMagickInfo("YUV");
520}
521
522/*
523%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
524% %
525% %
526% %
527% W r i t e Y U V I m a g e %
528% %
529% %
530% %
531%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
532%
533% WriteYUVImage() writes an image to a file in the digital YUV
534% (CCIR 601 4:1:1, plane or partition interlaced, or 4:2:2 plane, partition
535% interlaced or noninterlaced) bytes and returns it.
536%
537% The format of the WriteYUVImage method is:
538%
539% MagickBooleanType WriteYUVImage(const ImageInfo *image_info,Image *image)
540%
541% A description of each parameter follows.
542%
543% o image_info: the image info.
544%
545% o image: The image.
546%
547*/
548static MagickBooleanType WriteYUVImage(const ImageInfo *image_info,Image *image)
549{
550 Image
551 *chroma_image,
552 *yuv_image;
553
554 InterlaceType
555 interlace;
556
cristybb503372010-05-27 20:51:26 +0000557 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000558 horizontal_factor,
559 vertical_factor,
560 y;
561
562 MagickBooleanType
563 status;
564
565 MagickOffsetType
566 scene;
567
568 register const PixelPacket
569 *p,
570 *s;
571
cristybb503372010-05-27 20:51:26 +0000572 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000573 x;
574
cristybb503372010-05-27 20:51:26 +0000575 size_t
cristy3ed852e2009-09-05 21:47:34 +0000576 height,
cristy292ebf12011-02-08 20:21:31 +0000577 quantum,
cristy3ed852e2009-09-05 21:47:34 +0000578 width;
579
580 assert(image_info != (const ImageInfo *) NULL);
581 assert(image_info->signature == MagickSignature);
582 assert(image != (Image *) NULL);
583 assert(image->signature == MagickSignature);
584 if (image->debug != MagickFalse)
585 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy292ebf12011-02-08 20:21:31 +0000586 quantum=image->depth <= 8 ? 1 : 2;
cristy3ed852e2009-09-05 21:47:34 +0000587 interlace=image->interlace;
588 horizontal_factor=2;
589 vertical_factor=2;
590 if (image_info->sampling_factor != (char *) NULL)
591 {
592 GeometryInfo
593 geometry_info;
594
595 MagickStatusType
596 flags;
597
598 flags=ParseGeometry(image_info->sampling_factor,&geometry_info);
cristybb503372010-05-27 20:51:26 +0000599 horizontal_factor=(ssize_t) geometry_info.rho;
600 vertical_factor=(ssize_t) geometry_info.sigma;
cristy3ed852e2009-09-05 21:47:34 +0000601 if ((flags & SigmaValue) == 0)
602 vertical_factor=horizontal_factor;
603 if ((horizontal_factor != 1) && (horizontal_factor != 2) &&
604 (vertical_factor != 1) && (vertical_factor != 2))
605 ThrowWriterException(CorruptImageError,"UnexpectedSamplingFactor");
606 }
607 if ((interlace == UndefinedInterlace) ||
608 ((interlace == NoInterlace) && (vertical_factor == 2)))
609 {
610 interlace=NoInterlace; /* CCIR 4:2:2 */
611 if (vertical_factor == 2)
612 interlace=PlaneInterlace; /* CCIR 4:1:1 */
613 }
614 if (interlace != PartitionInterlace)
615 {
616 /*
617 Open output image file.
618 */
619 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
620 if (status == MagickFalse)
621 return(status);
622 }
623 else
624 {
625 AppendImageFormat("Y",image->filename);
626 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
627 if (status == MagickFalse)
628 return(status);
629 }
630 scene=0;
631 do
632 {
633 /*
634 Sample image to an even width and height, if necessary.
635 */
cristy292ebf12011-02-08 20:21:31 +0000636 image->depth=quantum == 1 ? 8 : 16;
cristy3ed852e2009-09-05 21:47:34 +0000637 width=image->columns+(image->columns & (horizontal_factor-1));
638 height=image->rows+(image->rows & (vertical_factor-1));
639 yuv_image=ResizeImage(image,width,height,TriangleFilter,1.0,
640 &image->exception);
641 if (yuv_image == (Image *) NULL)
642 ThrowWriterException(ResourceLimitError,image->exception.reason);
643 (void) TransformImageColorspace(yuv_image,YCbCrColorspace);
644 /*
645 Downsample image.
646 */
647 chroma_image=ResizeImage(image,width/horizontal_factor,
648 height/vertical_factor,TriangleFilter,1.0,&image->exception);
649 if (chroma_image == (Image *) NULL)
650 ThrowWriterException(ResourceLimitError,image->exception.reason);
651 (void) TransformImageColorspace(chroma_image,YCbCrColorspace);
652 if (interlace == NoInterlace)
653 {
654 /*
655 Write noninterlaced YUV.
656 */
cristybb503372010-05-27 20:51:26 +0000657 for (y=0; y < (ssize_t) yuv_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000658 {
659 p=GetVirtualPixels(yuv_image,0,y,yuv_image->columns,1,
660 &yuv_image->exception);
661 if (p == (const PixelPacket *) NULL)
662 break;
663 s=GetVirtualPixels(chroma_image,0,y,chroma_image->columns,1,
664 &chroma_image->exception);
665 if (s == (const PixelPacket *) NULL)
666 break;
cristybb503372010-05-27 20:51:26 +0000667 for (x=0; x < (ssize_t) yuv_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000668 {
cristy292ebf12011-02-08 20:21:31 +0000669 if (quantum == 1)
670 {
671 (void) WriteBlobByte(image,ScaleQuantumToChar(s->green));
672 (void) WriteBlobByte(image,ScaleQuantumToChar(
673 GetRedPixelComponent(p)));
674 p++;
675 (void) WriteBlobByte(image,ScaleQuantumToChar(s->blue));
676 (void) WriteBlobByte(image,ScaleQuantumToChar(
677 GetRedPixelComponent(p)));
678 }
679 else
680 {
681 (void) WriteBlobShort(image,ScaleQuantumToShort(s->green));
682 (void) WriteBlobShort(image,ScaleQuantumToShort(
683 GetRedPixelComponent(p)));
684 p++;
685 (void) WriteBlobShort(image,ScaleQuantumToShort(s->blue));
686 (void) WriteBlobShort(image,ScaleQuantumToShort(
687 GetRedPixelComponent(p)));
688 }
cristy3ed852e2009-09-05 21:47:34 +0000689 p++;
690 s++;
691 x++;
692 }
693 if (image->previous == (Image *) NULL)
694 {
cristycee97112010-05-28 00:44:52 +0000695 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
696 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000697 if (status == MagickFalse)
698 break;
699 }
700 }
701 yuv_image=DestroyImage(yuv_image);
702 }
703 else
704 {
705 /*
706 Initialize Y channel.
707 */
cristybb503372010-05-27 20:51:26 +0000708 for (y=0; y < (ssize_t) yuv_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000709 {
710 p=GetVirtualPixels(yuv_image,0,y,yuv_image->columns,1,
711 &yuv_image->exception);
712 if (p == (const PixelPacket *) NULL)
713 break;
cristybb503372010-05-27 20:51:26 +0000714 for (x=0; x < (ssize_t) yuv_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000715 {
cristy292ebf12011-02-08 20:21:31 +0000716 if (quantum == 1)
717 (void) WriteBlobByte(image,ScaleQuantumToChar(
718 GetRedPixelComponent(p)));
719 else
720 (void) WriteBlobShort(image,ScaleQuantumToShort(
721 GetRedPixelComponent(p)));
cristy3ed852e2009-09-05 21:47:34 +0000722 p++;
723 }
724 if (image->previous == (Image *) NULL)
725 {
cristycee97112010-05-28 00:44:52 +0000726 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
727 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000728 if (status == MagickFalse)
729 break;
730 }
731 }
732 yuv_image=DestroyImage(yuv_image);
733 if (image->previous == (Image *) NULL)
734 {
735 status=SetImageProgress(image,SaveImageTag,1,3);
736 if (status == MagickFalse)
737 break;
738 }
739 /*
740 Initialize U channel.
741 */
742 if (interlace == PartitionInterlace)
743 {
744 (void) CloseBlob(image);
745 AppendImageFormat("U",image->filename);
746 status=OpenBlob(image_info,image,WriteBinaryBlobMode,
747 &image->exception);
748 if (status == MagickFalse)
749 return(status);
750 }
cristybb503372010-05-27 20:51:26 +0000751 for (y=0; y < (ssize_t) chroma_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000752 {
753 p=GetVirtualPixels(chroma_image,0,y,chroma_image->columns,1,
754 &chroma_image->exception);
755 if (p == (const PixelPacket *) NULL)
756 break;
cristybb503372010-05-27 20:51:26 +0000757 for (x=0; x < (ssize_t) chroma_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000758 {
cristy292ebf12011-02-08 20:21:31 +0000759 if (quantum == 1)
760 (void) WriteBlobByte(image,ScaleQuantumToChar(
761 GetGreenPixelComponent(p)));
762 else
763 (void) WriteBlobShort(image,ScaleQuantumToShort(
764 GetGreenPixelComponent(p)));
cristy3ed852e2009-09-05 21:47:34 +0000765 p++;
766 }
767 }
768 if (image->previous == (Image *) NULL)
769 {
770 status=SetImageProgress(image,SaveImageTag,2,3);
771 if (status == MagickFalse)
772 break;
773 }
774 /*
775 Initialize V channel.
776 */
777 if (interlace == PartitionInterlace)
778 {
779 (void) CloseBlob(image);
780 AppendImageFormat("V",image->filename);
781 status=OpenBlob(image_info,image,WriteBinaryBlobMode,
782 &image->exception);
783 if (status == MagickFalse)
784 return(status);
785 }
cristybb503372010-05-27 20:51:26 +0000786 for (y=0; y < (ssize_t) chroma_image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000787 {
788 p=GetVirtualPixels(chroma_image,0,y,chroma_image->columns,1,
789 &chroma_image->exception);
790 if (p == (const PixelPacket *) NULL)
791 break;
cristybb503372010-05-27 20:51:26 +0000792 for (x=0; x < (ssize_t) chroma_image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000793 {
cristy292ebf12011-02-08 20:21:31 +0000794 if (quantum == 1)
795 (void) WriteBlobByte(image,ScaleQuantumToChar(
796 GetBluePixelComponent(p)));
797 else
798 (void) WriteBlobShort(image,ScaleQuantumToShort(
799 GetBluePixelComponent(p)));
cristy3ed852e2009-09-05 21:47:34 +0000800 p++;
801 }
802 }
803 if (image->previous == (Image *) NULL)
804 {
805 status=SetImageProgress(image,SaveImageTag,2,3);
806 if (status == MagickFalse)
807 break;
808 }
809 }
810 chroma_image=DestroyImage(chroma_image);
811 if (interlace == PartitionInterlace)
812 (void) CopyMagickString(image->filename,image_info->filename,
813 MaxTextExtent);
814 if (GetNextImageInList(image) == (Image *) NULL)
815 break;
816 image=SyncNextImageInList(image);
817 status=SetImageProgress(image,SaveImagesTag,scene++,
818 GetImageListLength(image));
819 if (status == MagickFalse)
820 break;
821 } while (image_info->adjoin != MagickFalse);
822 (void) CloseBlob(image);
823 return(MagickTrue);
824}