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