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