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