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