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