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