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