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