blob: 1a29b7dc05335e0fdbb615dc9b34888e49d3f4bf [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% Y Y YYYC BBBB YYYC RRRR %
7% Y Y C B B C R R %
8% Y C BBBB C RRRR %
9% Y C B B C R R %
10% Y YYYC BBBB YYYC R R %
11% %
12% %
13% Read/Write Raw YCbCr Image Format %
14% %
15% Software Design %
16% John Cristy %
17% July 1992 %
18% %
19% %
20% Copyright 1999-2009 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 "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/image.h"
51#include "magick/image-private.h"
52#include "magick/list.h"
53#include "magick/magick.h"
54#include "magick/memory_.h"
55#include "magick/monitor.h"
56#include "magick/monitor-private.h"
57#include "magick/pixel-private.h"
58#include "magick/quantum-private.h"
59#include "magick/static.h"
60#include "magick/statistic.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 WriteYCBCRImage(const ImageInfo *,Image *);
70
71/*
72%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
73% %
74% %
75% %
76% R e a d Y C b C r I m a g e %
77% %
78% %
79% %
80%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
81%
82% ReadYCBCRImage() reads an image of raw YCbCr or YCbCrA samples and returns
83% it. It allocates the memory necessary for the new Image structure and
84% returns a pointer to the new image.
85%
86% The format of the ReadYCBCRImage method is:
87%
88% Image *ReadYCBCRImage(const ImageInfo *image_info,
89% 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 *ReadYCBCRImage(const ImageInfo *image_info,
99 ExceptionInfo *exception)
100{
101 Image
102 *canvas_image,
103 *image;
104
105 long
106 y;
107
108 MagickBooleanType
109 status;
110
111 MagickOffsetType
112 scene;
113
114 QuantumInfo
115 *quantum_info;
116
117 QuantumType
118 quantum_type;
119
120 register const PixelPacket
121 *p;
122
123 register long
124 i,
125 x;
126
127 register PixelPacket
128 *q;
129
130 ssize_t
131 count;
132
133 size_t
134 length;
135
136 unsigned char
137 *pixels;
138
139 /*
140 Open image file.
141 */
142 assert(image_info != (const ImageInfo *) NULL);
143 assert(image_info->signature == MagickSignature);
144 if (image_info->debug != MagickFalse)
145 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
146 image_info->filename);
147 assert(exception != (ExceptionInfo *) NULL);
148 assert(exception->signature == MagickSignature);
149 image=AcquireImage(image_info);
150 if ((image->columns == 0) || (image->rows == 0))
151 ThrowReaderException(OptionError,"MustSpecifyImageSize");
152 image->colorspace=YCbCrColorspace;
153 if (image_info->interlace != PartitionInterlace)
154 {
155 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
156 if (status == MagickFalse)
157 {
158 image=DestroyImageList(image);
159 return((Image *) NULL);
160 }
161 for (i=0; i < image->offset; i++)
162 if (ReadBlobByte(image) == EOF)
163 {
164 ThrowFileException(exception,CorruptImageError,
165 "UnexpectedEndOfFile",image->filename);
166 break;
167 }
168 }
169 /*
170 Create virtual canvas to support cropping (i.e. image.rgb[100x100+10+20]).
171 */
172 canvas_image=CloneImage(image,image->extract_info.width,1,MagickFalse,
173 exception);
174 (void) SetImageVirtualPixelMethod(canvas_image,BlackVirtualPixelMethod);
175 quantum_info=AcquireQuantumInfo(image_info,canvas_image);
176 if (quantum_info == (QuantumInfo *) NULL)
177 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
178 pixels=GetQuantumPixels(quantum_info);
179 quantum_type=RGBQuantum;
180 if (LocaleCompare(image_info->magick,"YCbCrA") == 0)
181 {
182 quantum_type=RGBAQuantum;
183 image->matte=MagickTrue;
184 }
185 if (image_info->number_scenes != 0)
186 while (image->scene < image_info->scene)
187 {
188 /*
189 Skip to next image.
190 */
191 image->scene++;
192 length=GetQuantumExtent(canvas_image,quantum_info,quantum_type);
193 for (y=0; y < (long) image->rows; y++)
194 {
195 count=ReadBlob(image,length,pixels);
196 if (count != (ssize_t) length)
197 break;
198 }
199 }
200 count=0;
201 length=0;
202 scene=0;
203 do
204 {
205 /*
206 Read pixels to virtual canvas image then push to image.
207 */
208 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
209 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
210 break;
211 image->colorspace=YCbCrColorspace;
212 switch (image_info->interlace)
213 {
214 case NoInterlace:
215 default:
216 {
217 /*
218 No interlacing: YCbCrYCbCrYCbCrYCbCrYCbCrYCbCr...
219 */
220 if (scene == 0)
221 {
222 length=GetQuantumExtent(canvas_image,quantum_info,quantum_type);
223 count=ReadBlob(image,length,pixels);
cristy3ed852e2009-09-05 21:47:34 +0000224 }
225 for (y=0; y < (long) image->extract_info.height; y++)
226 {
cristy21da32d2009-09-12 14:56:09 +0000227 if (count != (ssize_t) length)
228 {
229 ThrowFileException(exception,CorruptImageError,
230 "UnexpectedEndOfFile",image->filename);
231 break;
232 }
cristy3ed852e2009-09-05 21:47:34 +0000233 q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
234 exception);
235 if (q == (PixelPacket *) NULL)
236 break;
237 length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
238 quantum_info,quantum_type,pixels,exception);
239 if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
240 break;
241 if (((y-image->extract_info.y) >= 0) &&
242 ((y-image->extract_info.y) < (long) image->rows))
243 {
244 p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
245 canvas_image->columns,1,exception);
246 q=QueueAuthenticPixels(image,0,y-image->extract_info.y,
247 image->columns,1,exception);
248 if ((p == (const PixelPacket *) NULL) ||
249 (q == (PixelPacket *) NULL))
250 break;
251 for (x=0; x < (long) image->columns; x++)
252 {
253 q->red=p->red;
254 q->green=p->green;
255 q->blue=p->blue;
256 if (image->matte != MagickFalse)
257 q->opacity=p->opacity;
258 p++;
259 q++;
260 }
261 if (SyncAuthenticPixels(image,exception) == MagickFalse)
262 break;
263 }
264 if (image->previous == (Image *) NULL)
265 {
266 status=SetImageProgress(image,LoadImageTag,y,image->rows);
267 if (status == MagickFalse)
268 break;
269 }
270 count=ReadBlob(image,length,pixels);
cristy3ed852e2009-09-05 21:47:34 +0000271 }
272 break;
273 }
274 case LineInterlace:
275 {
276 static QuantumType
277 quantum_types[4] =
278 {
279 RedQuantum,
280 GreenQuantum,
281 BlueQuantum,
282 OpacityQuantum
283 };
284
285 /*
286 Line interlacing: YYY...CbCbCb...CrCrCr...YYY...CbCbCb...CrCrCr...
287 */
288 if (scene == 0)
289 {
290 length=GetQuantumExtent(canvas_image,quantum_info,RedQuantum);
291 count=ReadBlob(image,length,pixels);
cristy3ed852e2009-09-05 21:47:34 +0000292 }
293 for (y=0; y < (long) image->extract_info.height; y++)
294 {
295 for (i=0; i < (image->matte != MagickFalse ? 4 : 3); i++)
296 {
cristy21da32d2009-09-12 14:56:09 +0000297 if (count != (ssize_t) length)
298 {
299 ThrowFileException(exception,CorruptImageError,
300 "UnexpectedEndOfFile",image->filename);
301 break;
302 }
cristy3ed852e2009-09-05 21:47:34 +0000303 quantum_type=quantum_types[i];
304 q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
305 exception);
306 if (q == (PixelPacket *) NULL)
307 break;
308 length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
309 quantum_info,quantum_type,pixels,exception);
310 if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
311 break;
312 if (((y-image->extract_info.y) >= 0) &&
313 ((y-image->extract_info.y) < (long) image->rows))
314 {
315 p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,
316 0,canvas_image->columns,1,exception);
317 q=GetAuthenticPixels(image,0,y-image->extract_info.y,
318 image->columns,1,exception);
319 if ((p == (const PixelPacket *) NULL) ||
320 (q == (PixelPacket *) NULL))
321 break;
322 for (x=0; x < (long) image->columns; x++)
323 {
324 switch (quantum_type)
325 {
326 case RedQuantum: q->red=p->red; break;
327 case GreenQuantum: q->green=p->green; break;
328 case BlueQuantum: q->blue=p->blue; break;
329 case OpacityQuantum: q->opacity=p->opacity; break;
330 default: break;
331 }
332 p++;
333 q++;
334 }
335 if (SyncAuthenticPixels(image,exception) == MagickFalse)
336 break;
337 }
338 count=ReadBlob(image,length,pixels);
cristy3ed852e2009-09-05 21:47:34 +0000339 }
340 if (image->previous == (Image *) NULL)
341 {
342 status=SetImageProgress(image,LoadImageTag,y,image->rows);
343 if (status == MagickFalse)
344 break;
345 }
346 }
347 break;
348 }
349 case PlaneInterlace:
350 {
351 /*
352 Plane interlacing: YYYYYY...CbCbCbCbCbCb...CrCrCrCrCrCr...
353 */
354 if (scene == 0)
355 {
356 length=GetQuantumExtent(canvas_image,quantum_info,RedQuantum);
357 count=ReadBlob(image,length,pixels);
cristy3ed852e2009-09-05 21:47:34 +0000358 }
359 for (y=0; y < (long) image->extract_info.height; y++)
360 {
cristy21da32d2009-09-12 14:56:09 +0000361 if (count != (ssize_t) length)
362 {
363 ThrowFileException(exception,CorruptImageError,
364 "UnexpectedEndOfFile",image->filename);
365 break;
366 }
cristy3ed852e2009-09-05 21:47:34 +0000367 q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
368 exception);
369 if (q == (PixelPacket *) NULL)
370 break;
371 length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
372 quantum_info,RedQuantum,pixels,exception);
373 if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
374 break;
375 if (((y-image->extract_info.y) >= 0) &&
376 ((y-image->extract_info.y) < (long) image->rows))
377 {
378 p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
379 canvas_image->columns,1,exception);
380 q=GetAuthenticPixels(image,0,y-image->extract_info.y,
381 image->columns,1,exception);
382 if ((p == (const PixelPacket *) NULL) ||
383 (q == (PixelPacket *) NULL))
384 break;
385 for (x=0; x < (long) image->columns; x++)
386 {
387 q->red=p->red;
388 p++;
389 q++;
390 }
391 if (SyncAuthenticPixels(image,exception) == MagickFalse)
392 break;
393 }
394 count=ReadBlob(image,length,pixels);
cristy3ed852e2009-09-05 21:47:34 +0000395 }
396 if (image->previous == (Image *) NULL)
397 {
398 status=SetImageProgress(image,LoadImageTag,1,5);
399 if (status == MagickFalse)
400 break;
401 }
402 for (y=0; y < (long) image->extract_info.height; y++)
403 {
cristy21da32d2009-09-12 14:56:09 +0000404 if (count != (ssize_t) length)
405 {
406 ThrowFileException(exception,CorruptImageError,
407 "UnexpectedEndOfFile",image->filename);
408 break;
409 }
cristy3ed852e2009-09-05 21:47:34 +0000410 q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
411 exception);
412 if (q == (PixelPacket *) NULL)
413 break;
414 length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
415 quantum_info,GreenQuantum,pixels,exception);
416 if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
417 break;
418 if (((y-image->extract_info.y) >= 0) &&
419 ((y-image->extract_info.y) < (long) image->rows))
420 {
421 p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
422 canvas_image->columns,1,exception);
423 q=GetAuthenticPixels(image,0,y-image->extract_info.y,
424 image->columns,1,exception);
425 if ((p == (const PixelPacket *) NULL) ||
426 (q == (PixelPacket *) NULL))
427 break;
428 for (x=0; x < (long) image->columns; x++)
429 {
430 q->green=p->green;
431 p++;
432 q++;
433 }
434 if (SyncAuthenticPixels(image,exception) == MagickFalse)
435 break;
436 }
437 count=ReadBlob(image,length,pixels);
cristy3ed852e2009-09-05 21:47:34 +0000438 }
439 if (image->previous == (Image *) NULL)
440 {
441 status=SetImageProgress(image,LoadImageTag,2,5);
442 if (status == MagickFalse)
443 break;
444 }
445 for (y=0; y < (long) image->extract_info.height; y++)
446 {
cristy21da32d2009-09-12 14:56:09 +0000447 if (count != (ssize_t) length)
448 {
449 ThrowFileException(exception,CorruptImageError,
450 "UnexpectedEndOfFile",image->filename);
451 break;
452 }
cristy3ed852e2009-09-05 21:47:34 +0000453 q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
454 exception);
455 if (q == (PixelPacket *) NULL)
456 break;
457 length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
458 quantum_info,BlueQuantum,pixels,exception);
459 if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
460 break;
461 if (((y-image->extract_info.y) >= 0) &&
462 ((y-image->extract_info.y) < (long) image->rows))
463 {
464 p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
465 canvas_image->columns,1,exception);
466 q=GetAuthenticPixels(image,0,y-image->extract_info.y,
467 image->columns,1,exception);
468 if ((p == (const PixelPacket *) NULL) ||
469 (q == (PixelPacket *) NULL))
470 break;
471 for (x=0; x < (long) image->columns; x++)
472 {
473 q->blue=p->blue;
474 p++;
475 q++;
476 }
477 if (SyncAuthenticPixels(image,exception) == MagickFalse)
478 break;
479 }
480 count=ReadBlob(image,length,pixels);
cristy3ed852e2009-09-05 21:47:34 +0000481 }
482 if (image->previous == (Image *) NULL)
483 {
484 status=SetImageProgress(image,LoadImageTag,3,5);
485 if (status == MagickFalse)
486 break;
487 }
488 if (image->matte != MagickFalse)
489 {
490 for (y=0; y < (long) image->extract_info.height; y++)
491 {
cristy21da32d2009-09-12 14:56:09 +0000492 if (count != (ssize_t) length)
493 {
494 ThrowFileException(exception,CorruptImageError,
495 "UnexpectedEndOfFile",image->filename);
496 break;
497 }
cristy3ed852e2009-09-05 21:47:34 +0000498 q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
499 exception);
500 if (q == (PixelPacket *) NULL)
501 break;
502 length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
503 quantum_info,AlphaQuantum,pixels,exception);
504 if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
505 break;
506 if (((y-image->extract_info.y) >= 0) &&
507 ((y-image->extract_info.y) < (long) image->rows))
508 {
509 p=GetVirtualPixels(canvas_image,
510 canvas_image->extract_info.x,0,canvas_image->columns,1,
511 exception);
512 q=GetAuthenticPixels(image,0,y-image->extract_info.y,
513 image->columns,1,exception);
514 if ((p == (const PixelPacket *) NULL) ||
515 (q == (PixelPacket *) NULL))
516 break;
517 for (x=0; x < (long) image->columns; x++)
518 {
519 q->opacity=p->opacity;
520 p++;
521 q++;
522 }
523 if (SyncAuthenticPixels(image,exception) == MagickFalse)
524 break;
525 }
526 count=ReadBlob(image,length,pixels);
cristy3ed852e2009-09-05 21:47:34 +0000527 }
528 if (image->previous == (Image *) NULL)
529 {
530 status=SetImageProgress(image,LoadImageTag,4,5);
531 if (status == MagickFalse)
532 break;
533 }
534 }
535 if (image->previous == (Image *) NULL)
536 {
537 status=SetImageProgress(image,LoadImageTag,5,5);
538 if (status == MagickFalse)
539 break;
540 }
541 break;
542 }
543 case PartitionInterlace:
544 {
545 /*
546 Partition interlacing: YYYYYY..., CbCbCbCbCbCb..., CrCrCrCrCrCr...
547 */
548 AppendImageFormat("Y",image->filename);
549 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
550 if (status == MagickFalse)
551 {
552 canvas_image=DestroyImageList(canvas_image);
553 image=DestroyImageList(image);
554 return((Image *) NULL);
555 }
556 for (i=0; i < image->offset; i++)
557 if (ReadBlobByte(image) == EOF)
558 {
559 ThrowFileException(exception,CorruptImageError,
560 "UnexpectedEndOfFile",image->filename);
561 break;
562 }
563 length=GetQuantumExtent(canvas_image,quantum_info,RedQuantum);
564 for (i=0; i < (long) scene; i++)
565 for (y=0; y < (long) image->extract_info.height; y++)
566 if (ReadBlob(image,length,pixels) != (ssize_t) length)
567 {
568 ThrowFileException(exception,CorruptImageError,
569 "UnexpectedEndOfFile",image->filename);
570 break;
571 }
572 count=ReadBlob(image,length,pixels);
cristy3ed852e2009-09-05 21:47:34 +0000573 for (y=0; y < (long) image->extract_info.height; y++)
574 {
cristy21da32d2009-09-12 14:56:09 +0000575 if (count != (ssize_t) length)
576 {
577 ThrowFileException(exception,CorruptImageError,
578 "UnexpectedEndOfFile",image->filename);
579 break;
580 }
cristy3ed852e2009-09-05 21:47:34 +0000581 q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
582 exception);
583 if (q == (PixelPacket *) NULL)
584 break;
585 length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
586 quantum_info,RedQuantum,pixels,exception);
587 if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
588 break;
589 if (((y-image->extract_info.y) >= 0) &&
590 ((y-image->extract_info.y) < (long) image->rows))
591 {
592 p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
593 canvas_image->columns,1,exception);
594 q=GetAuthenticPixels(image,0,y-image->extract_info.y,
595 image->columns,1,exception);
596 if ((p == (const PixelPacket *) NULL) ||
597 (q == (PixelPacket *) NULL))
598 break;
599 for (x=0; x < (long) image->columns; x++)
600 {
601 q->red=p->red;
602 p++;
603 q++;
604 }
605 if (SyncAuthenticPixels(image,exception) == MagickFalse)
606 break;
607 }
608 count=ReadBlob(image,length,pixels);
cristy3ed852e2009-09-05 21:47:34 +0000609 }
610 if (image->previous == (Image *) NULL)
611 {
612 status=SetImageProgress(image,LoadImageTag,1,5);
613 if (status == MagickFalse)
614 break;
615 }
616 (void) CloseBlob(image);
617 AppendImageFormat("Cb",image->filename);
618 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
619 if (status == MagickFalse)
620 {
621 canvas_image=DestroyImageList(canvas_image);
622 image=DestroyImageList(image);
623 return((Image *) NULL);
624 }
625 length=GetQuantumExtent(canvas_image,quantum_info,GreenQuantum);
626 for (i=0; i < (long) scene; i++)
627 for (y=0; y < (long) image->extract_info.height; y++)
628 if (ReadBlob(image,length,pixels) != (ssize_t) length)
629 {
630 ThrowFileException(exception,CorruptImageError,
631 "UnexpectedEndOfFile",image->filename);
632 break;
633 }
634 count=ReadBlob(image,length,pixels);
cristy3ed852e2009-09-05 21:47:34 +0000635 for (y=0; y < (long) image->extract_info.height; y++)
636 {
cristy21da32d2009-09-12 14:56:09 +0000637 if (count != (ssize_t) length)
638 {
639 ThrowFileException(exception,CorruptImageError,
640 "UnexpectedEndOfFile",image->filename);
641 break;
642 }
cristy3ed852e2009-09-05 21:47:34 +0000643 q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
644 exception);
645 if (q == (PixelPacket *) NULL)
646 break;
647 length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
648 quantum_info,GreenQuantum,pixels,exception);
649 if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
650 break;
651 if (((y-image->extract_info.y) >= 0) &&
652 ((y-image->extract_info.y) < (long) image->rows))
653 {
654 p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
655 canvas_image->columns,1,exception);
656 q=GetAuthenticPixels(image,0,y-image->extract_info.y,
657 image->columns,1,exception);
658 if ((p == (const PixelPacket *) NULL) ||
659 (q == (PixelPacket *) NULL))
660 break;
661 for (x=0; x < (long) image->columns; x++)
662 {
663 q->green=p->green;
664 p++;
665 q++;
666 }
667 if (SyncAuthenticPixels(image,exception) == MagickFalse)
668 break;
669 }
670 count=ReadBlob(image,length,pixels);
cristy3ed852e2009-09-05 21:47:34 +0000671 }
672 if (image->previous == (Image *) NULL)
673 {
674 status=SetImageProgress(image,LoadImageTag,2,5);
675 if (status == MagickFalse)
676 break;
677 }
678 (void) CloseBlob(image);
679 AppendImageFormat("Cr",image->filename);
680 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
681 if (status == MagickFalse)
682 {
683 canvas_image=DestroyImageList(canvas_image);
684 image=DestroyImageList(image);
685 return((Image *) NULL);
686 }
687 length=GetQuantumExtent(canvas_image,quantum_info,BlueQuantum);
688 for (i=0; i < (long) scene; i++)
689 for (y=0; y < (long) image->extract_info.height; y++)
690 if (ReadBlob(image,length,pixels) != (ssize_t) length)
691 {
692 ThrowFileException(exception,CorruptImageError,
693 "UnexpectedEndOfFile",image->filename);
694 break;
695 }
696 count=ReadBlob(image,length,pixels);
cristy3ed852e2009-09-05 21:47:34 +0000697 for (y=0; y < (long) image->extract_info.height; y++)
698 {
cristy21da32d2009-09-12 14:56:09 +0000699 if (count != (ssize_t) length)
700 {
701 ThrowFileException(exception,CorruptImageError,
702 "UnexpectedEndOfFile",image->filename);
703 break;
704 }
cristy3ed852e2009-09-05 21:47:34 +0000705 q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
706 exception);
707 if (q == (PixelPacket *) NULL)
708 break;
709 length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
710 quantum_info,BlueQuantum,pixels,exception);
711 if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
712 break;
713 if (((y-image->extract_info.y) >= 0) &&
714 ((y-image->extract_info.y) < (long) image->rows))
715 {
716 p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
717 canvas_image->columns,1,exception);
718 q=GetAuthenticPixels(image,0,y-image->extract_info.y,
719 image->columns,1,exception);
720 if ((p == (const PixelPacket *) NULL) ||
721 (q == (PixelPacket *) NULL))
722 break;
723 for (x=0; x < (long) image->columns; x++)
724 {
725 q->blue=p->blue;
726 p++;
727 q++;
728 }
729 if (SyncAuthenticPixels(image,exception) == MagickFalse)
730 break;
731 }
732 count=ReadBlob(image,length,pixels);
cristy3ed852e2009-09-05 21:47:34 +0000733 }
734 if (image->previous == (Image *) NULL)
735 {
736 status=SetImageProgress(image,LoadImageTag,3,5);
737 if (status == MagickFalse)
738 break;
739 }
740 if (image->matte != MagickFalse)
741 {
742 (void) CloseBlob(image);
743 AppendImageFormat("A",image->filename);
744 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
745 if (status == MagickFalse)
746 {
747 canvas_image=DestroyImageList(canvas_image);
748 image=DestroyImageList(image);
749 return((Image *) NULL);
750 }
751 length=GetQuantumExtent(canvas_image,quantum_info,AlphaQuantum);
752 for (i=0; i < (long) scene; i++)
753 for (y=0; y < (long) image->extract_info.height; y++)
754 if (ReadBlob(image,length,pixels) != (ssize_t) length)
755 {
756 ThrowFileException(exception,CorruptImageError,
757 "UnexpectedEndOfFile",image->filename);
758 break;
759 }
760 count=ReadBlob(image,length,pixels);
cristy3ed852e2009-09-05 21:47:34 +0000761 for (y=0; y < (long) image->extract_info.height; y++)
762 {
cristy21da32d2009-09-12 14:56:09 +0000763 if (count != (ssize_t) length)
764 {
765 ThrowFileException(exception,CorruptImageError,
766 "UnexpectedEndOfFile",image->filename);
767 break;
768 }
cristy3ed852e2009-09-05 21:47:34 +0000769 q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
770 exception);
771 if (q == (PixelPacket *) NULL)
772 break;
773 length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
774 quantum_info,BlueQuantum,pixels,exception);
775 if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
776 break;
777 if (((y-image->extract_info.y) >= 0) &&
778 ((y-image->extract_info.y) < (long) image->rows))
779 {
780 p=GetVirtualPixels(canvas_image,
781 canvas_image->extract_info.x,0,canvas_image->columns,1,
782 exception);
783 q=GetAuthenticPixels(image,0,y-image->extract_info.y,
784 image->columns,1,exception);
785 if ((p == (const PixelPacket *) NULL) ||
786 (q == (PixelPacket *) NULL))
787 break;
788 for (x=0; x < (long) image->columns; x++)
789 {
790 q->opacity=p->opacity;
791 p++;
792 q++;
793 }
794 if (SyncAuthenticPixels(image,exception) == MagickFalse)
795 break;
796 }
797 count=ReadBlob(image,length,pixels);
cristy3ed852e2009-09-05 21:47:34 +0000798 }
799 if (image->previous == (Image *) NULL)
800 {
801 status=SetImageProgress(image,LoadImageTag,4,5);
802 if (status == MagickFalse)
803 break;
804 }
805 }
806 if (image->previous == (Image *) NULL)
807 {
808 status=SetImageProgress(image,LoadImageTag,5,5);
809 if (status == MagickFalse)
810 break;
811 }
812 break;
813 }
814 }
815 SetQuantumImageType(image,quantum_type);
cristy3ed852e2009-09-05 21:47:34 +0000816 /*
817 Proceed to next image.
818 */
819 if (image_info->number_scenes != 0)
820 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
821 break;
822 if (count == (ssize_t) length)
823 {
824 /*
825 Allocate next image structure.
826 */
827 AcquireNextImage(image_info,image);
828 if (GetNextImageInList(image) == (Image *) NULL)
829 {
830 image=DestroyImageList(image);
831 return((Image *) NULL);
832 }
833 image=SyncNextImageInList(image);
834 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
835 GetBlobSize(image));
836 if (status == MagickFalse)
837 break;
838 }
839 scene++;
840 } while (count == (ssize_t) length);
cristy3ed852e2009-09-05 21:47:34 +0000841 quantum_info=DestroyQuantumInfo(quantum_info);
cristy01a3f332009-10-27 14:17:37 +0000842 InheritException(&image->exception,&canvas_image->exception);
cristy3ed852e2009-09-05 21:47:34 +0000843 canvas_image=DestroyImage(canvas_image);
844 (void) CloseBlob(image);
845 return(GetFirstImageInList(image));
846}
847
848/*
849%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
850% %
851% %
852% %
853% R e g i s t e r Y C b C r I m a g e %
854% %
855% %
856% %
857%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
858%
859% RegisterYCBCRImage() adds attributes for the YCbCr or YCbCrA image format to
860% the list of supported formats. The attributes include the image format
861% tag, a method to read and/or write the format, whether the format
862% supports the saving of more than one frame to the same file or blob,
863% whether the format supports native in-memory I/O, and a brief
864% description of the format.
865%
866% The format of the RegisterYCBCRImage method is:
867%
868% unsigned long RegisterYCBCRImage(void)
869%
870*/
871ModuleExport unsigned long RegisterYCBCRImage(void)
872{
873 MagickInfo
874 *entry;
875
876 entry=SetMagickInfo("YCbCr");
877 entry->decoder=(DecodeImageHandler *) ReadYCBCRImage;
878 entry->encoder=(EncodeImageHandler *) WriteYCBCRImage;
879 entry->raw=MagickTrue;
880 entry->endian_support=MagickTrue;
881 entry->description=ConstantString("Raw Y, Cb, and Cr samples");
882 entry->module=ConstantString("YCbCr");
883 (void) RegisterMagickInfo(entry);
884 entry=SetMagickInfo("YCbCrA");
885 entry->decoder=(DecodeImageHandler *) ReadYCBCRImage;
886 entry->encoder=(EncodeImageHandler *) WriteYCBCRImage;
887 entry->raw=MagickTrue;
888 entry->endian_support=MagickTrue;
889 entry->description=ConstantString("Raw Y, Cb, Cr, and alpha samples");
890 entry->module=ConstantString("YCbCr");
891 (void) RegisterMagickInfo(entry);
892 return(MagickImageCoderSignature);
893}
894
895/*
896%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
897% %
898% %
899% %
900% U n r e g i s t e r Y C b C r I m a g e %
901% %
902% %
903% %
904%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
905%
906% UnregisterYCBCRImage() removes format registrations made by the
907% YCbCr module from the list of supported formats.
908%
909% The format of the UnregisterYCBCRImage method is:
910%
911% UnregisterYCBCRImage(void)
912%
913*/
914ModuleExport void UnregisterYCBCRImage(void)
915{
916 (void) UnregisterMagickInfo("YCbCr");
917 (void) UnregisterMagickInfo("YCbCrA");
918}
919
920/*
921%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
922% %
923% %
924% %
925% W r i t e Y C b C r I m a g e %
926% %
927% %
928% %
929%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
930%
931% WriteYCBCRImage() writes an image to a file in the YCbCr or YCbCrA
932% rasterfile format.
933%
934% The format of the WriteYCBCRImage method is:
935%
936% MagickBooleanType WriteYCBCRImage(const ImageInfo *image_info,
937% Image *image)
938%
939% A description of each parameter follows.
940%
941% o image_info: the image info.
942%
943% o image: The image.
944%
945*/
946static MagickBooleanType WriteYCBCRImage(const ImageInfo *image_info,
947 Image *image)
948{
949 long
950 y;
951
952 MagickBooleanType
953 status;
954
955 MagickOffsetType
956 scene;
957
958 QuantumInfo
959 *quantum_info;
960
961 QuantumType
962 quantum_type;
963
964 register const PixelPacket
965 *p;
966
967 ssize_t
968 count;
969
970 size_t
971 length;
972
973 unsigned char
974 *pixels;
975
976 /*
977 Allocate memory for pixels.
978 */
979 assert(image_info != (const ImageInfo *) NULL);
980 assert(image_info->signature == MagickSignature);
981 assert(image != (Image *) NULL);
982 assert(image->signature == MagickSignature);
983 if (image->debug != MagickFalse)
984 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
985 if (image_info->interlace != PartitionInterlace)
986 {
987 /*
988 Open output image file.
989 */
990 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
991 if (status == MagickFalse)
992 return(status);
993 }
994 quantum_type=RGBQuantum;
995 if (LocaleCompare(image_info->magick,"YCbCrA") == 0)
996 {
997 quantum_type=RGBAQuantum;
998 image->matte=MagickTrue;
999 }
1000 scene=0;
1001 do
1002 {
1003 /*
1004 Convert MIFF to YCbCr raster pixels.
1005 */
1006 if (image->colorspace != YCbCrColorspace)
1007 (void) TransformImageColorspace(image,YCbCrColorspace);
1008 if ((LocaleCompare(image_info->magick,"YCbCrA") == 0) &&
1009 (image->matte == MagickFalse))
1010 (void) SetImageAlphaChannel(image,ResetAlphaChannel);
1011 quantum_info=AcquireQuantumInfo(image_info,image);
1012 if (quantum_info == (QuantumInfo *) NULL)
1013 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1014 pixels=GetQuantumPixels(quantum_info);
1015 switch (image_info->interlace)
1016 {
1017 case NoInterlace:
1018 default:
1019 {
1020 /*
1021 No interlacing: YCbCrYCbCrYCbCrYCbCrYCbCrYCbCr...
1022 */
1023 for (y=0; y < (long) image->rows; y++)
1024 {
1025 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1026 if (p == (const PixelPacket *) NULL)
1027 break;
1028 length=ExportQuantumPixels(image,(const CacheView *) NULL,quantum_info,
1029 quantum_type,pixels,&image->exception);
1030 count=WriteBlob(image,length,pixels);
1031 if (count != (ssize_t) length)
1032 break;
1033 if (image->previous == (Image *) NULL)
1034 {
1035 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1036 if (status == MagickFalse)
1037 break;
1038 }
1039 }
1040 break;
1041 }
1042 case LineInterlace:
1043 {
1044 /*
1045 Line interlacing: YYY...CbCbCb...CrCrCr...YYY...CbCbCb...CrCrCr...
1046 */
1047 for (y=0; y < (long) image->rows; y++)
1048 {
1049 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1050 if (p == (const PixelPacket *) NULL)
1051 break;
1052 length=ExportQuantumPixels(image,(const CacheView *) NULL,quantum_info,
1053 RedQuantum,pixels,&image->exception);
1054 count=WriteBlob(image,length,pixels);
1055 if (count != (ssize_t) length)
1056 break;
1057 length=ExportQuantumPixels(image,(const CacheView *) NULL,quantum_info,
1058 GreenQuantum,pixels,&image->exception);
1059 count=WriteBlob(image,length,pixels);
1060 if (count != (ssize_t) length)
1061 break;
1062 length=ExportQuantumPixels(image,(const CacheView *) NULL,quantum_info,
1063 BlueQuantum,pixels,&image->exception);
1064 count=WriteBlob(image,length,pixels);
1065 if (count != (ssize_t) length)
1066 break;
1067 if (quantum_type == RGBAQuantum)
1068 {
1069 length=ExportQuantumPixels(image,(const CacheView *) NULL,
1070 quantum_info,AlphaQuantum,pixels,&image->exception);
1071 count=WriteBlob(image,length,pixels);
1072 if (count != (ssize_t) length)
1073 break;
1074 }
1075 if (image->previous == (Image *) NULL)
1076 {
1077 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1078 if (status == MagickFalse)
1079 break;
1080 }
1081 }
1082 break;
1083 }
1084 case PlaneInterlace:
1085 {
1086 /*
1087 Plane interlacing: YYYYYY...CbCbCbCbCbCb...CrCrCrCrCrCr...
1088 */
1089 for (y=0; y < (long) image->rows; y++)
1090 {
1091 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1092 if (p == (const PixelPacket *) NULL)
1093 break;
1094 length=ExportQuantumPixels(image,(const CacheView *) NULL,quantum_info,
1095 RedQuantum,pixels,&image->exception);
1096 count=WriteBlob(image,length,pixels);
1097 if (count != (ssize_t) length)
1098 break;
1099 }
1100 if (image->previous == (Image *) NULL)
1101 {
1102 status=SetImageProgress(image,SaveImageTag,1,5);
1103 if (status == MagickFalse)
1104 break;
1105 }
1106 for (y=0; y < (long) image->rows; y++)
1107 {
1108 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1109 if (p == (const PixelPacket *) NULL)
1110 break;
1111 length=ExportQuantumPixels(image,(const CacheView *) NULL,quantum_info,
1112 GreenQuantum,pixels,&image->exception);
1113 count=WriteBlob(image,length,pixels);
1114 if (count != (ssize_t) length)
1115 break;
1116 }
1117 if (image->previous == (Image *) NULL)
1118 {
1119 status=SetImageProgress(image,SaveImageTag,2,5);
1120 if (status == MagickFalse)
1121 break;
1122 }
1123 for (y=0; y < (long) image->rows; y++)
1124 {
1125 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1126 if (p == (const PixelPacket *) NULL)
1127 break;
1128 length=ExportQuantumPixels(image,(const CacheView *) NULL,quantum_info,
1129 BlueQuantum,pixels,&image->exception);
1130 count=WriteBlob(image,length,pixels);
1131 if (count != (ssize_t) length)
1132 break;
1133 }
1134 if (image->previous == (Image *) NULL)
1135 {
1136 status=SetImageProgress(image,SaveImageTag,3,5);
1137 if (status == MagickFalse)
1138 break;
1139 }
1140 if (quantum_type == RGBAQuantum)
1141 {
1142 for (y=0; y < (long) image->rows; y++)
1143 {
1144 p=GetVirtualPixels(image,0,y,image->columns,1,
1145 &image->exception);
1146 if (p == (const PixelPacket *) NULL)
1147 break;
1148 length=ExportQuantumPixels(image,(const CacheView *) NULL,
1149 quantum_info,AlphaQuantum,pixels,&image->exception);
1150 count=WriteBlob(image,length,pixels);
1151 if (count != (ssize_t) length)
1152 break;
1153 }
1154 }
1155 if (image_info->interlace == PartitionInterlace)
1156 (void) CopyMagickString(image->filename,image_info->filename,
1157 MaxTextExtent);
1158 if (image->previous == (Image *) NULL)
1159 {
1160 status=SetImageProgress(image,SaveImageTag,5,5);
1161 if (status == MagickFalse)
1162 break;
1163 }
1164 break;
1165 }
1166 case PartitionInterlace:
1167 {
1168 /*
1169 Partition interlacing: YYYYYY..., CbCbCbCbCbCb..., CrCrCrCrCrCr...
1170 */
1171 AppendImageFormat("Y",image->filename);
1172 status=OpenBlob(image_info,image,scene == 0 ? WriteBinaryBlobMode :
1173 AppendBinaryBlobMode,&image->exception);
1174 if (status == MagickFalse)
1175 return(status);
1176 for (y=0; y < (long) image->rows; y++)
1177 {
1178 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1179 if (p == (const PixelPacket *) NULL)
1180 break;
1181 length=ExportQuantumPixels(image,(const CacheView *) NULL,quantum_info,
1182 RedQuantum,pixels,&image->exception);
1183 count=WriteBlob(image,length,pixels);
1184 if (count != (ssize_t) length)
1185 break;
1186 }
1187 if (image->previous == (Image *) NULL)
1188 {
1189 status=SetImageProgress(image,SaveImageTag,1,5);
1190 if (status == MagickFalse)
1191 break;
1192 }
1193 (void) CloseBlob(image);
1194 AppendImageFormat("Cb",image->filename);
1195 status=OpenBlob(image_info,image,scene == 0 ? WriteBinaryBlobMode :
1196 AppendBinaryBlobMode,&image->exception);
1197 if (status == MagickFalse)
1198 return(status);
1199 for (y=0; y < (long) image->rows; y++)
1200 {
1201 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1202 if (p == (const PixelPacket *) NULL)
1203 break;
1204 length=ExportQuantumPixels(image,(const CacheView *) NULL,quantum_info,
1205 GreenQuantum,pixels,&image->exception);
1206 count=WriteBlob(image,length,pixels);
1207 if (count != (ssize_t) length)
1208 break;
1209 }
1210 if (image->previous == (Image *) NULL)
1211 {
1212 status=SetImageProgress(image,SaveImageTag,2,5);
1213 if (status == MagickFalse)
1214 break;
1215 }
1216 (void) CloseBlob(image);
1217 AppendImageFormat("Cr",image->filename);
1218 status=OpenBlob(image_info,image,scene == 0 ? WriteBinaryBlobMode :
1219 AppendBinaryBlobMode,&image->exception);
1220 if (status == MagickFalse)
1221 return(status);
1222 for (y=0; y < (long) image->rows; y++)
1223 {
1224 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1225 if (p == (const PixelPacket *) NULL)
1226 break;
1227 length=ExportQuantumPixels(image,(const CacheView *) NULL,quantum_info,
1228 BlueQuantum,pixels,&image->exception);
1229 count=WriteBlob(image,length,pixels);
1230 if (count != (ssize_t) length)
1231 break;
1232 }
1233 if (image->previous == (Image *) NULL)
1234 {
1235 status=SetImageProgress(image,SaveImageTag,3,5);
1236 if (status == MagickFalse)
1237 break;
1238 }
1239 if (quantum_type == RGBAQuantum)
1240 {
1241 (void) CloseBlob(image);
1242 AppendImageFormat("A",image->filename);
1243 status=OpenBlob(image_info,image,scene == 0 ? WriteBinaryBlobMode :
1244 AppendBinaryBlobMode,&image->exception);
1245 if (status == MagickFalse)
1246 return(status);
1247 for (y=0; y < (long) image->rows; y++)
1248 {
1249 p=GetVirtualPixels(image,0,y,image->columns,1,
1250 &image->exception);
1251 if (p == (const PixelPacket *) NULL)
1252 break;
1253 length=ExportQuantumPixels(image,(const CacheView *) NULL,
1254 quantum_info,AlphaQuantum,pixels,&image->exception);
1255 count=WriteBlob(image,length,pixels);
1256 if (count != (ssize_t) length)
1257 break;
1258 }
1259 if (image->previous == (Image *) NULL)
1260 {
1261 status=SetImageProgress(image,SaveImageTag,4,5);
1262 if (status == MagickFalse)
1263 break;
1264 }
1265 }
1266 (void) CloseBlob(image);
1267 (void) CopyMagickString(image->filename,image_info->filename,
1268 MaxTextExtent);
1269 if (image->previous == (Image *) NULL)
1270 {
1271 status=SetImageProgress(image,SaveImageTag,5,5);
1272 if (status == MagickFalse)
1273 break;
1274 }
1275 break;
1276 }
1277 }
1278 quantum_info=DestroyQuantumInfo(quantum_info);
1279 if (GetNextImageInList(image) == (Image *) NULL)
1280 break;
1281 image=SyncNextImageInList(image);
1282 status=SetImageProgress(image,SaveImagesTag,scene++,
1283 GetImageListLength(image));
1284 if (status == MagickFalse)
1285 break;
1286 } while (image_info->adjoin != MagickFalse);
1287 (void) CloseBlob(image);
1288 return(MagickTrue);
1289}