1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % M M OOO N N OOO %
7 % MM MM O O NN N O O %
8 % M M M O O N N N O O %
9 % M M O O N NN O O %
10 % M M OOO N N OOO %
11 % %
12 % %
13 % Read/Write Raw Bi-Level Bitmap 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/attribute.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/color-private.h"
48 #include "MagickCore/colormap.h"
49 #include "MagickCore/colorspace.h"
50 #include "MagickCore/colorspace-private.h"
51 #include "MagickCore/exception.h"
52 #include "MagickCore/exception-private.h"
53 #include "MagickCore/image.h"
54 #include "MagickCore/image-private.h"
55 #include "MagickCore/list.h"
56 #include "MagickCore/magick.h"
57 #include "MagickCore/memory_.h"
58 #include "MagickCore/monitor.h"
59 #include "MagickCore/monitor-private.h"
60 #include "MagickCore/pixel-accessor.h"
61 #include "MagickCore/quantum-private.h"
62 #include "MagickCore/static.h"
63 #include "MagickCore/string_.h"
64 #include "MagickCore/module.h"
65
66 /*
67 Forward declarations.
68 */
69 static MagickBooleanType
70 WriteMONOImage(const ImageInfo *,Image *,ExceptionInfo *);
71
72 /*
73 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
74 % %
75 % %
76 % %
77 % R e a d M O N O I m a g e %
78 % %
79 % %
80 % %
81 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
82 %
83 % ReadMONOImage() reads an image of raw bites in LSB order and returns
84 % it. It allocates the memory necessary for the new Image structure and
85 % returns a pointer to the new image.
86 %
87 % The format of the ReadMONOImage method is:
88 %
89 % Image *ReadMONOImage(const ImageInfo *image_info,
90 % ExceptionInfo *exception)
91 %
92 % A description of each parameter follows:
93 %
94 % o image_info: the image info.
95 %
96 % o exception: return any errors or warnings in this structure.
97 %
98 */
ReadMONOImage(const ImageInfo * image_info,ExceptionInfo * exception)99 static Image *ReadMONOImage(const ImageInfo *image_info,
100 ExceptionInfo *exception)
101 {
102 Image
103 *image;
104
105 MagickBooleanType
106 status;
107
108 register Quantum
109 *q;
110
111 register ssize_t
112 x;
113
114 size_t
115 bit,
116 byte;
117
118 ssize_t
119 y;
120
121 /*
122 Open image file.
123 */
124 assert(image_info != (const ImageInfo *) NULL);
125 assert(image_info->signature == MagickCoreSignature);
126 if (image_info->debug != MagickFalse)
127 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
128 image_info->filename);
129 assert(exception != (ExceptionInfo *) NULL);
130 assert(exception->signature == MagickCoreSignature);
131 image=AcquireImage(image_info,exception);
132 if ((image->columns == 0) || (image->rows == 0))
133 ThrowReaderException(OptionError,"MustSpecifyImageSize");
134 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
135 if (status == MagickFalse)
136 {
137 image=DestroyImageList(image);
138 return((Image *) NULL);
139 }
140 if (DiscardBlobBytes(image,image->offset) == MagickFalse)
141 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
142 image->filename);
143 /*
144 Initialize image colormap.
145 */
146 image->depth=1;
147 if (AcquireImageColormap(image,2,exception) == MagickFalse)
148 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
149 if (image_info->ping != MagickFalse)
150 {
151 (void) CloseBlob(image);
152 return(GetFirstImageInList(image));
153 }
154 status=SetImageExtent(image,image->columns,image->rows,exception);
155 if (status == MagickFalse)
156 return(DestroyImageList(image));
157 /*
158 Convert bi-level image to pixel packets.
159 */
160 for (y=0; y < (ssize_t) image->rows; y++)
161 {
162 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
163 if (q == (Quantum *) NULL)
164 break;
165 bit=0;
166 byte=0;
167 for (x=0; x < (ssize_t) image->columns; x++)
168 {
169 if (bit == 0)
170 byte=(size_t) ReadBlobByte(image);
171 if (image_info->endian == LSBEndian)
172 SetPixelIndex(image,((byte & 0x01) != 0) ? 0x00 : 0x01,q);
173 else
174 SetPixelIndex(image,((byte & 0x01) != 0) ? 0x01 : 0x00,q);
175 bit++;
176 if (bit == 8)
177 bit=0;
178 byte>>=1;
179 q+=GetPixelChannels(image);
180 }
181 if (SyncAuthenticPixels(image,exception) == MagickFalse)
182 break;
183 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
184 image->rows);
185 if (status == MagickFalse)
186 break;
187 }
188 (void) SyncImage(image,exception);
189 if (EOFBlob(image) != MagickFalse)
190 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
191 image->filename);
192 (void) CloseBlob(image);
193 return(GetFirstImageInList(image));
194 }
195
196 /*
197 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
198 % %
199 % %
200 % %
201 % R e g i s t e r M O N O I m a g e %
202 % %
203 % %
204 % %
205 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
206 %
207 % RegisterMONOImage() adds attributes for the MONO image format to
208 % the list of supported formats. The attributes include the image format
209 % tag, a method to read and/or write the format, whether the format
210 % supports the saving of more than one frame to the same file or blob,
211 % whether the format supports native in-memory I/O, and a brief
212 % description of the format.
213 %
214 % The format of the RegisterMONOImage method is:
215 %
216 % size_t RegisterMONOImage(void)
217 %
218 */
RegisterMONOImage(void)219 ModuleExport size_t RegisterMONOImage(void)
220 {
221 MagickInfo
222 *entry;
223
224 entry=AcquireMagickInfo("MONO","MONO","Raw bi-level bitmap");
225 entry->decoder=(DecodeImageHandler *) ReadMONOImage;
226 entry->encoder=(EncodeImageHandler *) WriteMONOImage;
227 entry->flags|=CoderRawSupportFlag;
228 entry->flags|=CoderEndianSupportFlag;
229 entry->flags^=CoderAdjoinFlag;
230 (void) RegisterMagickInfo(entry);
231 return(MagickImageCoderSignature);
232 }
233
234 /*
235 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
236 % %
237 % %
238 % %
239 % U n r e g i s t e r M O N O I m a g e %
240 % %
241 % %
242 % %
243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
244 %
245 % UnregisterMONOImage() removes format registrations made by the
246 % MONO module from the list of supported formats.
247 %
248 % The format of the UnregisterMONOImage method is:
249 %
250 % UnregisterMONOImage(void)
251 %
252 */
UnregisterMONOImage(void)253 ModuleExport void UnregisterMONOImage(void)
254 {
255 (void) UnregisterMagickInfo("MONO");
256 }
257
258 /*
259 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
260 % %
261 % %
262 % %
263 % W r i t e M O N O I m a g e %
264 % %
265 % %
266 % %
267 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
268 %
269 % WriteMONOImage() writes an image of raw bits in LSB order to a file.
270 %
271 % The format of the WriteMONOImage method is:
272 %
273 % MagickBooleanType WriteMONOImage(const ImageInfo *image_info,
274 % Image *image,ExceptionInfo *exception)
275 %
276 % A description of each parameter follows.
277 %
278 % o image_info: the image info.
279 %
280 % o image: The image.
281 %
282 % o exception: return any errors or warnings in this structure.
283 %
284 */
WriteMONOImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)285 static MagickBooleanType WriteMONOImage(const ImageInfo *image_info,
286 Image *image,ExceptionInfo *exception)
287 {
288 MagickBooleanType
289 status;
290
291 register const Quantum
292 *p;
293
294 register ssize_t
295 x;
296
297 size_t
298 bit,
299 byte;
300
301 ssize_t
302 y;
303
304 /*
305 Open output image file.
306 */
307 assert(image_info != (const ImageInfo *) NULL);
308 assert(image_info->signature == MagickCoreSignature);
309 assert(image != (Image *) NULL);
310 assert(image->signature == MagickCoreSignature);
311 if (image->debug != MagickFalse)
312 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
313 assert(exception != (ExceptionInfo *) NULL);
314 assert(exception->signature == MagickCoreSignature);
315 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
316 if (status == MagickFalse)
317 return(status);
318 (void) TransformImageColorspace(image,sRGBColorspace,exception);
319 /*
320 Convert image to a bi-level image.
321 */
322 (void) SetImageType(image,BilevelType,exception);
323 for (y=0; y < (ssize_t) image->rows; y++)
324 {
325 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
326 if (p == (const Quantum *) NULL)
327 break;
328 bit=0;
329 byte=0;
330 for (x=0; x < (ssize_t) image->columns; x++)
331 {
332 byte>>=1;
333 if (image->endian == LSBEndian)
334 {
335 if (GetPixelLuma(image,p) < (QuantumRange/2.0))
336 byte|=0x80;
337 }
338 else
339 if (GetPixelLuma(image,p) >= (QuantumRange/2.0))
340 byte|=0x80;
341 bit++;
342 if (bit == 8)
343 {
344 (void) WriteBlobByte(image,(unsigned char) byte);
345 bit=0;
346 byte=0;
347 }
348 p+=GetPixelChannels(image);
349 }
350 if (bit != 0)
351 (void) WriteBlobByte(image,(unsigned char) (byte >> (8-bit)));
352 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
353 image->rows);
354 if (status == MagickFalse)
355 break;
356 }
357 (void) CloseBlob(image);
358 return(MagickTrue);
359 }
360