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