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