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