blob: 2d07314d91489ff23d579026b0c38f6dbb14d9b6 [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
cristy3ed852e2009-09-05 21:47:34 +0000103 MagickBooleanType
104 status;
105
106 MagickOffsetType
107 scene;
108
109 QuantumInfo
110 *quantum_info;
111
112 QuantumType
113 quantum_type;
114
cristya38675f2010-08-21 18:35:13 +0000115 Quantum
116 qx[4];
117
cristybb503372010-05-27 20:51:26 +0000118 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000119 i,
120 j;
121
cristy3ed852e2009-09-05 21:47:34 +0000122 ssize_t
cristya38675f2010-08-21 18:35:13 +0000123 count,
124 y;
cristy3ed852e2009-09-05 21:47:34 +0000125
126 size_t
cristya38675f2010-08-21 18:35:13 +0000127 channels,
cristy3ed852e2009-09-05 21:47:34 +0000128 length;
129
130 unsigned char
131 *pixels;
132
133 QuantumType
134 quantum_types[4];
135
136 char
137 sfx[] = {0, 0};
138
cristy3ed852e2009-09-05 21:47:34 +0000139 /*
140 Open image file.
141 */
142 assert(image_info != (const ImageInfo *) NULL);
143 assert(image_info->signature == MagickSignature);
144 if (image_info->debug != MagickFalse)
145 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
146 image_info->filename);
147 assert(exception != (ExceptionInfo *) NULL);
148 assert(exception->signature == MagickSignature);
149 image=AcquireImage(image_info);
150 if ((image->columns == 0) || (image->rows == 0))
151 ThrowReaderException(OptionError,"MustSpecifyImageSize");
152 if (image_info->interlace != PartitionInterlace)
153 {
154 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
155 if (status == MagickFalse)
156 {
157 image=DestroyImageList(image);
158 return((Image *) NULL);
159 }
160 for (i=0; i < image->offset; i++)
161 if (ReadBlobByte(image) == EOF)
162 {
163 ThrowFileException(exception,CorruptImageError,
164 "UnexpectedEndOfFile",image->filename);
165 break;
166 }
167 }
168 /*
169 Create virtual canvas to support cropping (i.e. image.rgb[100x100+10+20]).
170 */
171 canvas_image=CloneImage(image,image->extract_info.width,1,MagickFalse,
172 exception);
173 (void) SetImageVirtualPixelMethod(canvas_image,BlackVirtualPixelMethod);
174 quantum_info=AcquireQuantumInfo(image_info,canvas_image);
175 if (quantum_info == (QuantumInfo *) NULL)
176 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
177 pixels=GetQuantumPixels(quantum_info);
178 quantum_type=RGBQuantum;
cristya38675f2010-08-21 18:35:13 +0000179 for (i=0; i < 4; i++)
180 {
181 if (image_info->magick[i] == '\0')
182 break;
183 switch(image_info->magick[i])
184 {
185 case 'R': quantum_types[i]=RedQuantum; break;
186 case 'G': quantum_types[i]=GreenQuantum; break;
187 case 'B': quantum_types[i]=BlueQuantum; break;
cristy2080f2b2010-08-21 18:43:15 +0000188 case 'A':
189 {
190 quantum_types[i]=AlphaQuantum;
191 quantum_type=RGBAQuantum;
192 break;
193 }
194 case 'O':
195 {
196 quantum_types[i]=OpacityQuantum;
197 quantum_type=RGBOQuantum;
198 break;
199 }
200 default:
201 break;
cristya38675f2010-08-21 18:35:13 +0000202 }
203 }
204 channels=i;
cristy3ed852e2009-09-05 21:47:34 +0000205 if (image_info->number_scenes != 0)
206 while (image->scene < image_info->scene)
207 {
208 /*
209 Skip to next image.
210 */
211 image->scene++;
212 length=GetQuantumExtent(canvas_image,quantum_info,quantum_type);
cristybb503372010-05-27 20:51:26 +0000213 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000214 {
215 count=ReadBlob(image,length,pixels);
216 if (count != (ssize_t) length)
217 break;
218 }
219 }
cristy3ed852e2009-09-05 21:47:34 +0000220 count=0;
221 length=0;
222 scene=0;
223 do
224 {
225 /*
226 Read pixels to virtual canvas image then push to image.
227 */
228 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
229 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
230 break;
231 switch (image_info->interlace)
232 {
233 case NoInterlace:
234 default:
235 {
236 /*
237 No interlacing: RGBRGBRGBRGBRGBRGB...
238 */
239 if (scene == 0)
240 {
241 length=GetQuantumExtent(canvas_image,quantum_info,quantum_type);
242 count=ReadBlob(image,length,pixels);
243 if (count != (ssize_t) length)
244 break;
245 }
cristybb503372010-05-27 20:51:26 +0000246 for (y=0; y < (ssize_t) image->extract_info.height; y++)
cristy3ed852e2009-09-05 21:47:34 +0000247 {
248 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000249 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +0000250
cristybb503372010-05-27 20:51:26 +0000251 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000252 x;
253
254 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000255 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000256
cristy21da32d2009-09-12 14:56:09 +0000257 if (count != (ssize_t) length)
258 {
259 ThrowFileException(exception,CorruptImageError,
260 "UnexpectedEndOfFile",image->filename);
261 break;
262 }
cristy3ed852e2009-09-05 21:47:34 +0000263 q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
264 exception);
265 if (q == (PixelPacket *) NULL)
266 break;
267 length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
268 quantum_info,quantum_type,pixels,exception);
269 if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
270 break;
271 if (((y-image->extract_info.y) >= 0) &&
cristybb503372010-05-27 20:51:26 +0000272 ((y-image->extract_info.y) < (ssize_t) image->rows))
cristy3ed852e2009-09-05 21:47:34 +0000273 {
274 p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
275 canvas_image->columns,1,exception);
276 q=QueueAuthenticPixels(image,0,y-image->extract_info.y,
277 image->columns,1,exception);
278 if ((p == (const PixelPacket *) NULL) ||
279 (q == (PixelPacket *) NULL))
280 break;
cristybb503372010-05-27 20:51:26 +0000281 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000282 {
cristyce70c172010-01-07 17:15:30 +0000283 qx[0]=GetRedPixelComponent(p);
284 qx[1]=GetGreenPixelComponent(p);
285 qx[2]=GetBluePixelComponent(p);
cristya38675f2010-08-21 18:35:13 +0000286 qx[3]=GetOpacityPixelComponent(p);
287 for (i=0; i < channels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000288 switch(quantum_types[i])
289 {
cristya38675f2010-08-21 18:35:13 +0000290 case RedQuantum: q->red=qx[i]; break;
cristy3ed852e2009-09-05 21:47:34 +0000291 case GreenQuantum: q->green=qx[i]; break;
cristya38675f2010-08-21 18:35:13 +0000292 case BlueQuantum: q->blue=qx[i]; break;
293 case AlphaQuantum: q->opacity=qx[i]; break;
294 case OpacityQuantum: q->opacity=qx[i]; break;
295 default: break;
cristy3ed852e2009-09-05 21:47:34 +0000296 }
cristy3ed852e2009-09-05 21:47:34 +0000297 p++;
298 q++;
299 }
300 if (SyncAuthenticPixels(image,exception) == MagickFalse)
301 break;
302 }
303 if (image->previous == (Image *) NULL)
304 {
cristycee97112010-05-28 00:44:52 +0000305 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
306 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000307 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 }
cristybb503372010-05-27 20:51:26 +0000324 for (y=0; y < (ssize_t) image->extract_info.height; y++)
cristy3ed852e2009-09-05 21:47:34 +0000325 {
326 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000327 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +0000328
cristybb503372010-05-27 20:51:26 +0000329 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000330 x;
331
332 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000333 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000334
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) &&
cristybb503372010-05-27 20:51:26 +0000352 ((y-image->extract_info.y) < (ssize_t) image->rows))
cristy3ed852e2009-09-05 21:47:34 +0000353 {
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))
cristybb503372010-05-27 20:51:26 +0000362 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000363 {
cristyce70c172010-01-07 17:15:30 +0000364 SetRedPixelComponent(q,GetRedPixelComponent(p));
365 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
366 SetBluePixelComponent(q,GetBluePixelComponent(p));
367 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +0000368 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 {
cristycee97112010-05-28 00:44:52 +0000378 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
379 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000380 if (status == MagickFalse)
381 break;
382 }
383 }
384 break;
385 }
386 case PlaneInterlace:
387 {
388 /*
389 Plane interlacing: RRRRRR...GGGGGG...BBBBBB...
390 */
391 if (scene == 0)
392 {
393 length=GetQuantumExtent(canvas_image,quantum_info,quantum_types[0]);
394 count=ReadBlob(image,length,pixels);
cristy3ed852e2009-09-05 21:47:34 +0000395 }
396 for (i=0; i < channels; i++)
397 {
cristybb503372010-05-27 20:51:26 +0000398 for (y=0; y < (ssize_t) image->extract_info.height; y++)
cristy3ed852e2009-09-05 21:47:34 +0000399 {
400 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000401 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +0000402
cristybb503372010-05-27 20:51:26 +0000403 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000404 x;
405
406 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000407 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000408
cristy21da32d2009-09-12 14:56:09 +0000409 if (count != (ssize_t) length)
410 {
411 ThrowFileException(exception,CorruptImageError,
412 "UnexpectedEndOfFile",image->filename);
413 break;
414 }
cristy3ed852e2009-09-05 21:47:34 +0000415 q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
416 exception);
417 if (q == (PixelPacket *) NULL)
418 break;
419 length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
420 quantum_info,quantum_types[i],pixels,exception);
421 if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
422 break;
423 if (((y-image->extract_info.y) >= 0) &&
cristybb503372010-05-27 20:51:26 +0000424 ((y-image->extract_info.y) < (ssize_t) image->rows))
cristy3ed852e2009-09-05 21:47:34 +0000425 {
426 p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
427 canvas_image->columns,1,exception);
428 q=GetAuthenticPixels(image,0,y-image->extract_info.y,
429 image->columns,1,exception);
430 if ((p == (const PixelPacket *) NULL) ||
431 (q == (PixelPacket *) NULL))
432 break;
cristybb503372010-05-27 20:51:26 +0000433 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000434 {
435 switch(quantum_types[i])
436 {
cristydd5f5912010-07-31 23:37:23 +0000437 case RedQuantum:
438 {
439 SetRedPixelComponent(q,GetRedPixelComponent(p));
440 break;
441 }
442 case GreenQuantum:
443 {
444 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
445 break;
446 }
447 case BlueQuantum:
448 {
449 SetBluePixelComponent(q,GetBluePixelComponent(p));
450 break;
451 }
cristy3ed852e2009-09-05 21:47:34 +0000452 case OpacityQuantum:
cristydd5f5912010-07-31 23:37:23 +0000453 case AlphaQuantum:
454 {
455 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
456 break;
457 }
458 default:
459 break;
cristy3ed852e2009-09-05 21:47:34 +0000460 }
461 p++;
462 q++;
463 }
464 if (SyncAuthenticPixels(image,exception) == MagickFalse)
465 break;
466 }
467 count=ReadBlob(image,length,pixels);
cristy3ed852e2009-09-05 21:47:34 +0000468 }
469 if (image->previous == (Image *) NULL)
470 {
471 status=SetImageProgress(image,LoadImageTag,(i+1),5);
472 if (status == MagickFalse)
473 break;
474 }
475 }
476 if (image->previous == (Image *) NULL)
477 {
478 status=SetImageProgress(image,LoadImageTag,5,5);
479 if (status == MagickFalse)
480 break;
481 }
482 break;
483 }
484 case PartitionInterlace:
485 {
486 /*
487 Partition interlacing: RRRRRR..., GGGGGG..., BBBBBB...
488 */
489 for (i=0; i < channels; i++)
490 {
491 sfx[0]=image_info->magick[i];
492 AppendImageFormat(sfx,image->filename);
493 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
494 if (status == MagickFalse)
495 {
496 canvas_image=DestroyImageList(canvas_image);
497 image=DestroyImageList(image);
498 return((Image *) NULL);
499 }
500 if (i == 0)
501 for (j=0; j < image->offset; j++)
502 if (ReadBlobByte(image) == EOF)
503 {
504 ThrowFileException(exception,CorruptImageError,
505 "UnexpectedEndOfFile",image->filename);
506 break;
507 }
508 length=GetQuantumExtent(canvas_image,quantum_info,quantum_types[i]);
cristybb503372010-05-27 20:51:26 +0000509 for (j=0; j < (ssize_t) scene; j++)
510 for (y=0; y < (ssize_t) image->extract_info.height; y++)
cristy3ed852e2009-09-05 21:47:34 +0000511 if (ReadBlob(image,length,pixels) != (ssize_t) length)
512 {
513 ThrowFileException(exception,CorruptImageError,
514 "UnexpectedEndOfFile",image->filename);
515 break;
516 }
517 count=ReadBlob(image,length,pixels);
cristybb503372010-05-27 20:51:26 +0000518 for (y=0; y < (ssize_t) image->extract_info.height; y++)
cristy3ed852e2009-09-05 21:47:34 +0000519 {
520 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000521 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +0000522
cristybb503372010-05-27 20:51:26 +0000523 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000524 x;
525
526 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000527 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000528
cristy21da32d2009-09-12 14:56:09 +0000529 if (count != (ssize_t) length)
530 {
531 ThrowFileException(exception,CorruptImageError,
532 "UnexpectedEndOfFile",image->filename);
533 break;
534 }
cristy3ed852e2009-09-05 21:47:34 +0000535 q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
536 exception);
537 if (q == (PixelPacket *) NULL)
538 break;
539 length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
540 quantum_info,quantum_types[i],pixels,exception);
541 if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
542 break;
543 if (((y-image->extract_info.y) >= 0) &&
cristybb503372010-05-27 20:51:26 +0000544 ((y-image->extract_info.y) < (ssize_t) image->rows))
cristy3ed852e2009-09-05 21:47:34 +0000545 {
546 p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
547 canvas_image->columns,1,exception);
548 q=GetAuthenticPixels(image,0,y-image->extract_info.y,
549 image->columns,1,exception);
550 if ((p == (const PixelPacket *) NULL) ||
551 (q == (PixelPacket *) NULL))
552 break;
cristybb503372010-05-27 20:51:26 +0000553 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000554 {
555 switch(quantum_types[i])
556 {
cristyccf7deb2010-07-31 23:46:58 +0000557 case RedQuantum:
558 {
559 SetRedPixelComponent(q,GetRedPixelComponent(p));
560 break;
561 }
562 case GreenQuantum:
563 {
564 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
565 break;
566 }
567 case BlueQuantum:
568 {
569 SetBluePixelComponent(q,GetBluePixelComponent(p));
570 break;
571 }
cristy3ed852e2009-09-05 21:47:34 +0000572 case OpacityQuantum:
cristyccf7deb2010-07-31 23:46:58 +0000573 case AlphaQuantum:
574 {
575 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
576 break;
577 }
578 default:
579 break;
cristy3ed852e2009-09-05 21:47:34 +0000580 }
581 p++;
582 q++;
583 }
584 if (SyncAuthenticPixels(image,exception) == MagickFalse)
585 break;
586 }
587 count=ReadBlob(image,length,pixels);
cristy3ed852e2009-09-05 21:47:34 +0000588 }
589 if (image->previous == (Image *) NULL)
590 {
591 status=SetImageProgress(image,LoadImageTag,(i+1),5);
592 if (status == MagickFalse)
593 break;
594 }
595 if (i != (channels-1))
596 (void) CloseBlob(image);
597 }
598 if (image->previous == (Image *) NULL)
599 {
600 status=SetImageProgress(image,LoadImageTag,5,5);
601 if (status == MagickFalse)
602 break;
603 }
604 break;
605 }
606 }
607 SetQuantumImageType(image,quantum_type);
cristy3ed852e2009-09-05 21:47:34 +0000608 /*
609 Proceed to next image.
610 */
611 if (image_info->number_scenes != 0)
612 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
613 break;
614 if (count == (ssize_t) length)
615 {
616 /*
617 Allocate next image structure.
618 */
619 AcquireNextImage(image_info,image);
620 if (GetNextImageInList(image) == (Image *) NULL)
621 {
622 image=DestroyImageList(image);
623 return((Image *) NULL);
624 }
625 image=SyncNextImageInList(image);
626 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
627 GetBlobSize(image));
628 if (status == MagickFalse)
629 break;
630 }
631 scene++;
632 } while (count == (ssize_t) length);
cristy3ed852e2009-09-05 21:47:34 +0000633 quantum_info=DestroyQuantumInfo(quantum_info);
cristy01a3f332009-10-27 14:17:37 +0000634 InheritException(&image->exception,&canvas_image->exception);
cristy3ed852e2009-09-05 21:47:34 +0000635 canvas_image=DestroyImage(canvas_image);
636 (void) CloseBlob(image);
637 return(GetFirstImageInList(image));
638}
639
640/*
641%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
642% %
643% %
644% %
645% R e g i s t e r R G B I m a g e %
646% %
647% %
648% %
649%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
650%
651% RegisterRGBImage() adds attributes for the RGB or RGBA image format to
652% the list of supported formats. The attributes include the image format
653% tag, a method to read and/or write the format, whether the format
654% supports the saving of more than one frame to the same file or blob,
655% whether the format supports native in-memory I/O, and a brief
656% description of the format.
657%
658% The format of the RegisterRGBImage method is:
659%
cristybb503372010-05-27 20:51:26 +0000660% size_t RegisterRGBImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000661%
662*/
cristybb503372010-05-27 20:51:26 +0000663ModuleExport size_t RegisterRGBImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000664{
665 MagickInfo
666 *entry;
667
668 entry=SetMagickInfo("RGB");
669 entry->decoder=(DecodeImageHandler *) ReadRGBImage;
670 entry->encoder=(EncodeImageHandler *) WriteRGBImage;
671 entry->raw=MagickTrue;
672 entry->endian_support=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +0000673 entry->description=ConstantString("Raw red, green, and blue samples");
674 entry->module=ConstantString("RGB");
675 (void) RegisterMagickInfo(entry);
676 entry=SetMagickInfo("RBG");
677 entry->decoder=(DecodeImageHandler *) ReadRGBImage;
678 entry->encoder=(EncodeImageHandler *) WriteRGBImage;
679 entry->raw=MagickTrue;
680 entry->endian_support=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +0000681 entry->description=ConstantString("Raw red, blue, and green samples");
682 entry->module=ConstantString("RGB");
683 (void) RegisterMagickInfo(entry);
684 entry=SetMagickInfo("GRB");
685 entry->decoder=(DecodeImageHandler *) ReadRGBImage;
686 entry->encoder=(EncodeImageHandler *) WriteRGBImage;
687 entry->raw=MagickTrue;
688 entry->endian_support=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +0000689 entry->description=ConstantString("Raw green, red, and blue samples");
690 entry->module=ConstantString("RGB");
691 (void) RegisterMagickInfo(entry);
692 entry=SetMagickInfo("GBR");
693 entry->decoder=(DecodeImageHandler *) ReadRGBImage;
694 entry->encoder=(EncodeImageHandler *) WriteRGBImage;
695 entry->raw=MagickTrue;
696 entry->endian_support=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +0000697 entry->description=ConstantString("Raw green, blue, and red samples");
698 entry->module=ConstantString("RGB");
699 (void) RegisterMagickInfo(entry);
700 entry=SetMagickInfo("BRG");
701 entry->decoder=(DecodeImageHandler *) ReadRGBImage;
702 entry->encoder=(EncodeImageHandler *) WriteRGBImage;
703 entry->raw=MagickTrue;
704 entry->endian_support=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +0000705 entry->description=ConstantString("Raw blue, red, and green samples");
706 entry->module=ConstantString("RGB");
707 (void) RegisterMagickInfo(entry);
708 entry=SetMagickInfo("BGR");
709 entry->decoder=(DecodeImageHandler *) ReadRGBImage;
710 entry->encoder=(EncodeImageHandler *) WriteRGBImage;
711 entry->raw=MagickTrue;
712 entry->endian_support=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +0000713 entry->description=ConstantString("Raw blue, green, and red samples");
714 entry->module=ConstantString("RGB");
715 (void) RegisterMagickInfo(entry);
cristy4a16cd52010-01-05 14:04:01 +0000716 entry=SetMagickInfo("BGRA");
717 entry->decoder=(DecodeImageHandler *) ReadRGBImage;
718 entry->encoder=(EncodeImageHandler *) WriteRGBImage;
719 entry->raw=MagickTrue;
720 entry->endian_support=MagickTrue;
cristy4a16cd52010-01-05 14:04:01 +0000721 entry->description=ConstantString("Raw blue, green, red and alpha samples");
722 entry->module=ConstantString("RGB");
723 (void) RegisterMagickInfo(entry);
cristy3ed852e2009-09-05 21:47:34 +0000724 entry=SetMagickInfo("RGBA");
725 entry->decoder=(DecodeImageHandler *) ReadRGBImage;
726 entry->encoder=(EncodeImageHandler *) WriteRGBImage;
727 entry->raw=MagickTrue;
728 entry->endian_support=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +0000729 entry->description=ConstantString("Raw red, green, blue, and alpha samples");
730 entry->module=ConstantString("RGB");
731 (void) RegisterMagickInfo(entry);
732 entry=SetMagickInfo("RGBO");
733 entry->decoder=(DecodeImageHandler *) ReadRGBImage;
734 entry->encoder=(EncodeImageHandler *) WriteRGBImage;
735 entry->raw=MagickTrue;
736 entry->endian_support=MagickTrue;
cristy3ed852e2009-09-05 21:47:34 +0000737 entry->description=ConstantString("Raw red, green, blue, and opacity "
738 "samples");
739 entry->module=ConstantString("RGB");
740 (void) RegisterMagickInfo(entry);
741 return(MagickImageCoderSignature);
742}
743
744/*
745%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
746% %
747% %
748% %
749% U n r e g i s t e r R G B I m a g e %
750% %
751% %
752% %
753%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
754%
755% UnregisterRGBImage() removes format registrations made by the
756% RGB module from the list of supported formats.
757%
758% The format of the UnregisterRGBImage method is:
759%
760% UnregisterRGBImage(void)
761%
762*/
763ModuleExport void UnregisterRGBImage(void)
764{
765 (void) UnregisterMagickInfo("RGBO");
766 (void) UnregisterMagickInfo("RGBA");
767 (void) UnregisterMagickInfo("BGR");
cristy4a16cd52010-01-05 14:04:01 +0000768 (void) UnregisterMagickInfo("BGRA");
cristy3ed852e2009-09-05 21:47:34 +0000769 (void) UnregisterMagickInfo("BRG");
770 (void) UnregisterMagickInfo("GBR");
771 (void) UnregisterMagickInfo("GRB");
772 (void) UnregisterMagickInfo("RBG");
773 (void) UnregisterMagickInfo("RGB");
774}
775
776/*
777%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
778% %
779% %
780% %
781% W r i t e R G B I m a g e %
782% %
783% %
784% %
785%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
786%
787% WriteRGBImage() writes an image to a file in the RGB or RGBA rasterfile
788% format.
789%
790% The format of the WriteRGBImage method is:
791%
792% MagickBooleanType WriteRGBImage(const ImageInfo *image_info,Image *image)
793%
794% A description of each parameter follows.
795%
796% o image_info: the image info.
797%
798% o image: The image.
799%
800*/
801static MagickBooleanType WriteRGBImage(const ImageInfo *image_info,Image *image)
802{
cristybb503372010-05-27 20:51:26 +0000803 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000804 y;
805
806 MagickBooleanType
807 status;
808
809 MagickOffsetType
810 scene;
811
812 QuantumInfo
813 *quantum_info;
814
815 QuantumType
816 quantum_type,
817 quantum_types[4];
818
cristybb503372010-05-27 20:51:26 +0000819 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000820 i;
821
822 ssize_t
823 count;
824
825 size_t
826 length;
827
828 unsigned char
829 *pixels;
830
cristybb503372010-05-27 20:51:26 +0000831 size_t
cristy3ed852e2009-09-05 21:47:34 +0000832 channels;
833
834 /*
835 Allocate memory for pixels.
836 */
837 assert(image_info != (const ImageInfo *) NULL);
838 assert(image_info->signature == MagickSignature);
839 assert(image != (Image *) NULL);
840 assert(image->signature == MagickSignature);
841 if (image->debug != MagickFalse)
842 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
843 if (image_info->interlace != PartitionInterlace)
844 {
845 /*
846 Open output image file.
847 */
848 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
849 if (status == MagickFalse)
850 return(status);
851 }
852 quantum_type=RGBQuantum;
cristya38675f2010-08-21 18:35:13 +0000853 for (i=0; i < 4; i++)
cristy3ed852e2009-09-05 21:47:34 +0000854 {
cristya38675f2010-08-21 18:35:13 +0000855 if (image_info->magick[i] == '\0')
856 break;
857 switch(image_info->magick[i])
cristy3ed852e2009-09-05 21:47:34 +0000858 {
cristy2080f2b2010-08-21 18:43:15 +0000859 case 'R': quantum_types[i]=RedQuantum; break;
860 case 'G': quantum_types[i]=GreenQuantum; break;
861 case 'B': quantum_types[i]=BlueQuantum; break;
862 case 'A':
863 {
864 quantum_types[i]=AlphaQuantum;
865 quantum_type=RGBAQuantum;
866 break;
867 }
868 case 'O':
869 {
870 quantum_types[i]=OpacityQuantum;
871 quantum_type=RGBOQuantum;
872 break;
873 }
874 default:
875 break;
cristy3ed852e2009-09-05 21:47:34 +0000876 }
877 }
cristya38675f2010-08-21 18:35:13 +0000878 channels=i;
cristy3ed852e2009-09-05 21:47:34 +0000879 scene=0;
880 do
881 {
882 /*
883 Convert MIFF to RGB raster pixels.
884 */
885 if (image->colorspace != RGBColorspace)
886 (void) TransformImageColorspace(image,RGBColorspace);
887 if ((LocaleCompare(image_info->magick,"RGBA") == 0) &&
888 (image->matte == MagickFalse))
889 (void) SetImageAlphaChannel(image,ResetAlphaChannel);
890 quantum_info=AcquireQuantumInfo(image_info,image);
891 if (quantum_info == (QuantumInfo *) NULL)
892 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
893 pixels=GetQuantumPixels(quantum_info);
894 switch (image_info->interlace)
895 {
896 case NoInterlace:
897 default:
898 {
899 CacheView
900 *image_view;
901
902 PixelPacket
903 px;
904
905 Quantum
cristya38675f2010-08-21 18:35:13 +0000906 *qx[4];
cristy3ed852e2009-09-05 21:47:34 +0000907
908 /*
909 No interlacing: RGBRGBRGBRGBRGBRGB...
910 */
911 image_view=AcquireCacheView(image);
cristybb503372010-05-27 20:51:26 +0000912 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000913 {
cristybb503372010-05-27 20:51:26 +0000914 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000915 x;
916
917 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000918 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000919
920 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
921 &image->exception);
922 if (q == (PixelPacket *) NULL)
923 break;
cristybb503372010-05-27 20:51:26 +0000924 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000925 {
926 px=(*q);
927 qx[0]=&(q->red);
928 qx[1]=&(q->green);
929 qx[2]=&(q->blue);
cristya38675f2010-08-21 18:35:13 +0000930 qx[3]=&(q->opacity);
931 for (i=0; i < channels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000932 switch (quantum_types[i])
933 {
cristya38675f2010-08-21 18:35:13 +0000934 case RedQuantum: *qx[i]=px.red; break;
cristy3ed852e2009-09-05 21:47:34 +0000935 case GreenQuantum: *qx[i]=px.green; break;
cristya38675f2010-08-21 18:35:13 +0000936 case BlueQuantum: *qx[i]=px.blue; break;
937 case AlphaQuantum: *qx[i]=px.opacity; break;
938 case OpacityQuantum: *qx[i]=px.opacity; break;
939 default: break;
cristy3ed852e2009-09-05 21:47:34 +0000940 }
941 q++;
942 }
943 length=ExportQuantumPixels(image,image_view,quantum_info,quantum_type,
944 pixels,&image->exception);
945 count=WriteBlob(image,length,pixels);
946 if (count != (ssize_t) length)
947 break;
948 if (image->previous == (Image *) NULL)
949 {
cristycee97112010-05-28 00:44:52 +0000950 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
951 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000952 if (status == MagickFalse)
953 break;
954 }
955 }
956 image_view=DestroyCacheView(image_view);
957 break;
958 }
959 case LineInterlace:
960 {
961 /*
962 Line interlacing: RRR...GGG...BBB...RRR...GGG...BBB...
963 */
cristybb503372010-05-27 20:51:26 +0000964 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000965 {
966 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000967 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +0000968
969 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
970 if (p == (const PixelPacket *) NULL)
971 break;
cristybb503372010-05-27 20:51:26 +0000972 for (i=0; i < (ssize_t) channels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000973 {
974 length=ExportQuantumPixels(image,(const CacheView *) NULL,
975 quantum_info,quantum_types[i],pixels,&image->exception);
976 count=WriteBlob(image,length,pixels);
977 if (count != (ssize_t) length)
978 break;
979 }
980 if (image->previous == (Image *) NULL)
981 {
cristycee97112010-05-28 00:44:52 +0000982 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
983 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000984 if (status == MagickFalse)
985 break;
986 }
987 }
988 break;
989 }
990 case PlaneInterlace:
991 {
992 /*
993 Plane interlacing: RRRRRR...GGGGGG...BBBBBB...
994 */
cristybb503372010-05-27 20:51:26 +0000995 for (i=0; i < (ssize_t) channels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000996 {
cristybb503372010-05-27 20:51:26 +0000997 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000998 {
999 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001000 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00001001
1002 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1003 if (p == (const PixelPacket *) NULL)
1004 break;
1005 length=ExportQuantumPixels(image,(const CacheView *) NULL,
1006 quantum_info,quantum_types[i],pixels,&image->exception);
1007 count=WriteBlob(image,length,pixels);
1008 if (count != (ssize_t) length)
1009 break;
1010 }
1011 if (image->previous == (Image *) NULL)
1012 {
1013 status=SetImageProgress(image,SaveImageTag,(i+1),5);
1014 if (status == MagickFalse)
1015 break;
1016 }
1017 }
1018 if (image->previous == (Image *) NULL)
1019 {
1020 status=SetImageProgress(image,SaveImageTag,5,5);
1021 if (status == MagickFalse)
1022 break;
1023 }
1024 break;
1025 }
1026 case PartitionInterlace:
1027 {
1028 char
1029 sfx[] = {0, 0};
1030
1031 /*
1032 Partition interlacing: RRRRRR..., GGGGGG..., BBBBBB...
1033 */
cristybb503372010-05-27 20:51:26 +00001034 for (i=0; i < (ssize_t) channels; i++)
cristy3ed852e2009-09-05 21:47:34 +00001035 {
1036 sfx[0]=image_info->magick[i];
1037 AppendImageFormat(sfx,image->filename);
1038 status=OpenBlob(image_info,image,scene == 0 ? WriteBinaryBlobMode :
1039 AppendBinaryBlobMode,&image->exception);
1040 if (status == MagickFalse)
1041 return(status);
cristybb503372010-05-27 20:51:26 +00001042 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001043 {
1044 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001045 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00001046
1047 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1048 if (p == (const PixelPacket *) NULL)
1049 break;
1050 length=ExportQuantumPixels(image,(const CacheView *) NULL,
1051 quantum_info,quantum_types[i],pixels,&image->exception);
1052 count=WriteBlob(image,length,pixels);
1053 if (count != (ssize_t) length)
1054 break;
1055 }
1056 if (image->previous == (Image *) NULL)
1057 {
1058 status=SetImageProgress(image,SaveImageTag,(i+1),5);
1059 if (status == MagickFalse)
1060 break;
1061 }
1062 (void) CloseBlob(image);
1063 }
1064 (void) CopyMagickString(image->filename,image_info->filename,
1065 MaxTextExtent);
1066 if (image->previous == (Image *) NULL)
1067 {
1068 status=SetImageProgress(image,SaveImageTag,5,5);
1069 if (status == MagickFalse)
1070 break;
1071 }
1072 break;
1073 }
1074 }
1075 quantum_info=DestroyQuantumInfo(quantum_info);
1076 if (GetNextImageInList(image) == (Image *) NULL)
1077 break;
1078 image=SyncNextImageInList(image);
1079 status=SetImageProgress(image,SaveImagesTag,scene++,
1080 GetImageListLength(image));
1081 if (status == MagickFalse)
1082 break;
1083 } while (image_info->adjoin != MagickFalse);
1084 (void) CloseBlob(image);
1085 return(MagickTrue);
1086}