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