rgb.c revision 009d739511cb808de2f5899fe7e06be7350838e9
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%                            RRRR    GGGG  BBBB                               %
7%                            R   R  G      B   B                              %
8%                            RRRR   G  GG  BBBB                               %
9%                            R R    G   G  B   B                              %
10%                            R  R    GGG   BBBB                               %
11%                                                                             %
12%                                                                             %
13%                     Read/Write Raw RGB Image Format                         %
14%                                                                             %
15%                              Software Design                                %
16%                                John Cristy                                  %
17%                                 July 1992                                   %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2008 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 "magick/studio.h"
43#include "magick/blob.h"
44#include "magick/blob-private.h"
45#include "magick/cache.h"
46#include "magick/colorspace.h"
47#include "magick/constitute.h"
48#include "magick/exception.h"
49#include "magick/exception-private.h"
50#include "magick/image.h"
51#include "magick/image-private.h"
52#include "magick/list.h"
53#include "magick/magick.h"
54#include "magick/memory_.h"
55#include "magick/monitor.h"
56#include "magick/monitor-private.h"
57#include "magick/pixel-private.h"
58#include "magick/quantum-private.h"
59#include "magick/static.h"
60#include "magick/statistic.h"
61#include "magick/string_.h"
62#include "magick/module.h"
63#include "magick/utility.h"
64
65/*
66  Forward declarations.
67*/
68static MagickBooleanType
69  WriteRGBImage(const ImageInfo *,Image *);
70
71/*
72%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
73%                                                                             %
74%                                                                             %
75%                                                                             %
76%   R e a d R G B I m a g e                                                   %
77%                                                                             %
78%                                                                             %
79%                                                                             %
80%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
81%
82%  ReadRGBImage() reads an image of raw RGB or RGBA samples and returns it. It
83%  allocates the memory necessary for the new Image structure and returns a
84%  pointer to the new image.
85%
86%  The format of the ReadRGBImage method is:
87%
88%      Image *ReadRGBImage(const ImageInfo *image_info,ExceptionInfo *exception)
89%
90%  A description of each parameter follows:
91%
92%    o image_info: the image info.
93%
94%    o exception: return any errors or warnings in this structure.
95%
96*/
97static Image *ReadRGBImage(const ImageInfo *image_info,ExceptionInfo *exception)
98{
99  Image
100    *canvas_image,
101    *image;
102
103  ssize_t
104    y;
105
106  MagickBooleanType
107    status;
108
109  MagickOffsetType
110    scene;
111
112  QuantumInfo
113    *quantum_info;
114
115  QuantumType
116    quantum_type;
117
118  register ssize_t
119    i,
120    j;
121
122  Quantum
123    qx[3];
124
125  ssize_t
126    count;
127
128  size_t
129    length;
130
131  unsigned char
132    *pixels;
133
134  QuantumType
135    quantum_types[4];
136
137  char
138    sfx[] = {0, 0};
139
140  int
141    channels = 3;
142
143  /*
144    Open image file.
145  */
146  assert(image_info != (const ImageInfo *) NULL);
147  assert(image_info->signature == MagickSignature);
148  if (image_info->debug != MagickFalse)
149    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
150      image_info->filename);
151  assert(exception != (ExceptionInfo *) NULL);
152  assert(exception->signature == MagickSignature);
153  image=AcquireImage(image_info);
154  if ((image->columns == 0) || (image->rows == 0))
155    ThrowReaderException(OptionError,"MustSpecifyImageSize");
156  if (image_info->interlace != PartitionInterlace)
157    {
158      status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
159      if (status == MagickFalse)
160        {
161          image=DestroyImageList(image);
162          return((Image *) NULL);
163        }
164      for (i=0; i < image->offset; i++)
165        if (ReadBlobByte(image) == EOF)
166          {
167            ThrowFileException(exception,CorruptImageError,
168              "UnexpectedEndOfFile",image->filename);
169            break;
170          }
171    }
172  /*
173    Create virtual canvas to support cropping (i.e. image.rgb[100x100+10+20]).
174  */
175  canvas_image=CloneImage(image,image->extract_info.width,1,MagickFalse,
176    exception);
177  (void) SetImageVirtualPixelMethod(canvas_image,BlackVirtualPixelMethod);
178  quantum_info=AcquireQuantumInfo(image_info,canvas_image);
179  if (quantum_info == (QuantumInfo *) NULL)
180    ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
181  pixels=GetQuantumPixels(quantum_info);
182  quantum_type=RGBQuantum;
183  if (LocaleCompare(image_info->magick,"RGBA") == 0)
184    {
185      quantum_type=RGBAQuantum;
186      image->matte=MagickTrue;
187      channels=4;
188    }
189  else if (LocaleCompare(image_info->magick,"BGRA") == 0)
190    {
191      quantum_type=BGRAQuantum;
192      image->matte=MagickTrue;
193      channels=4;
194    }
195  else if (LocaleCompare(image_info->magick,"RGBO") == 0)
196    {
197      quantum_type=RGBOQuantum;
198      image->matte=MagickTrue;
199      channels=4;
200    }
201  if (image_info->number_scenes != 0)
202    while (image->scene < image_info->scene)
203    {
204      /*
205        Skip to next image.
206      */
207      image->scene++;
208      length=GetQuantumExtent(canvas_image,quantum_info,quantum_type);
209      for (y=0; y < (ssize_t) image->rows; y++)
210      {
211        count=ReadBlob(image,length,pixels);
212        if (count != (ssize_t) length)
213          break;
214      }
215    }
216  for (i=0; i < channels; i++)
217  {
218    switch(image_info->magick[i])
219    {
220      case 'R': quantum_types[i]=RedQuantum;     break;
221      case 'G': quantum_types[i]=GreenQuantum;   break;
222      case 'B': quantum_types[i]=BlueQuantum;    break;
223      case 'A': quantum_types[i]=AlphaQuantum;   break;
224      case 'O': quantum_types[i]=OpacityQuantum; break;
225    }
226  }
227  count=0;
228  length=0;
229  scene=0;
230  do
231  {
232    /*
233      Read pixels to virtual canvas image then push to image.
234    */
235    if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
236      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
237        break;
238    switch (image_info->interlace)
239    {
240      case NoInterlace:
241      default:
242      {
243        /*
244          No interlacing:  RGBRGBRGBRGBRGBRGB...
245        */
246        if (scene == 0)
247          {
248            length=GetQuantumExtent(canvas_image,quantum_info,quantum_type);
249            count=ReadBlob(image,length,pixels);
250            if (count != (ssize_t) length)
251              break;
252          }
253        for (y=0; y < (ssize_t) image->extract_info.height; y++)
254        {
255          register const PixelPacket
256            *restrict p;
257
258          register ssize_t
259            x;
260
261          register PixelPacket
262            *restrict q;
263
264          if (count != (ssize_t) length)
265            {
266              ThrowFileException(exception,CorruptImageError,
267                "UnexpectedEndOfFile",image->filename);
268              break;
269            }
270          q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
271            exception);
272          if (q == (PixelPacket *) NULL)
273            break;
274          length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
275            quantum_info,quantum_type,pixels,exception);
276          if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
277            break;
278          if (((y-image->extract_info.y) >= 0) &&
279              ((y-image->extract_info.y) < (ssize_t) image->rows))
280            {
281              p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
282                canvas_image->columns,1,exception);
283              q=QueueAuthenticPixels(image,0,y-image->extract_info.y,
284                image->columns,1,exception);
285              if ((p == (const PixelPacket *) NULL) ||
286                  (q == (PixelPacket *) NULL))
287                break;
288              for (x=0; x < (ssize_t) image->columns; x++)
289              {
290                qx[0]=GetRedPixelComponent(p);
291                qx[1]=GetGreenPixelComponent(p);
292                qx[2]=GetBluePixelComponent(p);
293                for (i=0; i < 3; i++)
294                  switch(quantum_types[i])
295                  {
296                    case RedQuantum:   q->red=qx[i];   break;
297                    case GreenQuantum: q->green=qx[i]; break;
298                    case BlueQuantum:  q->blue=qx[i];  break;
299                    default:                           break;
300                  }
301                SetOpacityPixelComponent(q,OpaqueOpacity);
302                if (image->matte != MagickFalse)
303                  SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
304                p++;
305                q++;
306              }
307              if (SyncAuthenticPixels(image,exception) == MagickFalse)
308                break;
309            }
310          if (image->previous == (Image *) NULL)
311            {
312              status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
313                image->rows);
314              if (status == MagickFalse)
315                break;
316            }
317          count=ReadBlob(image,length,pixels);
318        }
319        break;
320      }
321      case LineInterlace:
322      {
323        /*
324          Line interlacing:  RRR...GGG...BBB...RRR...GGG...BBB...
325        */
326        if (scene == 0)
327          {
328            length=GetQuantumExtent(canvas_image,quantum_info,quantum_types[0]);
329            count=ReadBlob(image,length,pixels);
330          }
331        for (y=0; y < (ssize_t) image->extract_info.height; y++)
332        {
333          register const PixelPacket
334            *restrict p;
335
336          register ssize_t
337            x;
338
339          register PixelPacket
340            *restrict q;
341
342          if (count != (ssize_t) length)
343            {
344              ThrowFileException(exception,CorruptImageError,
345                "UnexpectedEndOfFile",image->filename);
346              break;
347            }
348          for (i=0; i < channels; i++)
349          {
350            q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
351              exception);
352            if (q == (PixelPacket *) NULL)
353              break;
354            length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
355              quantum_info,quantum_types[i],pixels,exception);
356            if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
357              break;
358            if (((y-image->extract_info.y) >= 0) &&
359                ((y-image->extract_info.y) < (ssize_t) image->rows))
360              {
361                p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,
362                  0,canvas_image->columns,1,exception);
363                q=GetAuthenticPixels(image,0,y-image->extract_info.y,
364                  image->columns,1,exception);
365                if ((p == (const PixelPacket *) NULL) ||
366                    (q == (PixelPacket *) NULL))
367                  break;
368                if (i == (channels - 1))
369                  for (x=0; x < (ssize_t) image->columns; x++)
370                  {
371                    SetRedPixelComponent(q,GetRedPixelComponent(p));
372                    SetGreenPixelComponent(q,GetGreenPixelComponent(p));
373                    SetBluePixelComponent(q,GetBluePixelComponent(p));
374                    SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
375                    p++;
376                    q++;
377                  }
378                if (SyncAuthenticPixels(image,exception) == MagickFalse)
379                  break;
380              }
381            count=ReadBlob(image,length,pixels);
382          }
383          if (image->previous == (Image *) NULL)
384            {
385              status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
386                image->rows);
387              if (status == MagickFalse)
388                break;
389            }
390        }
391        break;
392      }
393      case PlaneInterlace:
394      {
395        /*
396          Plane interlacing:  RRRRRR...GGGGGG...BBBBBB...
397        */
398        if (scene == 0)
399          {
400            length=GetQuantumExtent(canvas_image,quantum_info,quantum_types[0]);
401            count=ReadBlob(image,length,pixels);
402          }
403        for (i=0; i < channels; i++)
404        {
405          for (y=0; y < (ssize_t) image->extract_info.height; y++)
406          {
407            register const PixelPacket
408              *restrict p;
409
410            register ssize_t
411              x;
412
413            register PixelPacket
414              *restrict q;
415
416            if (count != (ssize_t) length)
417              {
418                ThrowFileException(exception,CorruptImageError,
419                  "UnexpectedEndOfFile",image->filename);
420                break;
421              }
422            q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
423              exception);
424            if (q == (PixelPacket *) NULL)
425              break;
426            length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
427              quantum_info,quantum_types[i],pixels,exception);
428            if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
429              break;
430            if (((y-image->extract_info.y) >= 0) &&
431                ((y-image->extract_info.y) < (ssize_t) image->rows))
432              {
433                p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
434                  canvas_image->columns,1,exception);
435                q=GetAuthenticPixels(image,0,y-image->extract_info.y,
436                  image->columns,1,exception);
437                if ((p == (const PixelPacket *) NULL) ||
438                    (q == (PixelPacket *) NULL))
439                  break;
440                for (x=0; x < (ssize_t) image->columns; x++)
441                {
442                  switch(quantum_types[i])
443                  {
444                    case RedQuantum:    SetRedPixelComponent(q,GetRedPixelComponent(p));         break;
445                    case GreenQuantum:  SetGreenPixelComponent(q,GetGreenPixelComponent(p));     break;
446                    case BlueQuantum:   SetBluePixelComponent(q,GetBluePixelComponent(p));       break;
447                    case OpacityQuantum:
448                    case AlphaQuantum:  SetOpacityPixelComponent(q,GetOpacityPixelComponent(p)); break;
449                    default:                                   break;
450                  }
451                  p++;
452                  q++;
453                }
454                if (SyncAuthenticPixels(image,exception) == MagickFalse)
455                  break;
456              }
457            count=ReadBlob(image,length,pixels);
458          }
459          if (image->previous == (Image *) NULL)
460            {
461              status=SetImageProgress(image,LoadImageTag,(i+1),5);
462              if (status == MagickFalse)
463                break;
464            }
465        }
466        if (image->previous == (Image *) NULL)
467          {
468            status=SetImageProgress(image,LoadImageTag,5,5);
469            if (status == MagickFalse)
470              break;
471          }
472        break;
473      }
474      case PartitionInterlace:
475      {
476        /*
477          Partition interlacing:  RRRRRR..., GGGGGG..., BBBBBB...
478        */
479        for (i=0; i < channels; i++)
480        {
481          sfx[0]=image_info->magick[i];
482          AppendImageFormat(sfx,image->filename);
483          status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
484          if (status == MagickFalse)
485            {
486              canvas_image=DestroyImageList(canvas_image);
487              image=DestroyImageList(image);
488              return((Image *) NULL);
489            }
490          if (i == 0)
491            for (j=0; j < image->offset; j++)
492              if (ReadBlobByte(image) == EOF)
493                {
494                  ThrowFileException(exception,CorruptImageError,
495                    "UnexpectedEndOfFile",image->filename);
496                  break;
497                }
498          length=GetQuantumExtent(canvas_image,quantum_info,quantum_types[i]);
499          for (j=0; j < (ssize_t) scene; j++)
500            for (y=0; y < (ssize_t) image->extract_info.height; y++)
501              if (ReadBlob(image,length,pixels) != (ssize_t) length)
502                {
503                  ThrowFileException(exception,CorruptImageError,
504                    "UnexpectedEndOfFile",image->filename);
505                  break;
506                }
507          count=ReadBlob(image,length,pixels);
508          for (y=0; y < (ssize_t) image->extract_info.height; y++)
509          {
510            register const PixelPacket
511              *restrict p;
512
513            register ssize_t
514              x;
515
516            register PixelPacket
517              *restrict q;
518
519            if (count != (ssize_t) length)
520              {
521                ThrowFileException(exception,CorruptImageError,
522                  "UnexpectedEndOfFile",image->filename);
523                break;
524              }
525            q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
526              exception);
527            if (q == (PixelPacket *) NULL)
528              break;
529            length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
530              quantum_info,quantum_types[i],pixels,exception);
531            if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
532              break;
533            if (((y-image->extract_info.y) >= 0) &&
534                ((y-image->extract_info.y) < (ssize_t) image->rows))
535              {
536                p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
537                  canvas_image->columns,1,exception);
538                q=GetAuthenticPixels(image,0,y-image->extract_info.y,
539                  image->columns,1,exception);
540                if ((p == (const PixelPacket *) NULL) ||
541                    (q == (PixelPacket *) NULL))
542                  break;
543                for (x=0; x < (ssize_t) image->columns; x++)
544                {
545                  switch(quantum_types[i])
546                  {
547                    case RedQuantum:    SetRedPixelComponent(q,GetRedPixelComponent(p));         break;
548                    case GreenQuantum:  SetGreenPixelComponent(q,GetGreenPixelComponent(p));     break;
549                    case BlueQuantum:   SetBluePixelComponent(q,GetBluePixelComponent(p));       break;
550                    case OpacityQuantum:
551                    case AlphaQuantum:  SetOpacityPixelComponent(q,GetOpacityPixelComponent(p)); break;
552                    default:                                   break;
553                  }
554                  p++;
555                  q++;
556                }
557                if (SyncAuthenticPixels(image,exception) == MagickFalse)
558                  break;
559              }
560            count=ReadBlob(image,length,pixels);
561          }
562          if (image->previous == (Image *) NULL)
563            {
564              status=SetImageProgress(image,LoadImageTag,(i+1),5);
565              if (status == MagickFalse)
566                break;
567            }
568          if (i != (channels-1))
569            (void) CloseBlob(image);
570        }
571        if (image->previous == (Image *) NULL)
572          {
573            status=SetImageProgress(image,LoadImageTag,5,5);
574            if (status == MagickFalse)
575              break;
576          }
577        break;
578      }
579    }
580    SetQuantumImageType(image,quantum_type);
581    /*
582      Proceed to next image.
583    */
584    if (image_info->number_scenes != 0)
585      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
586        break;
587    if (count == (ssize_t) length)
588      {
589        /*
590          Allocate next image structure.
591        */
592        AcquireNextImage(image_info,image);
593        if (GetNextImageInList(image) == (Image *) NULL)
594          {
595            image=DestroyImageList(image);
596            return((Image *) NULL);
597          }
598        image=SyncNextImageInList(image);
599        status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
600          GetBlobSize(image));
601        if (status == MagickFalse)
602          break;
603      }
604    scene++;
605  } while (count == (ssize_t) length);
606  quantum_info=DestroyQuantumInfo(quantum_info);
607  InheritException(&image->exception,&canvas_image->exception);
608  canvas_image=DestroyImage(canvas_image);
609  (void) CloseBlob(image);
610  return(GetFirstImageInList(image));
611}
612
613/*
614%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
615%                                                                             %
616%                                                                             %
617%                                                                             %
618%   R e g i s t e r R G B I m a g e                                           %
619%                                                                             %
620%                                                                             %
621%                                                                             %
622%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
623%
624%  RegisterRGBImage() adds attributes for the RGB or RGBA image format to
625%  the list of supported formats.  The attributes include the image format
626%  tag, a method to read and/or write the format, whether the format
627%  supports the saving of more than one frame to the same file or blob,
628%  whether the format supports native in-memory I/O, and a brief
629%  description of the format.
630%
631%  The format of the RegisterRGBImage method is:
632%
633%      size_t RegisterRGBImage(void)
634%
635*/
636ModuleExport size_t RegisterRGBImage(void)
637{
638  MagickInfo
639    *entry;
640
641  entry=SetMagickInfo("RGB");
642  entry->decoder=(DecodeImageHandler *) ReadRGBImage;
643  entry->encoder=(EncodeImageHandler *) WriteRGBImage;
644  entry->raw=MagickTrue;
645  entry->endian_support=MagickTrue;
646  entry->format_type=ImplicitFormatType;
647  entry->description=ConstantString("Raw red, green, and blue samples");
648  entry->module=ConstantString("RGB");
649  (void) RegisterMagickInfo(entry);
650  entry=SetMagickInfo("RBG");
651  entry->decoder=(DecodeImageHandler *) ReadRGBImage;
652  entry->encoder=(EncodeImageHandler *) WriteRGBImage;
653  entry->raw=MagickTrue;
654  entry->endian_support=MagickTrue;
655  entry->format_type=ImplicitFormatType;
656  entry->description=ConstantString("Raw red, blue, and green samples");
657  entry->module=ConstantString("RGB");
658  (void) RegisterMagickInfo(entry);
659  entry=SetMagickInfo("GRB");
660  entry->decoder=(DecodeImageHandler *) ReadRGBImage;
661  entry->encoder=(EncodeImageHandler *) WriteRGBImage;
662  entry->raw=MagickTrue;
663  entry->endian_support=MagickTrue;
664  entry->format_type=ImplicitFormatType;
665  entry->description=ConstantString("Raw green, red, and blue samples");
666  entry->module=ConstantString("RGB");
667  (void) RegisterMagickInfo(entry);
668  entry=SetMagickInfo("GBR");
669  entry->decoder=(DecodeImageHandler *) ReadRGBImage;
670  entry->encoder=(EncodeImageHandler *) WriteRGBImage;
671  entry->raw=MagickTrue;
672  entry->endian_support=MagickTrue;
673  entry->format_type=ImplicitFormatType;
674  entry->description=ConstantString("Raw green, blue, and red samples");
675  entry->module=ConstantString("RGB");
676  (void) RegisterMagickInfo(entry);
677  entry=SetMagickInfo("BRG");
678  entry->decoder=(DecodeImageHandler *) ReadRGBImage;
679  entry->encoder=(EncodeImageHandler *) WriteRGBImage;
680  entry->raw=MagickTrue;
681  entry->endian_support=MagickTrue;
682  entry->format_type=ImplicitFormatType;
683  entry->description=ConstantString("Raw blue, red, and green samples");
684  entry->module=ConstantString("RGB");
685  (void) RegisterMagickInfo(entry);
686  entry=SetMagickInfo("BGR");
687  entry->decoder=(DecodeImageHandler *) ReadRGBImage;
688  entry->encoder=(EncodeImageHandler *) WriteRGBImage;
689  entry->raw=MagickTrue;
690  entry->endian_support=MagickTrue;
691  entry->format_type=ImplicitFormatType;
692  entry->description=ConstantString("Raw blue, green, and red samples");
693  entry->module=ConstantString("RGB");
694  (void) RegisterMagickInfo(entry);
695  entry=SetMagickInfo("BGRA");
696  entry->decoder=(DecodeImageHandler *) ReadRGBImage;
697  entry->encoder=(EncodeImageHandler *) WriteRGBImage;
698  entry->raw=MagickTrue;
699  entry->endian_support=MagickTrue;
700  entry->format_type=ImplicitFormatType;
701  entry->description=ConstantString("Raw blue, green, red and alpha samples");
702  entry->module=ConstantString("RGB");
703  (void) RegisterMagickInfo(entry);
704  entry=SetMagickInfo("RGBA");
705  entry->decoder=(DecodeImageHandler *) ReadRGBImage;
706  entry->encoder=(EncodeImageHandler *) WriteRGBImage;
707  entry->raw=MagickTrue;
708  entry->endian_support=MagickTrue;
709  entry->format_type=ImplicitFormatType;
710  entry->description=ConstantString("Raw red, green, blue, and alpha samples");
711  entry->module=ConstantString("RGB");
712  (void) RegisterMagickInfo(entry);
713  entry=SetMagickInfo("RGBO");
714  entry->decoder=(DecodeImageHandler *) ReadRGBImage;
715  entry->encoder=(EncodeImageHandler *) WriteRGBImage;
716  entry->raw=MagickTrue;
717  entry->endian_support=MagickTrue;
718  entry->format_type=ImplicitFormatType;
719  entry->description=ConstantString("Raw red, green, blue, and opacity "
720    "samples");
721  entry->module=ConstantString("RGB");
722  (void) RegisterMagickInfo(entry);
723  return(MagickImageCoderSignature);
724}
725
726/*
727%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
728%                                                                             %
729%                                                                             %
730%                                                                             %
731%   U n r e g i s t e r R G B I m a g e                                       %
732%                                                                             %
733%                                                                             %
734%                                                                             %
735%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
736%
737%  UnregisterRGBImage() removes format registrations made by the
738%  RGB module from the list of supported formats.
739%
740%  The format of the UnregisterRGBImage method is:
741%
742%      UnregisterRGBImage(void)
743%
744*/
745ModuleExport void UnregisterRGBImage(void)
746{
747  (void) UnregisterMagickInfo("RGBO");
748  (void) UnregisterMagickInfo("RGBA");
749  (void) UnregisterMagickInfo("BGR");
750  (void) UnregisterMagickInfo("BGRA");
751  (void) UnregisterMagickInfo("BRG");
752  (void) UnregisterMagickInfo("GBR");
753  (void) UnregisterMagickInfo("GRB");
754  (void) UnregisterMagickInfo("RBG");
755  (void) UnregisterMagickInfo("RGB");
756}
757
758/*
759%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
760%                                                                             %
761%                                                                             %
762%                                                                             %
763%   W r i t e R G B I m a g e                                                 %
764%                                                                             %
765%                                                                             %
766%                                                                             %
767%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
768%
769%  WriteRGBImage() writes an image to a file in the RGB or RGBA rasterfile
770%  format.
771%
772%  The format of the WriteRGBImage method is:
773%
774%      MagickBooleanType WriteRGBImage(const ImageInfo *image_info,Image *image)
775%
776%  A description of each parameter follows.
777%
778%    o image_info: the image info.
779%
780%    o image:  The image.
781%
782*/
783static MagickBooleanType WriteRGBImage(const ImageInfo *image_info,Image *image)
784{
785  ssize_t
786    y;
787
788  MagickBooleanType
789    status;
790
791  MagickOffsetType
792    scene;
793
794  QuantumInfo
795    *quantum_info;
796
797  QuantumType
798    quantum_type,
799    quantum_types[4];
800
801  register ssize_t
802    i;
803
804  ssize_t
805    count;
806
807  size_t
808    length;
809
810  unsigned char
811    *pixels;
812
813  size_t
814    channels;
815
816  /*
817    Allocate memory for pixels.
818  */
819  assert(image_info != (const ImageInfo *) NULL);
820  assert(image_info->signature == MagickSignature);
821  assert(image != (Image *) NULL);
822  assert(image->signature == MagickSignature);
823  if (image->debug != MagickFalse)
824    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
825  if (image_info->interlace != PartitionInterlace)
826    {
827      /*
828        Open output image file.
829      */
830      status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
831      if (status == MagickFalse)
832        return(status);
833    }
834  quantum_type=RGBQuantum;
835  channels=3;
836  if (LocaleCompare(image_info->magick,"RGBA") == 0)
837    {
838      quantum_type=RGBAQuantum;
839      image->matte=MagickTrue;
840      channels=4;
841    }
842  if (LocaleCompare(image_info->magick,"RGBO") == 0)
843    {
844      quantum_type=RGBOQuantum;
845      image->matte=MagickTrue;
846      channels=4;
847    }
848  for (i=0; i < (ssize_t) channels; i++)
849  {
850    switch (image_info->magick[i])
851    {
852      case 'R': quantum_types[i]=RedQuantum;     break;
853      case 'G': quantum_types[i]=GreenQuantum;   break;
854      case 'B': quantum_types[i]=BlueQuantum;    break;
855      case 'A': quantum_types[i]=AlphaQuantum;   break;
856      case 'O': quantum_types[i]=OpacityQuantum; break;
857    }
858  }
859  scene=0;
860  do
861  {
862    /*
863      Convert MIFF to RGB raster pixels.
864    */
865    if (image->colorspace != RGBColorspace)
866      (void) TransformImageColorspace(image,RGBColorspace);
867    if ((LocaleCompare(image_info->magick,"RGBA") == 0) &&
868        (image->matte == MagickFalse))
869      (void) SetImageAlphaChannel(image,ResetAlphaChannel);
870    quantum_info=AcquireQuantumInfo(image_info,image);
871    if (quantum_info == (QuantumInfo *) NULL)
872      ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
873    pixels=GetQuantumPixels(quantum_info);
874    switch (image_info->interlace)
875    {
876      case NoInterlace:
877      default:
878      {
879        CacheView
880          *image_view;
881
882        PixelPacket
883          px;
884
885        Quantum
886          *qx[3];
887
888        /*
889          No interlacing:  RGBRGBRGBRGBRGBRGB...
890        */
891        image_view=AcquireCacheView(image);
892        for (y=0; y < (ssize_t) image->rows; y++)
893        {
894          register ssize_t
895            x;
896
897          register PixelPacket
898            *restrict q;
899
900          q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
901            &image->exception);
902          if (q == (PixelPacket *) NULL)
903            break;
904          for (x=0; x < (ssize_t) image->columns; x++)
905          {
906            px=(*q);
907            qx[0]=&(q->red);
908            qx[1]=&(q->green);
909            qx[2]=&(q->blue);
910            for (i=0; i < 3; i++)
911              switch (quantum_types[i])
912              {
913                case RedQuantum:   *qx[i]=px.red;   break;
914                case GreenQuantum: *qx[i]=px.green; break;
915                case BlueQuantum:  *qx[i]=px.blue;  break;
916                default:                            break;
917              }
918            q++;
919          }
920          length=ExportQuantumPixels(image,image_view,quantum_info,quantum_type,
921            pixels,&image->exception);
922          count=WriteBlob(image,length,pixels);
923          if (count != (ssize_t) length)
924            break;
925          if (image->previous == (Image *) NULL)
926            {
927              status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
928                image->rows);
929              if (status == MagickFalse)
930                break;
931            }
932        }
933        image_view=DestroyCacheView(image_view);
934        break;
935      }
936      case LineInterlace:
937      {
938        /*
939          Line interlacing:  RRR...GGG...BBB...RRR...GGG...BBB...
940        */
941        for (y=0; y < (ssize_t) image->rows; y++)
942        {
943          register const PixelPacket
944            *restrict p;
945
946          p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
947          if (p == (const PixelPacket *) NULL)
948            break;
949          for (i=0; i < (ssize_t) channels; i++)
950          {
951            length=ExportQuantumPixels(image,(const CacheView *) NULL,
952              quantum_info,quantum_types[i],pixels,&image->exception);
953            count=WriteBlob(image,length,pixels);
954            if (count != (ssize_t) length)
955              break;
956          }
957          if (image->previous == (Image *) NULL)
958            {
959              status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
960                image->rows);
961              if (status == MagickFalse)
962                break;
963            }
964        }
965        break;
966      }
967      case PlaneInterlace:
968      {
969        /*
970          Plane interlacing:  RRRRRR...GGGGGG...BBBBBB...
971        */
972        for (i=0; i < (ssize_t) channels; i++)
973        {
974          for (y=0; y < (ssize_t) image->rows; y++)
975          {
976            register const PixelPacket
977              *restrict p;
978
979            p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
980            if (p == (const PixelPacket *) NULL)
981              break;
982            length=ExportQuantumPixels(image,(const CacheView *) NULL,
983              quantum_info,quantum_types[i],pixels,&image->exception);
984            count=WriteBlob(image,length,pixels);
985            if (count != (ssize_t) length)
986              break;
987          }
988          if (image->previous == (Image *) NULL)
989            {
990              status=SetImageProgress(image,SaveImageTag,(i+1),5);
991              if (status == MagickFalse)
992                break;
993            }
994        }
995        if (image->previous == (Image *) NULL)
996          {
997            status=SetImageProgress(image,SaveImageTag,5,5);
998            if (status == MagickFalse)
999              break;
1000          }
1001        break;
1002      }
1003      case PartitionInterlace:
1004      {
1005        char
1006          sfx[] = {0, 0};
1007
1008        /*
1009          Partition interlacing:  RRRRRR..., GGGGGG..., BBBBBB...
1010        */
1011        for (i=0; i < (ssize_t) channels; i++)
1012        {
1013          sfx[0]=image_info->magick[i];
1014          AppendImageFormat(sfx,image->filename);
1015          status=OpenBlob(image_info,image,scene == 0 ? WriteBinaryBlobMode :
1016            AppendBinaryBlobMode,&image->exception);
1017          if (status == MagickFalse)
1018            return(status);
1019          for (y=0; y < (ssize_t) image->rows; y++)
1020          {
1021            register const PixelPacket
1022              *restrict p;
1023
1024            p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1025            if (p == (const PixelPacket *) NULL)
1026              break;
1027            length=ExportQuantumPixels(image,(const CacheView *) NULL,
1028              quantum_info,quantum_types[i],pixels,&image->exception);
1029            count=WriteBlob(image,length,pixels);
1030            if (count != (ssize_t) length)
1031              break;
1032          }
1033          if (image->previous == (Image *) NULL)
1034            {
1035              status=SetImageProgress(image,SaveImageTag,(i+1),5);
1036              if (status == MagickFalse)
1037                break;
1038            }
1039          (void) CloseBlob(image);
1040        }
1041        (void) CopyMagickString(image->filename,image_info->filename,
1042          MaxTextExtent);
1043        if (image->previous == (Image *) NULL)
1044          {
1045            status=SetImageProgress(image,SaveImageTag,5,5);
1046            if (status == MagickFalse)
1047              break;
1048          }
1049        break;
1050      }
1051    }
1052    quantum_info=DestroyQuantumInfo(quantum_info);
1053    if (GetNextImageInList(image) == (Image *) NULL)
1054      break;
1055    image=SyncNextImageInList(image);
1056    status=SetImageProgress(image,SaveImagesTag,scene++,
1057      GetImageListLength(image));
1058    if (status == MagickFalse)
1059      break;
1060  } while (image_info->adjoin != MagickFalse);
1061  (void) CloseBlob(image);
1062  return(MagickTrue);
1063}
1064