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-2016 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
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
66/*
67  Forward declarations.
68*/
69static MagickBooleanType
70  WriteYCBCRImage(const ImageInfo *,Image *,ExceptionInfo *);
71
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*/
99static 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  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 unsigned char *) 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=(const unsigned char *) ReadBlobStream(image,length,
195          GetQuantumPixels(quantum_info),&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=(const unsigned char *) ReadBlobStream(image,length,
227              GetQuantumPixels(quantum_info),&count);
228          }
229        for (y=0; y < (ssize_t) image->extract_info.height; y++)
230        {
231          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=(const unsigned char *) ReadBlobStream(image,length,
276            GetQuantumPixels(quantum_info),&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=(const unsigned char *) ReadBlobStream(image,length,
298              GetQuantumPixels(quantum_info),&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=(const unsigned char *) ReadBlobStream(image,length,
363              GetQuantumPixels(quantum_info),&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=(const unsigned char *) ReadBlobStream(image,length,
384              GetQuantumPixels(quantum_info),&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=(const unsigned char *) ReadBlobStream(image,length,
422            GetQuantumPixels(quantum_info),&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=(const unsigned char *) ReadBlobStream(image,length,
466            GetQuantumPixels(quantum_info),&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=(const unsigned char *) ReadBlobStream(image,length,
510            GetQuantumPixels(quantum_info),&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=(const unsigned char *) ReadBlobStream(image,length,
557                GetQuantumPixels(quantum_info),&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=(const unsigned char *) ReadBlobStream(image,length,
595              GetQuantumPixels(quantum_info),&count);
596            if (count != (ssize_t) length)
597              {
598                ThrowFileException(exception,CorruptImageError,
599                  "UnexpectedEndOfFile",image->filename);
600                break;
601              }
602          }
603        pixels=(const unsigned char *) ReadBlobStream(image,length,
604          GetQuantumPixels(quantum_info),&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=(const unsigned char *) ReadBlobStream(image,length,
641            GetQuantumPixels(quantum_info),&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=(const unsigned char *) ReadBlobStream(image,length,
663              GetQuantumPixels(quantum_info),&count);
664            if (count != (ssize_t) length)
665              {
666                ThrowFileException(exception,CorruptImageError,
667                  "UnexpectedEndOfFile",image->filename);
668                break;
669              }
670          }
671        pixels=(const unsigned char *) ReadBlobStream(image,length,
672          GetQuantumPixels(quantum_info),&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=(const unsigned char *) ReadBlobStream(image,length,
709            GetQuantumPixels(quantum_info),&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=(const unsigned char *) ReadBlobStream(image,length,
731              GetQuantumPixels(quantum_info),&count);
732            if (count != (ssize_t) length)
733              {
734                ThrowFileException(exception,CorruptImageError,
735                  "UnexpectedEndOfFile",image->filename);
736                break;
737              }
738          }
739        pixels=(const unsigned char *) ReadBlobStream(image,length,
740          GetQuantumPixels(quantum_info),&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=(const unsigned char *) ReadBlobStream(image,length,
777            GetQuantumPixels(quantum_info),&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=(const unsigned char *) 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=(const unsigned char *) ReadBlobStream(image,length,
810              GetQuantumPixels(quantum_info),&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=(const unsigned char *) ReadBlobStream(image,length,
848                GetQuantumPixels(quantum_info),&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
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*/
921ModuleExport 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
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*/
960ModuleExport void UnregisterYCBCRImage(void)
961{
962  (void) UnregisterMagickInfo("YCbCr");
963  (void) UnregisterMagickInfo("YCbCrA");
964}
965
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*/
994static 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 == MagickCoreSignature);
1027  assert(image != (Image *) NULL);
1028  assert(image->signature == MagickCoreSignature);
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 == MagickCoreSignature);
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=(unsigned char *) 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}
1338