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