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