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