blob: 3395e0b924eed7be1acf15977e2c9923f32b66c6 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
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% John Cristy %
17% July 1992 %
18% %
19% %
cristy7e41fe82010-12-04 23:12:08 +000020% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% 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% http://www.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*/
cristy4c08aed2011-07-01 19:47:50 +000042#include "MagickCore/studio.h"
43#include "MagickCore/blob.h"
44#include "MagickCore/blob-private.h"
45#include "MagickCore/cache.h"
46#include "MagickCore/color-private.h"
47#include "MagickCore/colormap.h"
48#include "MagickCore/colorspace.h"
cristy510d06a2011-07-06 23:43:54 +000049#include "MagickCore/colorspace-private.h"
cristy4c08aed2011-07-01 19:47:50 +000050#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/string_.h"
63#include "MagickCore/module.h"
cristy3ed852e2009-09-05 21:47:34 +000064
65/*
66 Forward declarations.
67*/
68static MagickBooleanType
cristy1e178e72011-08-28 19:44:34 +000069 WriteMONOImage(const ImageInfo *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +000070
71/*
72%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
73% %
74% %
75% %
76% R e a d M O N O I m a g e %
77% %
78% %
79% %
80%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
81%
82% ReadMONOImage() reads an image of raw bites in LSB order and returns
83% it. It allocates the memory necessary for the new Image structure and
84% returns a pointer to the new image.
85%
86% The format of the ReadMONOImage method is:
87%
88% Image *ReadMONOImage(const ImageInfo *image_info,
89% ExceptionInfo *exception)
90%
91% A description of each parameter follows:
92%
93% o image_info: the image info.
94%
95% o exception: return any errors or warnings in this structure.
96%
97*/
98static Image *ReadMONOImage(const ImageInfo *image_info,
99 ExceptionInfo *exception)
100{
101 Image
102 *image;
103
cristy3ed852e2009-09-05 21:47:34 +0000104 MagickBooleanType
105 status;
106
cristy4c08aed2011-07-01 19:47:50 +0000107 register Quantum
cristy3ed852e2009-09-05 21:47:34 +0000108 *q;
109
cristyaff6d802011-04-26 01:46:31 +0000110 register ssize_t
111 x;
112
cristybb503372010-05-27 20:51:26 +0000113 size_t
cristy3ed852e2009-09-05 21:47:34 +0000114 bit,
115 byte;
116
cristyaff6d802011-04-26 01:46:31 +0000117 ssize_t
118 y;
119
cristy3ed852e2009-09-05 21:47:34 +0000120 /*
121 Open image file.
122 */
123 assert(image_info != (const ImageInfo *) NULL);
124 assert(image_info->signature == MagickSignature);
125 if (image_info->debug != MagickFalse)
126 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
127 image_info->filename);
128 assert(exception != (ExceptionInfo *) NULL);
129 assert(exception->signature == MagickSignature);
130 image=AcquireImage(image_info);
131 if ((image->columns == 0) || (image->rows == 0))
132 ThrowReaderException(OptionError,"MustSpecifyImageSize");
133 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
134 if (status == MagickFalse)
135 {
136 image=DestroyImageList(image);
137 return((Image *) NULL);
138 }
cristyd4297022010-09-16 22:59:09 +0000139 if (DiscardBlobBytes(image,image->offset) == MagickFalse)
140 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
141 image->filename);
cristy3ed852e2009-09-05 21:47:34 +0000142 /*
143 Initialize image colormap.
144 */
145 image->depth=1;
146 if (AcquireImageColormap(image,2) == MagickFalse)
147 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
148 if (image_info->ping != MagickFalse)
149 {
150 (void) CloseBlob(image);
151 return(GetFirstImageInList(image));
152 }
153 /*
154 Convert bi-level image to pixel packets.
155 */
cristybb503372010-05-27 20:51:26 +0000156 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000157 {
158 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000159 if (q == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000160 break;
cristy3ed852e2009-09-05 21:47:34 +0000161 bit=0;
162 byte=0;
cristybb503372010-05-27 20:51:26 +0000163 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000164 {
165 if (bit == 0)
cristybb503372010-05-27 20:51:26 +0000166 byte=(size_t) ReadBlobByte(image);
cristy3ed852e2009-09-05 21:47:34 +0000167 if (image_info->endian == LSBEndian)
cristy4c08aed2011-07-01 19:47:50 +0000168 SetPixelIndex(image,((byte & 0x01) != 0) ? 0x00 : 0x01,q);
cristy3ed852e2009-09-05 21:47:34 +0000169 else
cristy4c08aed2011-07-01 19:47:50 +0000170 SetPixelIndex(image,((byte & 0x01) != 0) ? 0x01 : 0x00,q);
cristy3ed852e2009-09-05 21:47:34 +0000171 bit++;
172 if (bit == 8)
173 bit=0;
174 byte>>=1;
cristyed231572011-07-14 02:18:59 +0000175 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000176 }
177 if (SyncAuthenticPixels(image,exception) == MagickFalse)
178 break;
cristycee97112010-05-28 00:44:52 +0000179 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
cristy4c08aed2011-07-01 19:47:50 +0000180 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000181 if (status == MagickFalse)
182 break;
183 }
184 (void) SyncImage(image);
185 if (EOFBlob(image) != MagickFalse)
186 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
187 image->filename);
188 (void) CloseBlob(image);
189 return(GetFirstImageInList(image));
190}
191
192/*
193%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
194% %
195% %
196% %
197% R e g i s t e r M O N O I m a g e %
198% %
199% %
200% %
201%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
202%
203% RegisterMONOImage() adds attributes for the MONO image format to
204% the list of supported formats. The attributes include the image format
205% tag, a method to read and/or write the format, whether the format
206% supports the saving of more than one frame to the same file or blob,
207% whether the format supports native in-memory I/O, and a brief
208% description of the format.
209%
210% The format of the RegisterMONOImage method is:
211%
cristybb503372010-05-27 20:51:26 +0000212% size_t RegisterMONOImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000213%
214*/
cristybb503372010-05-27 20:51:26 +0000215ModuleExport size_t RegisterMONOImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000216{
217 MagickInfo
218 *entry;
219
220 entry=SetMagickInfo("MONO");
221 entry->decoder=(DecodeImageHandler *) ReadMONOImage;
222 entry->encoder=(EncodeImageHandler *) WriteMONOImage;
223 entry->raw=MagickTrue;
224 entry->endian_support=MagickTrue;
225 entry->adjoin=MagickFalse;
226 entry->description=ConstantString("Raw bi-level bitmap");
227 entry->module=ConstantString("MONO");
228 (void) RegisterMagickInfo(entry);
229 return(MagickImageCoderSignature);
230}
231
232/*
233%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
234% %
235% %
236% %
237% U n r e g i s t e r M O N O I m a g e %
238% %
239% %
240% %
241%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
242%
243% UnregisterMONOImage() removes format registrations made by the
244% MONO module from the list of supported formats.
245%
246% The format of the UnregisterMONOImage method is:
247%
248% UnregisterMONOImage(void)
249%
250*/
251ModuleExport void UnregisterMONOImage(void)
252{
253 (void) UnregisterMagickInfo("MONO");
254}
255
256/*
257%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
258% %
259% %
260% %
261% W r i t e M O N O I m a g e %
262% %
263% %
264% %
265%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
266%
267% WriteMONOImage() writes an image of raw bits in LSB order to a file.
268%
269% The format of the WriteMONOImage method is:
270%
271% MagickBooleanType WriteMONOImage(const ImageInfo *image_info,
cristy1e178e72011-08-28 19:44:34 +0000272% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000273%
274% A description of each parameter follows.
275%
276% o image_info: the image info.
277%
278% o image: The image.
279%
cristy1e178e72011-08-28 19:44:34 +0000280% o exception: return any errors or warnings in this structure.
281%
cristy3ed852e2009-09-05 21:47:34 +0000282*/
283static MagickBooleanType WriteMONOImage(const ImageInfo *image_info,
cristy1e178e72011-08-28 19:44:34 +0000284 Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000285{
cristy3ed852e2009-09-05 21:47:34 +0000286 MagickBooleanType
287 status;
288
cristy4c08aed2011-07-01 19:47:50 +0000289 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000290 *p;
291
cristybb503372010-05-27 20:51:26 +0000292 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000293 x;
294
cristybb503372010-05-27 20:51:26 +0000295 size_t
cristy3ed852e2009-09-05 21:47:34 +0000296 bit,
297 byte;
298
cristyaff6d802011-04-26 01:46:31 +0000299 ssize_t
300 y;
301
cristy3ed852e2009-09-05 21:47:34 +0000302 /*
303 Open output image file.
304 */
305 assert(image_info != (const ImageInfo *) NULL);
306 assert(image_info->signature == MagickSignature);
307 assert(image != (Image *) NULL);
308 assert(image->signature == MagickSignature);
309 if (image->debug != MagickFalse)
310 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy1e178e72011-08-28 19:44:34 +0000311 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000312 if (status == MagickFalse)
313 return(status);
cristy510d06a2011-07-06 23:43:54 +0000314 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000315 (void) TransformImageColorspace(image,RGBColorspace);
316 /*
317 Convert image to a bi-level image.
318 */
319 (void) SetImageType(image,BilevelType);
cristybb503372010-05-27 20:51:26 +0000320 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000321 {
cristy1e178e72011-08-28 19:44:34 +0000322 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000323 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000324 break;
cristy3ed852e2009-09-05 21:47:34 +0000325 bit=0;
326 byte=0;
cristybb503372010-05-27 20:51:26 +0000327 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000328 {
329 byte>>=1;
330 if (image->endian == LSBEndian)
331 {
cristy4c08aed2011-07-01 19:47:50 +0000332 if (GetPixelIntensity(image,p) < ((Quantum) QuantumRange/2.0))
cristy3ed852e2009-09-05 21:47:34 +0000333 byte|=0x80;
334 }
335 else
cristy4c08aed2011-07-01 19:47:50 +0000336 if (GetPixelIntensity(image,p) >= ((Quantum) QuantumRange/2.0))
cristy3ed852e2009-09-05 21:47:34 +0000337 byte|=0x80;
338 bit++;
339 if (bit == 8)
340 {
341 (void) WriteBlobByte(image,(unsigned char) byte);
342 bit=0;
343 byte=0;
344 }
cristyed231572011-07-14 02:18:59 +0000345 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000346 }
347 if (bit != 0)
348 (void) WriteBlobByte(image,(unsigned char) (byte >> (8-bit)));
cristycee97112010-05-28 00:44:52 +0000349 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristyaff6d802011-04-26 01:46:31 +0000350 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000351 if (status == MagickFalse)
352 break;
353 }
354 (void) CloseBlob(image);
355 return(MagickTrue);
356}