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