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