blob: b062f09363128a12c85c774d61a86e52a3f8b202 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
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
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
65/*
66 Forward declarations.
67*/
68static MagickBooleanType
69 WriteRGBImage(const ImageInfo *,Image *);
70
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*/
97static 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
cristy21da32d2009-09-12 14:56:09 +0000258 if (count != (ssize_t) length)
259 {
260 ThrowFileException(exception,CorruptImageError,
261 "UnexpectedEndOfFile",image->filename);
262 break;
263 }
cristy3ed852e2009-09-05 21:47:34 +0000264 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);
cristy3ed852e2009-09-05 21:47:34 +0000311 }
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);
cristy3ed852e2009-09-05 21:47:34 +0000323 }
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
cristy21da32d2009-09-12 14:56:09 +0000335 if (count != (ssize_t) length)
336 {
337 ThrowFileException(exception,CorruptImageError,
338 "UnexpectedEndOfFile",image->filename);
339 break;
340 }
cristy3ed852e2009-09-05 21:47:34 +0000341 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);
cristy3ed852e2009-09-05 21:47:34 +0000375 }
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);
cristy3ed852e2009-09-05 21:47:34 +0000394 }
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
cristy21da32d2009-09-12 14:56:09 +0000408 if (count != (ssize_t) length)
409 {
410 ThrowFileException(exception,CorruptImageError,
411 "UnexpectedEndOfFile",image->filename);
412 break;
413 }
cristy3ed852e2009-09-05 21:47:34 +0000414 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);
cristy3ed852e2009-09-05 21:47:34 +0000450 }
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);
cristy3ed852e2009-09-05 21:47:34 +0000500 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
cristy21da32d2009-09-12 14:56:09 +0000511 if (count != (ssize_t) length)
512 {
513 ThrowFileException(exception,CorruptImageError,
514 "UnexpectedEndOfFile",image->filename);
515 break;
516 }
cristy3ed852e2009-09-05 21:47:34 +0000517 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);
cristy3ed852e2009-09-05 21:47:34 +0000553 }
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);
cristy3ed852e2009-09-05 21:47:34 +0000573 /*
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 InheritException(exception,&image->exception);
599 quantum_info=DestroyQuantumInfo(quantum_info);
600 canvas_image=DestroyImage(canvas_image);
601 (void) CloseBlob(image);
602 return(GetFirstImageInList(image));
603}
604
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*/
628ModuleExport 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
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*/
728ModuleExport 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
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*/
765static 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}