blob: c84d3eaa22d8fe62cb71f699168df7046d673401 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% RRRR AAA W W %
7% R R A A W W %
8% RRRR AAAAA W W W %
9% R R A A WW WW %
10% R R A A W W %
11% %
12% %
13% Read/Write RAW Image Format %
14% %
15% Software Design %
16% John Cristy %
17% July 1992 %
18% %
19% %
cristy16af1cb2009-12-11 21:38:29 +000020% Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% 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/quantum-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
64/*
65 Forward declarations.
66*/
67static MagickBooleanType
68 WriteRAWImage(const ImageInfo *,Image *);
69
70/*
71%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
72% %
73% %
74% %
75% R e a d R A W I m a g e %
76% %
77% %
78% %
79%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
80%
81% ReadRAWImage() reads an image of raw samples and returns it. It allocates
82% the memory necessary for the new Image structure and returns a pointer to
83% the new image.
84%
85% The format of the ReadRAWImage method is:
86%
87% Image *ReadRAWImage(const ImageInfo *image_info,ExceptionInfo *exception)
88%
89% A description of each parameter follows:
90%
91% o image_info: the image info.
92%
93% o exception: return any errors or warnings in this structure.
94%
95*/
96static Image *ReadRAWImage(const ImageInfo *image_info,
97 ExceptionInfo *exception)
98{
99 Image
100 *canvas_image,
101 *image;
102
103 long
104 y;
105
106 MagickBooleanType
107 status;
108
cristy9af8a2a2009-10-02 13:29:27 +0000109 MagickOffsetType
110 scene;
111
cristy3ed852e2009-09-05 21:47:34 +0000112 QuantumInfo
113 *quantum_info;
114
115 QuantumType
116 quantum_type;
117
cristy3ed852e2009-09-05 21:47:34 +0000118 register long
cristy9af8a2a2009-10-02 13:29:27 +0000119 i;
cristy3ed852e2009-09-05 21:47:34 +0000120
121 ssize_t
122 count;
123
124 size_t
125 length;
126
127 unsigned char
128 *pixels;
129
130 /*
131 Open image file.
132 */
133 assert(image_info != (const ImageInfo *) NULL);
134 assert(image_info->signature == MagickSignature);
135 if (image_info->debug != MagickFalse)
136 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
137 image_info->filename);
138 assert(exception != (ExceptionInfo *) NULL);
139 assert(exception->signature == MagickSignature);
140 image=AcquireImage(image_info);
141 if ((image->columns == 0) || (image->rows == 0))
142 ThrowReaderException(OptionError,"MustSpecifyImageSize");
143 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
144 if (status == MagickFalse)
145 {
146 image=DestroyImageList(image);
147 return((Image *) NULL);
148 }
149 for (i=0; i < image->offset; i++)
150 if (ReadBlobByte(image) == EOF)
151 {
152 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
153 image->filename);
154 break;
155 }
156 /*
157 Create virtual canvas to support cropping (i.e. image.gray[100x100+10+20]).
158 */
159 canvas_image=CloneImage(image,image->extract_info.width,1,MagickFalse,
160 exception);
161 (void) SetImageVirtualPixelMethod(canvas_image,BlackVirtualPixelMethod);
162 quantum_type=GrayQuantum;
163 quantum_info=AcquireQuantumInfo(image_info,canvas_image);
164 if (quantum_info == (QuantumInfo *) NULL)
165 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
166 pixels=GetQuantumPixels(quantum_info);
167 if (image_info->number_scenes != 0)
168 while (image->scene < image_info->scene)
169 {
170 /*
171 Skip to next image.
172 */
173 image->scene++;
174 length=GetQuantumExtent(canvas_image,quantum_info,quantum_type);
175 for (y=0; y < (long) image->rows; y++)
176 {
177 count=ReadBlob(image,length,pixels);
178 if (count != (ssize_t) length)
179 break;
180 }
181 }
cristy9af8a2a2009-10-02 13:29:27 +0000182 scene=0;
183 count=0;
184 length=0;
cristy3ed852e2009-09-05 21:47:34 +0000185 do
186 {
187 /*
188 Read pixels to virtual canvas image then push to image.
189 */
190 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
191 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
192 break;
cristy9af8a2a2009-10-02 13:29:27 +0000193 if (scene == 0)
194 {
195 length=GetQuantumExtent(canvas_image,quantum_info,quantum_type);
196 count=ReadBlob(image,length,pixels);
197 }
cristy3ed852e2009-09-05 21:47:34 +0000198 for (y=0; y < (long) image->extract_info.height; y++)
199 {
cristy9af8a2a2009-10-02 13:29:27 +0000200 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000201 *restrict p;
cristy9af8a2a2009-10-02 13:29:27 +0000202
203 register long
204 x;
205
206 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000207 *restrict q;
cristy9af8a2a2009-10-02 13:29:27 +0000208
209 if (count != (ssize_t) length)
210 {
211 ThrowFileException(exception,CorruptImageError,
212 "UnexpectedEndOfFile",image->filename);
213 break;
214 }
cristy3ed852e2009-09-05 21:47:34 +0000215 q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,exception);
216 if (q == (PixelPacket *) NULL)
217 break;
218 length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,quantum_info,
219 quantum_type,pixels,exception);
220 if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
221 break;
cristy3ed852e2009-09-05 21:47:34 +0000222 if (((y-image->extract_info.y) >= 0) &&
223 ((y-image->extract_info.y) < (long) image->rows))
224 {
225 p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
cristy9af8a2a2009-10-02 13:29:27 +0000226 image->columns,1,exception);
227 q=QueueAuthenticPixels(image,0,y-image->extract_info.y,image->columns,
228 1,exception);
cristy3ed852e2009-09-05 21:47:34 +0000229 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
230 break;
cristy3ed852e2009-09-05 21:47:34 +0000231 for (x=0; x < (long) image->columns; x++)
232 {
cristyce70c172010-01-07 17:15:30 +0000233 SetRedPixelComponent(q,GetRedPixelComponent(p));
234 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
235 SetBluePixelComponent(q,GetBluePixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +0000236 p++;
237 q++;
238 }
239 if (SyncAuthenticPixels(image,exception) == MagickFalse)
240 break;
241 }
242 if (image->previous == (Image *) NULL)
243 {
244 status=SetImageProgress(image,LoadImageTag,y,image->rows);
245 if (status == MagickFalse)
246 break;
247 }
cristy9af8a2a2009-10-02 13:29:27 +0000248 count=ReadBlob(image,length,pixels);
cristy3ed852e2009-09-05 21:47:34 +0000249 }
250 SetQuantumImageType(image,quantum_type);
251 /*
252 Proceed to next image.
253 */
254 if (image_info->number_scenes != 0)
255 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
256 break;
257 if (count == (ssize_t) length)
258 {
259 /*
260 Allocate next image structure.
261 */
262 AcquireNextImage(image_info,image);
263 if (GetNextImageInList(image) == (Image *) NULL)
264 {
265 image=DestroyImageList(image);
266 return((Image *) NULL);
267 }
268 image=SyncNextImageInList(image);
269 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
270 GetBlobSize(image));
271 if (status == MagickFalse)
272 break;
273 }
cristy9af8a2a2009-10-02 13:29:27 +0000274 scene++;
cristy3ed852e2009-09-05 21:47:34 +0000275 } while (count == (ssize_t) length);
276 quantum_info=DestroyQuantumInfo(quantum_info);
cristy01a3f332009-10-27 14:17:37 +0000277 InheritException(&image->exception,&canvas_image->exception);
cristy3ed852e2009-09-05 21:47:34 +0000278 canvas_image=DestroyImage(canvas_image);
279 (void) CloseBlob(image);
280 return(GetFirstImageInList(image));
281}
282
283/*
284%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
285% %
286% %
287% %
288% R e g i s t e r R A W I m a g e %
289% %
290% %
291% %
292%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
293%
294% RegisterRAWImage() adds attributes for the RAW image format to the list of
295% supported formats. The attributes include the image format tag, a method to
296% read and/or write the format, whether the format supports the saving of
297% more than one frame to the same file or blob, whether the format supports
298% native in-memory I/O, and a brief description of the format.
299%
300% The format of the RegisterRAWImage method is:
301%
302% unsigned long RegisterRAWImage(void)
303%
304*/
305ModuleExport unsigned long RegisterRAWImage(void)
306{
307 MagickInfo
308 *entry;
309
310 entry=SetMagickInfo("R");
311 entry->decoder=(DecodeImageHandler *) ReadRAWImage;
312 entry->encoder=(EncodeImageHandler *) WriteRAWImage;
313 entry->raw=MagickTrue;
314 entry->endian_support=MagickTrue;
315 entry->format_type=ExplicitFormatType;
316 entry->description=ConstantString("Raw red samples");
317 entry->module=ConstantString("RAW");
318 (void) RegisterMagickInfo(entry);
319 entry=SetMagickInfo("C");
320 entry->decoder=(DecodeImageHandler *) ReadRAWImage;
321 entry->encoder=(EncodeImageHandler *) WriteRAWImage;
322 entry->raw=MagickTrue;
323 entry->endian_support=MagickTrue;
324 entry->format_type=ExplicitFormatType;
325 entry->description=ConstantString("Raw cyan samples");
326 entry->module=ConstantString("RAW");
327 (void) RegisterMagickInfo(entry);
328 entry=SetMagickInfo("G");
329 entry->decoder=(DecodeImageHandler *) ReadRAWImage;
330 entry->encoder=(EncodeImageHandler *) WriteRAWImage;
331 entry->raw=MagickTrue;
332 entry->endian_support=MagickTrue;
333 entry->format_type=ExplicitFormatType;
334 entry->description=ConstantString("Raw green samples");
335 entry->module=ConstantString("RAW");
336 (void) RegisterMagickInfo(entry);
337 entry=SetMagickInfo("M");
338 entry->decoder=(DecodeImageHandler *) ReadRAWImage;
339 entry->encoder=(EncodeImageHandler *) WriteRAWImage;
340 entry->raw=MagickTrue;
341 entry->endian_support=MagickTrue;
342 entry->format_type=ExplicitFormatType;
343 entry->description=ConstantString("Raw magenta samples");
344 entry->module=ConstantString("RAW");
345 (void) RegisterMagickInfo(entry);
346 entry=SetMagickInfo("B");
347 entry->decoder=(DecodeImageHandler *) ReadRAWImage;
348 entry->encoder=(EncodeImageHandler *) WriteRAWImage;
349 entry->raw=MagickTrue;
350 entry->endian_support=MagickTrue;
351 entry->description=ConstantString("Raw blue samples");
352 entry->format_type=ExplicitFormatType;
353 entry->module=ConstantString("RAW");
354 (void) RegisterMagickInfo(entry);
355 entry=SetMagickInfo("Y");
356 entry->decoder=(DecodeImageHandler *) ReadRAWImage;
357 entry->encoder=(EncodeImageHandler *) WriteRAWImage;
358 entry->raw=MagickTrue;
359 entry->endian_support=MagickTrue;
360 entry->format_type=ExplicitFormatType;
361 entry->description=ConstantString("Raw yellow samples");
362 entry->module=ConstantString("RAW");
363 (void) RegisterMagickInfo(entry);
364 entry=SetMagickInfo("A");
365 entry->decoder=(DecodeImageHandler *) ReadRAWImage;
366 entry->encoder=(EncodeImageHandler *) WriteRAWImage;
367 entry->raw=MagickTrue;
368 entry->endian_support=MagickTrue;
369 entry->description=ConstantString("Raw alpha samples");
370 entry->module=ConstantString("RAW");
371 (void) RegisterMagickInfo(entry);
372 entry=SetMagickInfo("O");
373 entry->decoder=(DecodeImageHandler *) ReadRAWImage;
374 entry->encoder=(EncodeImageHandler *) WriteRAWImage;
375 entry->raw=MagickTrue;
376 entry->endian_support=MagickTrue;
377 entry->format_type=ExplicitFormatType;
378 entry->description=ConstantString("Raw opacity samples");
379 entry->module=ConstantString("RAW");
380 (void) RegisterMagickInfo(entry);
381 entry=SetMagickInfo("K");
382 entry->decoder=(DecodeImageHandler *) ReadRAWImage;
383 entry->encoder=(EncodeImageHandler *) WriteRAWImage;
384 entry->raw=MagickTrue;
385 entry->endian_support=MagickTrue;
386 entry->format_type=ExplicitFormatType;
387 entry->description=ConstantString("Raw black samples");
388 entry->module=ConstantString("RAW");
389 (void) RegisterMagickInfo(entry);
390 return(MagickImageCoderSignature);
391}
392
393/*
394%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
395% %
396% %
397% %
398% U n r e g i s t e r R A W I m a g e %
399% %
400% %
401% %
402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
403%
404% UnregisterRAWImage() removes format registrations made by the RAW module
405% from the list of supported formats.
406%
407% The format of the UnregisterRAWImage method is:
408%
409% UnregisterRAWImage(void)
410%
411*/
412ModuleExport void UnregisterRAWImage(void)
413{
414 (void) UnregisterMagickInfo("R");
415 (void) UnregisterMagickInfo("C");
416 (void) UnregisterMagickInfo("G");
417 (void) UnregisterMagickInfo("M");
418 (void) UnregisterMagickInfo("B");
419 (void) UnregisterMagickInfo("Y");
420 (void) UnregisterMagickInfo("A");
421 (void) UnregisterMagickInfo("O");
422 (void) UnregisterMagickInfo("K");
423}
424
425/*
426%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
427% %
428% %
429% %
430% W r i t e R A W I m a g e %
431% %
432% %
433% %
434%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
435%
436% WriteRAWImage() writes an image to a file as raw intensity values.
437%
438% The format of the WriteRAWImage method is:
439%
440% MagickBooleanType WriteRAWImage(const ImageInfo *image_info,Image *image)
441%
442% A description of each parameter follows.
443%
444% o image_info: the image info.
445%
446% o image: The image.
447%
448*/
449static MagickBooleanType WriteRAWImage(const ImageInfo *image_info,Image *image)
450{
451 long
452 y;
453
454 MagickOffsetType
455 scene;
456
457 QuantumInfo
458 *quantum_info;
459
460 QuantumType
461 quantum_type;
462
463 MagickBooleanType
464 status;
465
466 register const PixelPacket
467 *p;
468
469 ssize_t
470 count;
471
472 size_t
473 length;
474
475 unsigned char
476 *pixels;
477
478 /*
479 Open output image file.
480 */
481 assert(image_info != (const ImageInfo *) NULL);
482 assert(image_info->signature == MagickSignature);
483 assert(image != (Image *) NULL);
484 assert(image->signature == MagickSignature);
485 if (image->debug != MagickFalse)
486 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
487 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
488 if (status == MagickFalse)
489 return(status);
490 switch (*image->magick)
491 {
492 case 'A':
493 case 'a':
494 {
495 quantum_type=AlphaQuantum;
496 break;
497 }
498 case 'B':
499 case 'b':
500 {
501 quantum_type=BlueQuantum;
502 break;
503 }
504 case 'C':
505 case 'c':
506 {
507 quantum_type=CyanQuantum;
508 if (image->colorspace == CMYKColorspace)
509 break;
510 ThrowWriterException(ImageError,"ColorSeparatedImageRequired");
511 }
512 case 'g':
513 case 'G':
514 {
515 quantum_type=GreenQuantum;
516 break;
517 }
518 case 'I':
519 case 'i':
520 {
521 quantum_type=IndexQuantum;
522 break;
523 }
524 case 'K':
525 case 'k':
526 {
527 quantum_type=BlackQuantum;
528 if (image->colorspace == CMYKColorspace)
529 break;
530 ThrowWriterException(ImageError,"ColorSeparatedImageRequired");
531 }
532 case 'M':
533 case 'm':
534 {
535 quantum_type=MagentaQuantum;
536 if (image->colorspace == CMYKColorspace)
537 break;
538 ThrowWriterException(ImageError,"ColorSeparatedImageRequired");
539 }
540 case 'o':
541 case 'O':
542 {
543 quantum_type=OpacityQuantum;
544 break;
545 }
546 case 'R':
547 case 'r':
548 {
549 quantum_type=RedQuantum;
550 break;
551 }
552 case 'Y':
553 case 'y':
554 {
555 quantum_type=YellowQuantum;
556 if (image->colorspace == CMYKColorspace)
557 break;
558 ThrowWriterException(ImageError,"ColorSeparatedImageRequired");
559 }
560 default:
561 {
562 quantum_type=GrayQuantum;
563 break;
564 }
565 }
566 scene=0;
567 do
568 {
569 /*
570 Convert image to RAW raster pixels.
571 */
572 quantum_info=AcquireQuantumInfo(image_info,image);
573 if (quantum_info == (QuantumInfo *) NULL)
574 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
575 pixels=GetQuantumPixels(quantum_info);
576 for (y=0; y < (long) image->rows; y++)
577 {
578 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
579 if (p == (const PixelPacket *) NULL)
580 break;
581 length=ExportQuantumPixels(image,(const CacheView *) NULL,quantum_info,
582 quantum_type,pixels,&image->exception);
583 count=WriteBlob(image,length,pixels);
584 if (count != (ssize_t) length)
585 break;
586 if (image->previous == (Image *) NULL)
587 {
588 status=SetImageProgress(image,SaveImageTag,y,image->rows);
589 if (status == MagickFalse)
590 break;
591 }
592 }
593 quantum_info=DestroyQuantumInfo(quantum_info);
594 if (GetNextImageInList(image) == (Image *) NULL)
595 break;
596 image=SyncNextImageInList(image);
597 status=SetImageProgress(image,SaveImagesTag,scene++,
598 GetImageListLength(image));
599 if (status == MagickFalse)
600 break;
601 } while (image_info->adjoin != MagickFalse);
602 (void) CloseBlob(image);
603 return(MagickTrue);
604}