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