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