1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                         GGGG  RRRR    AAA   Y   Y                           %
7 %                        G      R   R  A   A   Y Y                            %
8 %                        G  GG  RRRR   AAAAA    Y                             %
9 %                        G   G  R R    A   A    Y                             %
10 %                         GGG   R  R   A   A    Y                             %
11 %                                                                             %
12 %                                                                             %
13 %                     Read/Write Raw GRAY Image Format                        %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                   Cristy                                    %
17 %                                 July 1992                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2019 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/channel.h"
47 #include "MagickCore/colorspace.h"
48 #include "MagickCore/colorspace-private.h"
49 #include "MagickCore/constitute.h"
50 #include "MagickCore/exception.h"
51 #include "MagickCore/exception-private.h"
52 #include "MagickCore/image.h"
53 #include "MagickCore/image-private.h"
54 #include "MagickCore/list.h"
55 #include "MagickCore/magick.h"
56 #include "MagickCore/memory_.h"
57 #include "MagickCore/monitor.h"
58 #include "MagickCore/monitor-private.h"
59 #include "MagickCore/pixel-accessor.h"
60 #include "MagickCore/quantum-private.h"
61 #include "MagickCore/static.h"
62 #include "MagickCore/statistic.h"
63 #include "MagickCore/string_.h"
64 #include "MagickCore/module.h"
65 #include "MagickCore/utility.h"
66 
67 /*
68   Forward declarations.
69 */
70 static MagickBooleanType
71   WriteGRAYImage(const ImageInfo *,Image *,ExceptionInfo *);
72 
73 /*
74 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
75 %                                                                             %
76 %                                                                             %
77 %                                                                             %
78 %   R e a d G R A Y I m a g e                                                 %
79 %                                                                             %
80 %                                                                             %
81 %                                                                             %
82 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
83 %
84 %  ReadGRAYImage() reads an image of raw GRAY samples and returns it.  It
85 %  allocates the memory necessary for the new Image structure and returns a
86 %  pointer to the new image.
87 %
88 %  The format of the ReadGRAYImage method is:
89 %
90 %      Image *ReadGRAYImage(const ImageInfo *image_info,
91 %        ExceptionInfo *exception)
92 %
93 %  A description of each parameter follows:
94 %
95 %    o image_info: the image info.
96 %
97 %    o exception: return any errors or warnings in this structure.
98 %
99 */
ReadGRAYImage(const ImageInfo * image_info,ExceptionInfo * exception)100 static Image *ReadGRAYImage(const ImageInfo *image_info,
101   ExceptionInfo *exception)
102 {
103   const unsigned char
104     *pixels;
105 
106   Image
107     *canvas_image,
108     *image;
109 
110   MagickBooleanType
111     status;
112 
113   MagickOffsetType
114     scene;
115 
116   QuantumInfo
117     *quantum_info;
118 
119   QuantumType
120     quantum_type;
121 
122   register ssize_t
123     i;
124 
125   size_t
126     length;
127 
128   ssize_t
129     count,
130     y;
131 
132   /*
133     Open image file.
134   */
135   assert(image_info != (const ImageInfo *) NULL);
136   assert(image_info->signature == MagickCoreSignature);
137   if (image_info->debug != MagickFalse)
138     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
139       image_info->filename);
140   assert(exception != (ExceptionInfo *) NULL);
141   assert(exception->signature == MagickCoreSignature);
142   image=AcquireImage(image_info,exception);
143   if ((image->columns == 0) || (image->rows == 0))
144     ThrowReaderException(OptionError,"MustSpecifyImageSize");
145   image->colorspace=GRAYColorspace;
146   if (image_info->interlace != PartitionInterlace)
147     {
148       status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
149       if (status == MagickFalse)
150         {
151           image=DestroyImageList(image);
152           return((Image *) NULL);
153         }
154       if (DiscardBlobBytes(image,(MagickSizeType) image->offset) == MagickFalse)
155         ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
156           image->filename);
157     }
158   /*
159     Create virtual canvas to support cropping (i.e. image.rgb[100x100+10+20]).
160   */
161   canvas_image=CloneImage(image,image->extract_info.width,1,MagickFalse,
162     exception);
163   if(canvas_image == (Image *) NULL)
164     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
165   (void) SetImageVirtualPixelMethod(canvas_image,BlackVirtualPixelMethod,
166     exception);
167   quantum_info=AcquireQuantumInfo(image_info,canvas_image);
168   if (quantum_info == (QuantumInfo *) NULL)
169     {
170       canvas_image=DestroyImage(canvas_image);
171       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
172     }
173   quantum_type=GrayQuantum;
174   if (LocaleCompare(image_info->magick,"GRAYA") == 0)
175     {
176       quantum_type=GrayAlphaQuantum;
177       image->alpha_trait=BlendPixelTrait;
178       canvas_image->alpha_trait=BlendPixelTrait;
179     }
180   pixels=(const unsigned char *) NULL;
181   if (image_info->number_scenes != 0)
182     while (image->scene < image_info->scene)
183     {
184       /*
185         Skip to next image.
186       */
187       image->scene++;
188       length=GetQuantumExtent(canvas_image,quantum_info,quantum_type);
189       for (y=0; y < (ssize_t) image->rows; y++)
190       {
191         pixels=(const unsigned char *) ReadBlobStream(image,length,
192           GetQuantumPixels(quantum_info),&count);
193         if (count != (ssize_t) length)
194           break;
195       }
196     }
197   count=0;
198   length=0;
199   scene=0;
200   status=MagickTrue;
201   do
202   {
203     /*
204       Read pixels to virtual canvas image then push to image.
205     */
206     if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
207       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
208         break;
209     status=SetImageExtent(image,image->columns,image->rows,exception);
210     if (status == MagickFalse)
211       break;
212     switch (image_info->interlace)
213     {
214       case NoInterlace:
215       default:
216       {
217         /*
218           No interlacing:  GGG...
219         */
220         if (scene == 0)
221           {
222             length=GetQuantumExtent(canvas_image,quantum_info,quantum_type);
223             pixels=(const unsigned char *) ReadBlobStream(image,length,
224               GetQuantumPixels(quantum_info),&count);
225           }
226         for (y=0; y < (ssize_t) image->extract_info.height; y++)
227         {
228           register const Quantum
229             *magick_restrict p;
230 
231           register Quantum
232             *magick_restrict q;
233 
234           register ssize_t
235             x;
236 
237           if (count != (ssize_t) length)
238             {
239               status=MagickFalse;
240               ThrowFileException(exception,CorruptImageError,
241                 "UnexpectedEndOfFile",image->filename);
242               break;
243             }
244           q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
245             exception);
246           if (q == (Quantum *) NULL)
247             break;
248           length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
249             quantum_info,quantum_type,pixels,exception);
250           if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
251             break;
252           if (((y-image->extract_info.y) >= 0) &&
253               ((y-image->extract_info.y) < (ssize_t) image->rows))
254             {
255               p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
256                 canvas_image->columns,1,exception);
257               q=QueueAuthenticPixels(image,0,y-image->extract_info.y,
258                 image->columns,1,exception);
259               if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
260                 break;
261               for (x=0; x < (ssize_t) image->columns; x++)
262               {
263                 SetPixelRed(image,GetPixelRed(canvas_image,p),q);
264                 SetPixelGreen(image,GetPixelGreen(canvas_image,p),q);
265                 SetPixelBlue(image,GetPixelBlue(canvas_image,p),q);
266                 SetPixelAlpha(image,OpaqueAlpha,q);
267                 if (image->alpha_trait != UndefinedPixelTrait)
268                   SetPixelAlpha(image,GetPixelAlpha(canvas_image,p),q);
269                 p+=GetPixelChannels(canvas_image);
270                 q+=GetPixelChannels(image);
271               }
272               if (SyncAuthenticPixels(image,exception) == MagickFalse)
273                 break;
274             }
275           if (image->previous == (Image *) NULL)
276             {
277               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
278                 image->rows);
279               if (status == MagickFalse)
280                 break;
281             }
282           pixels=(const unsigned char *) ReadBlobStream(image,length,
283             GetQuantumPixels(quantum_info),&count);
284         }
285         break;
286       }
287       case LineInterlace:
288       {
289         static QuantumType
290           quantum_types[4] =
291           {
292             GrayQuantum,
293             AlphaQuantum
294           };
295 
296         /*
297           Line interlacing:  G...G...G...
298         */
299         if (scene == 0)
300           {
301             length=GetQuantumExtent(canvas_image,quantum_info,RedQuantum);
302             pixels=(const unsigned char *) ReadBlobStream(image,length,
303               GetQuantumPixels(quantum_info),&count);
304           }
305         for (y=0; y < (ssize_t) image->extract_info.height; y++)
306         {
307           for (i=0; i < (ssize_t) (image->alpha_trait != UndefinedPixelTrait ? 4 : 3); i++)
308           {
309             register const Quantum
310               *magick_restrict p;
311 
312             register Quantum
313               *magick_restrict q;
314 
315             register ssize_t
316               x;
317 
318             if (count != (ssize_t) length)
319               {
320                 status=MagickFalse;
321                 ThrowFileException(exception,CorruptImageError,
322                   "UnexpectedEndOfFile",image->filename);
323                 break;
324               }
325             quantum_type=quantum_types[i];
326             q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
327               exception);
328             if (q == (Quantum *) NULL)
329               break;
330             length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
331               quantum_info,quantum_type,pixels,exception);
332             if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
333               break;
334             if (((y-image->extract_info.y) >= 0) &&
335                 ((y-image->extract_info.y) < (ssize_t) image->rows))
336               {
337                 p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,
338                   0,canvas_image->columns,1,exception);
339                 q=GetAuthenticPixels(image,0,y-image->extract_info.y,
340                   image->columns,1,exception);
341                 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
342                   break;
343                 for (x=0; x < (ssize_t) image->columns; x++)
344                 {
345                   switch (quantum_type)
346                   {
347                     case GrayQuantum:
348                     {
349                       SetPixelGray(image,GetPixelGray(canvas_image,p),q);
350                       break;
351                     }
352                     case AlphaQuantum:
353                     {
354                       SetPixelAlpha(image,GetPixelAlpha(canvas_image,p),q);
355                       break;
356                     }
357                     default:
358                       break;
359                   }
360                   p+=GetPixelChannels(canvas_image);
361                   q+=GetPixelChannels(image);
362                 }
363                 if (SyncAuthenticPixels(image,exception) == MagickFalse)
364                   break;
365               }
366             pixels=(const unsigned char *) ReadBlobStream(image,length,
367               GetQuantumPixels(quantum_info),&count);
368           }
369           if (image->previous == (Image *) NULL)
370             {
371               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
372                 image->rows);
373               if (status == MagickFalse)
374                 break;
375             }
376         }
377         break;
378       }
379       case PlaneInterlace:
380       {
381         /*
382           Plane interlacing:  G...G...G...
383         */
384         if (scene == 0)
385           {
386             length=GetQuantumExtent(canvas_image,quantum_info,RedQuantum);
387             pixels=(const unsigned char *) ReadBlobStream(image,length,
388               GetQuantumPixels(quantum_info),&count);
389           }
390         for (y=0; y < (ssize_t) image->extract_info.height; y++)
391         {
392           register const Quantum
393             *magick_restrict p;
394 
395           register Quantum
396             *magick_restrict q;
397 
398           register ssize_t
399             x;
400 
401           if (count != (ssize_t) length)
402             {
403               status=MagickFalse;
404               ThrowFileException(exception,CorruptImageError,
405                 "UnexpectedEndOfFile",image->filename);
406               break;
407             }
408           q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
409             exception);
410           if (q == (Quantum *) NULL)
411             break;
412           length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
413             quantum_info,RedQuantum,pixels,exception);
414           if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
415             break;
416           if (((y-image->extract_info.y) >= 0) &&
417               ((y-image->extract_info.y) < (ssize_t) image->rows))
418             {
419               p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
420                 canvas_image->columns,1,exception);
421               q=GetAuthenticPixels(image,0,y-image->extract_info.y,
422                 image->columns,1,exception);
423               if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
424                 break;
425               for (x=0; x < (ssize_t) image->columns; x++)
426               {
427                 SetPixelGray(image,GetPixelGray(canvas_image,p),q);
428                 p+=GetPixelChannels(canvas_image);
429                 q+=GetPixelChannels(image);
430               }
431               if (SyncAuthenticPixels(image,exception) == MagickFalse)
432                 break;
433             }
434           pixels=(const unsigned char *) ReadBlobStream(image,length,
435             GetQuantumPixels(quantum_info),&count);
436         }
437         if (image->previous == (Image *) NULL)
438           {
439             status=SetImageProgress(image,LoadImageTag,1,6);
440             if (status == MagickFalse)
441               break;
442           }
443         if (image->alpha_trait != UndefinedPixelTrait)
444           {
445             for (y=0; y < (ssize_t) image->extract_info.height; y++)
446             {
447               register const Quantum
448                 *magick_restrict p;
449 
450               register Quantum
451                 *magick_restrict q;
452 
453               register ssize_t
454                 x;
455 
456               if (count != (ssize_t) length)
457                 {
458                   status=MagickFalse;
459                   ThrowFileException(exception,CorruptImageError,
460                     "UnexpectedEndOfFile",image->filename);
461                   break;
462                 }
463               q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
464                 exception);
465               if (q == (Quantum *) NULL)
466                 break;
467               length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
468                 quantum_info,AlphaQuantum,pixels,exception);
469               if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
470                 break;
471               if (((y-image->extract_info.y) >= 0) &&
472                   ((y-image->extract_info.y) < (ssize_t) image->rows))
473                 {
474                   p=GetVirtualPixels(canvas_image,
475                     canvas_image->extract_info.x,0,canvas_image->columns,1,
476                     exception);
477                   q=GetAuthenticPixels(image,0,y-image->extract_info.y,
478                     image->columns,1,exception);
479                   if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
480                     break;
481                   for (x=0; x < (ssize_t) image->columns; x++)
482                   {
483                     SetPixelAlpha(image,GetPixelAlpha(canvas_image,p),q);
484                     p+=GetPixelChannels(canvas_image);
485                     q+=GetPixelChannels(image);
486                   }
487                   if (SyncAuthenticPixels(image,exception) == MagickFalse)
488                     break;
489                 }
490               pixels=(const unsigned char *) ReadBlobStream(image,length,
491                 GetQuantumPixels(quantum_info),&count);
492             }
493             if (image->previous == (Image *) NULL)
494               {
495                 status=SetImageProgress(image,LoadImageTag,5,6);
496                 if (status == MagickFalse)
497                   break;
498               }
499           }
500         if (image->previous == (Image *) NULL)
501           {
502             status=SetImageProgress(image,LoadImageTag,6,6);
503             if (status == MagickFalse)
504               break;
505           }
506         break;
507       }
508       case PartitionInterlace:
509       {
510         /*
511           Partition interlacing:  G..., G..., G...
512         */
513         AppendImageFormat("G",image->filename);
514         status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
515         if (status == MagickFalse)
516           break;
517         if (DiscardBlobBytes(image,(MagickSizeType) image->offset) == MagickFalse)
518           {
519             status=MagickFalse;
520             ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
521               image->filename);
522             break;
523           }
524         length=GetQuantumExtent(canvas_image,quantum_info,RedQuantum);
525         for (i=0; i < (ssize_t) scene; i++)
526         {
527           for (y=0; y < (ssize_t) image->extract_info.height; y++)
528           {
529             pixels=(const unsigned char *) ReadBlobStream(image,length,
530               GetQuantumPixels(quantum_info),&count);
531             if (count != (ssize_t) length)
532               break;
533           }
534           if (count != (ssize_t) length)
535             break;
536         }
537         pixels=(const unsigned char *) ReadBlobStream(image,length,
538           GetQuantumPixels(quantum_info),&count);
539         for (y=0; y < (ssize_t) image->extract_info.height; y++)
540         {
541           register const Quantum
542             *magick_restrict p;
543 
544           register Quantum
545             *magick_restrict q;
546 
547           register ssize_t
548             x;
549 
550           if (count != (ssize_t) length)
551             {
552               status=MagickFalse;
553               ThrowFileException(exception,CorruptImageError,
554                 "UnexpectedEndOfFile",image->filename);
555               break;
556             }
557           q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
558             exception);
559           if (q == (Quantum *) NULL)
560             break;
561           length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
562             quantum_info,RedQuantum,pixels,exception);
563           if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
564             break;
565           if (((y-image->extract_info.y) >= 0) &&
566               ((y-image->extract_info.y) < (ssize_t) image->rows))
567             {
568               p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,0,
569                 canvas_image->columns,1,exception);
570               q=GetAuthenticPixels(image,0,y-image->extract_info.y,
571                 image->columns,1,exception);
572               if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
573                 break;
574               for (x=0; x < (ssize_t) image->columns; x++)
575               {
576                 SetPixelRed(image,GetPixelRed(canvas_image,p),q);
577                 p+=GetPixelChannels(canvas_image);
578                 q+=GetPixelChannels(image);
579               }
580               if (SyncAuthenticPixels(image,exception) == MagickFalse)
581                 break;
582             }
583           pixels=(const unsigned char *) ReadBlobStream(image,length,
584             GetQuantumPixels(quantum_info),&count);
585         }
586         if (image->previous == (Image *) NULL)
587           {
588             status=SetImageProgress(image,LoadImageTag,1,5);
589             if (status == MagickFalse)
590               break;
591           }
592         (void) CloseBlob(image);
593         if (image->alpha_trait != UndefinedPixelTrait)
594           {
595             (void) CloseBlob(image);
596             AppendImageFormat("A",image->filename);
597             status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
598             if (status == MagickFalse)
599               break;
600             length=GetQuantumExtent(canvas_image,quantum_info,AlphaQuantum);
601             for (i=0; i < (ssize_t) scene; i++)
602             {
603               for (y=0; y < (ssize_t) image->extract_info.height; y++)
604               {
605                 pixels=(const unsigned char *) ReadBlobStream(image,length,
606                   GetQuantumPixels(quantum_info),&count);
607                 if (count != (ssize_t) length)
608                   break;
609               }
610               if (count != (ssize_t) length)
611                 break;
612             }
613             pixels=(const unsigned char *) ReadBlobStream(image,length,
614               GetQuantumPixels(quantum_info),&count);
615             for (y=0; y < (ssize_t) image->extract_info.height; y++)
616             {
617               register const Quantum
618                 *magick_restrict p;
619 
620               register Quantum
621                 *magick_restrict q;
622 
623               register ssize_t
624                 x;
625 
626               if (count != (ssize_t) length)
627                 {
628                   status=MagickFalse;
629                   ThrowFileException(exception,CorruptImageError,
630                     "UnexpectedEndOfFile",image->filename);
631                   break;
632                 }
633               q=GetAuthenticPixels(canvas_image,0,0,canvas_image->columns,1,
634                 exception);
635               if (q == (Quantum *) NULL)
636                 break;
637               length=ImportQuantumPixels(canvas_image,(CacheView *) NULL,
638                 quantum_info,BlueQuantum,pixels,exception);
639               if (SyncAuthenticPixels(canvas_image,exception) == MagickFalse)
640                 break;
641               if (((y-image->extract_info.y) >= 0) &&
642                   ((y-image->extract_info.y) < (ssize_t) image->rows))
643                 {
644                   p=GetVirtualPixels(canvas_image,canvas_image->extract_info.x,
645                     0,canvas_image->columns,1,exception);
646                   q=GetAuthenticPixels(image,0,y-image->extract_info.y,
647                     image->columns,1,exception);
648                   if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
649                     break;
650                   for (x=0; x < (ssize_t) image->columns; x++)
651                   {
652                     SetPixelAlpha(image,GetPixelAlpha(canvas_image,p),q);
653                     p+=GetPixelChannels(canvas_image);
654                     q+=GetPixelChannels(image);
655                   }
656                   if (SyncAuthenticPixels(image,exception) == MagickFalse)
657                     break;
658                }
659               pixels=(const unsigned char *) ReadBlobStream(image,length,
660                 GetQuantumPixels(quantum_info),&count);
661             }
662             if (image->previous == (Image *) NULL)
663               {
664                 status=SetImageProgress(image,LoadImageTag,4,5);
665                 if (status == MagickFalse)
666                   break;
667               }
668           }
669         (void) CloseBlob(image);
670         if (image->previous == (Image *) NULL)
671           {
672             status=SetImageProgress(image,LoadImageTag,5,5);
673             if (status == MagickFalse)
674               break;
675           }
676         break;
677       }
678     }
679     if (status == MagickFalse)
680       break;
681     SetQuantumImageType(image,quantum_type);
682     /*
683       Proceed to next image.
684     */
685     if (image_info->number_scenes != 0)
686       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
687         break;
688     if (count == (ssize_t) length)
689       {
690         /*
691           Allocate next image structure.
692         */
693         AcquireNextImage(image_info,image,exception);
694         if (GetNextImageInList(image) == (Image *) NULL)
695           {
696             status=MagickFalse;
697             break;
698           }
699         image=SyncNextImageInList(image);
700         status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
701           GetBlobSize(image));
702         if (status == MagickFalse)
703           break;
704       }
705     scene++;
706   } while (count == (ssize_t) length);
707   quantum_info=DestroyQuantumInfo(quantum_info);
708   canvas_image=DestroyImage(canvas_image);
709   (void) CloseBlob(image);
710   if (status == MagickFalse)
711     return(DestroyImageList(image));
712   return(GetFirstImageInList(image));
713 }
714 
715 /*
716 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
717 %                                                                             %
718 %                                                                             %
719 %                                                                             %
720 %   R e g i s t e r G R A Y I m a g e                                           %
721 %                                                                             %
722 %                                                                             %
723 %                                                                             %
724 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
725 %
726 %  RegisterGRAYImage() adds attributes for the GRAY image format to
727 %  the list of supported formats.  The attributes include the image format
728 %  tag, a method to read and/or write the format, whether the format
729 %  supports the saving of more than one frame to the same file or blob,
730 %  whether the format supports native in-memory I/O, and a brief
731 %  description of the format.
732 %
733 %  The format of the RegisterGRAYImage method is:
734 %
735 %      size_t RegisterGRAYImage(void)
736 %
737 */
RegisterGRAYImage(void)738 ModuleExport size_t RegisterGRAYImage(void)
739 {
740   MagickInfo
741     *entry;
742 
743   entry=AcquireMagickInfo("GRAY","GRAY","Raw gray samples");
744   entry->decoder=(DecodeImageHandler *) ReadGRAYImage;
745   entry->encoder=(EncodeImageHandler *) WriteGRAYImage;
746   entry->flags|=CoderRawSupportFlag;
747   entry->flags|=CoderEndianSupportFlag;
748   (void) RegisterMagickInfo(entry);
749   entry=AcquireMagickInfo("GRAY","GRAYA","Raw gray and alpha samples");
750   entry->decoder=(DecodeImageHandler *) ReadGRAYImage;
751   entry->encoder=(EncodeImageHandler *) WriteGRAYImage;
752   entry->flags|=CoderRawSupportFlag;
753   entry->flags|=CoderEndianSupportFlag;
754   (void) RegisterMagickInfo(entry);
755   return(MagickImageCoderSignature);
756 }
757 
758 /*
759 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
760 %                                                                             %
761 %                                                                             %
762 %                                                                             %
763 %   U n r e g i s t e r G R A Y I m a g e                                     %
764 %                                                                             %
765 %                                                                             %
766 %                                                                             %
767 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
768 %
769 %  UnregisterGRAYImage() removes format registrations made by the GRAY module
770 %  from the list of supported formats.
771 %
772 %  The format of the UnregisterGRAYImage method is:
773 %
774 %      UnregisterGRAYImage(void)
775 %
776 */
UnregisterGRAYImage(void)777 ModuleExport void UnregisterGRAYImage(void)
778 {
779   (void) UnregisterMagickInfo("GRAYA");
780   (void) UnregisterMagickInfo("GRAY");
781 }
782 
783 /*
784 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
785 %                                                                             %
786 %                                                                             %
787 %                                                                             %
788 %   W r i t e G R A Y I m a g e                                               %
789 %                                                                             %
790 %                                                                             %
791 %                                                                             %
792 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
793 %
794 %  WriteGRAYImage() writes an image to a file in the GRAY, GRAYAlpha, or GRAYO
795 %  rasterfile format.
796 %
797 %  The format of the WriteGRAYImage method is:
798 %
799 %      MagickBooleanType WriteGRAYImage(const ImageInfo *image_info,
800 %        Image *image,ExceptionInfo *exception)
801 %
802 %  A description of each parameter follows.
803 %
804 %    o image_info: the image info.
805 %
806 %    o image:  The image.
807 %
808 %    o exception: return any errors or warnings in this structure.
809 %
810 */
WriteGRAYImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)811 static MagickBooleanType WriteGRAYImage(const ImageInfo *image_info,
812   Image *image,ExceptionInfo *exception)
813 {
814   MagickBooleanType
815     status;
816 
817   MagickOffsetType
818     scene;
819 
820   QuantumInfo
821     *quantum_info;
822 
823   QuantumType
824     quantum_type;
825 
826   size_t
827     imageListLength,
828     length;
829 
830   ssize_t
831     count,
832     y;
833 
834   unsigned char
835     *pixels;
836 
837   /*
838     Allocate memory for pixels.
839   */
840   assert(image_info != (const ImageInfo *) NULL);
841   assert(image_info->signature == MagickCoreSignature);
842   assert(image != (Image *) NULL);
843   assert(image->signature == MagickCoreSignature);
844   if (image->debug != MagickFalse)
845     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
846   if (image_info->interlace != PartitionInterlace)
847     {
848       /*
849         Open output image file.
850       */
851       status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
852       if (status == MagickFalse)
853         return(status);
854     }
855   quantum_type=GrayQuantum;
856   if (LocaleCompare(image_info->magick,"GRAYA") == 0)
857     quantum_type=GrayAlphaQuantum;
858   scene=0;
859   imageListLength=GetImageListLength(image);
860   do
861   {
862     /*
863       Convert MIFF to GRAY raster pixels.
864     */
865     (void) TransformImageColorspace(image,GRAYColorspace,exception);
866     if ((LocaleCompare(image_info->magick,"GRAYA") == 0) &&
867         (image->alpha_trait == UndefinedPixelTrait))
868       (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
869     quantum_info=AcquireQuantumInfo(image_info,image);
870     if (quantum_info == (QuantumInfo *) NULL)
871       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
872     pixels=(unsigned char *) GetQuantumPixels(quantum_info);
873     switch (image_info->interlace)
874     {
875       case NoInterlace:
876       default:
877       {
878         /*
879           No interlacing:  GGG...
880         */
881         for (y=0; y < (ssize_t) image->rows; y++)
882         {
883           register const Quantum
884             *magick_restrict p;
885 
886           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
887           if (p == (const Quantum *) NULL)
888             break;
889           length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
890             quantum_type,pixels,exception);
891           count=WriteBlob(image,length,pixels);
892           if (count != (ssize_t) length)
893             break;
894           if (image->previous == (Image *) NULL)
895             {
896               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
897                 image->rows);
898               if (status == MagickFalse)
899                 break;
900             }
901         }
902         break;
903       }
904       case LineInterlace:
905       {
906         /*
907           Line interlacing:  G...G...G...
908         */
909         for (y=0; y < (ssize_t) image->rows; y++)
910         {
911           register const Quantum
912             *magick_restrict p;
913 
914           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
915           if (p == (const Quantum *) NULL)
916             break;
917           length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
918             GrayQuantum,pixels,exception);
919           count=WriteBlob(image,length,pixels);
920           if (count != (ssize_t) length)
921             break;
922           if (quantum_type == GrayAlphaQuantum)
923             {
924               length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
925                 AlphaQuantum,pixels,exception);
926               count=WriteBlob(image,length,pixels);
927               if (count != (ssize_t) length)
928                 break;
929             }
930           if (image->previous == (Image *) NULL)
931             {
932               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
933                 image->rows);
934               if (status == MagickFalse)
935                 break;
936             }
937         }
938         break;
939       }
940       case PlaneInterlace:
941       {
942         /*
943           Plane interlacing:  G...G...G...
944         */
945         for (y=0; y < (ssize_t) image->rows; y++)
946         {
947           register const Quantum
948             *magick_restrict p;
949 
950           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
951           if (p == (const Quantum *) NULL)
952             break;
953           length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
954             GrayQuantum,pixels,exception);
955           count=WriteBlob(image,length,pixels);
956           if (count != (ssize_t) length)
957             break;
958         }
959         if (image->previous == (Image *) NULL)
960           {
961             status=SetImageProgress(image,SaveImageTag,1,6);
962             if (status == MagickFalse)
963               break;
964           }
965         if (quantum_type == GrayAlphaQuantum)
966           {
967             for (y=0; y < (ssize_t) image->rows; y++)
968             {
969               register const Quantum
970                 *magick_restrict p;
971 
972               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
973               if (p == (const Quantum *) NULL)
974                 break;
975               length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
976                 AlphaQuantum,pixels,exception);
977               count=WriteBlob(image,length,pixels);
978               if (count != (ssize_t) length)
979               break;
980             }
981             if (image->previous == (Image *) NULL)
982               {
983                 status=SetImageProgress(image,SaveImageTag,5,6);
984                 if (status == MagickFalse)
985                   break;
986               }
987           }
988         if (image_info->interlace == PartitionInterlace)
989           (void) CopyMagickString(image->filename,image_info->filename,
990             MagickPathExtent);
991         if (image->previous == (Image *) NULL)
992           {
993             status=SetImageProgress(image,SaveImageTag,6,6);
994             if (status == MagickFalse)
995               break;
996           }
997         break;
998       }
999       case PartitionInterlace:
1000       {
1001         /*
1002           Partition interlacing:  G..., G..., G...
1003         */
1004         AppendImageFormat("G",image->filename);
1005         status=OpenBlob(image_info,image,scene == 0 ? WriteBinaryBlobMode :
1006           AppendBinaryBlobMode,exception);
1007         if (status == MagickFalse)
1008           return(status);
1009         for (y=0; y < (ssize_t) image->rows; y++)
1010         {
1011           register const Quantum
1012             *magick_restrict p;
1013 
1014           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1015           if (p == (const Quantum *) NULL)
1016             break;
1017           length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1018             RedQuantum,pixels,exception);
1019           count=WriteBlob(image,length,pixels);
1020           if (count != (ssize_t) length)
1021             break;
1022         }
1023         if (image->previous == (Image *) NULL)
1024           {
1025             status=SetImageProgress(image,SaveImageTag,1,6);
1026             if (status == MagickFalse)
1027               break;
1028           }
1029         (void) CloseBlob(image);
1030         if (quantum_type == GrayAlphaQuantum)
1031           {
1032             (void) CloseBlob(image);
1033             AppendImageFormat("A",image->filename);
1034             status=OpenBlob(image_info,image,scene == 0 ? WriteBinaryBlobMode :
1035               AppendBinaryBlobMode,exception);
1036             if (status == MagickFalse)
1037               return(status);
1038             for (y=0; y < (ssize_t) image->rows; y++)
1039             {
1040               register const Quantum
1041                 *magick_restrict p;
1042 
1043               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1044               if (p == (const Quantum *) NULL)
1045                 break;
1046               length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1047                 AlphaQuantum,pixels,exception);
1048               count=WriteBlob(image,length,pixels);
1049               if (count != (ssize_t) length)
1050                 break;
1051             }
1052             if (image->previous == (Image *) NULL)
1053               {
1054                 status=SetImageProgress(image,SaveImageTag,5,6);
1055                 if (status == MagickFalse)
1056                   break;
1057               }
1058           }
1059         (void) CloseBlob(image);
1060         (void) CopyMagickString(image->filename,image_info->filename,
1061           MagickPathExtent);
1062         if (image->previous == (Image *) NULL)
1063           {
1064             status=SetImageProgress(image,SaveImageTag,6,6);
1065             if (status == MagickFalse)
1066               break;
1067           }
1068         break;
1069       }
1070     }
1071     quantum_info=DestroyQuantumInfo(quantum_info);
1072     if (GetNextImageInList(image) == (Image *) NULL)
1073       break;
1074     image=SyncNextImageInList(image);
1075     status=SetImageProgress(image,SaveImagesTag,scene++,imageListLength);
1076     if (status == MagickFalse)
1077       break;
1078   } while (image_info->adjoin != MagickFalse);
1079   (void) CloseBlob(image);
1080   return(MagickTrue);
1081 }
1082