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