blob: e1ee647475ff388e996eceeeb3f54f72f6d2b09b [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);
cristy9950d572011-10-01 18:22:35 +0000130 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000131 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;
cristy018f07f2011-09-04 21:15:19 +0000146 if (AcquireImageColormap(image,2,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000147 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);
cristyacd2ed22011-08-30 01:44:23 +0000159 if (q == (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 }
cristyea1a8aa2011-10-20 13:24:06 +0000184 (void) SyncImage(image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000185 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);
cristy3a37efd2011-08-28 20:31:03 +0000311 assert(exception != (ExceptionInfo *) NULL);
312 assert(exception->signature == MagickSignature);
cristy1e178e72011-08-28 19:44:34 +0000313 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000314 if (status == MagickFalse)
315 return(status);
cristy510d06a2011-07-06 23:43:54 +0000316 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristye941a752011-10-15 01:52:48 +0000317 (void) TransformImageColorspace(image,RGBColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +0000318 /*
319 Convert image to a bi-level image.
320 */
cristy018f07f2011-09-04 21:15:19 +0000321 (void) SetImageType(image,BilevelType,exception);
cristybb503372010-05-27 20:51:26 +0000322 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000323 {
cristy1e178e72011-08-28 19:44:34 +0000324 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000325 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000326 break;
cristy3ed852e2009-09-05 21:47:34 +0000327 bit=0;
328 byte=0;
cristybb503372010-05-27 20:51:26 +0000329 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000330 {
331 byte>>=1;
332 if (image->endian == LSBEndian)
333 {
cristy4c08aed2011-07-01 19:47:50 +0000334 if (GetPixelIntensity(image,p) < ((Quantum) QuantumRange/2.0))
cristy3ed852e2009-09-05 21:47:34 +0000335 byte|=0x80;
336 }
337 else
cristy4c08aed2011-07-01 19:47:50 +0000338 if (GetPixelIntensity(image,p) >= ((Quantum) QuantumRange/2.0))
cristy3ed852e2009-09-05 21:47:34 +0000339 byte|=0x80;
340 bit++;
341 if (bit == 8)
342 {
343 (void) WriteBlobByte(image,(unsigned char) byte);
344 bit=0;
345 byte=0;
346 }
cristyed231572011-07-14 02:18:59 +0000347 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000348 }
349 if (bit != 0)
350 (void) WriteBlobByte(image,(unsigned char) (byte >> (8-bit)));
cristycee97112010-05-28 00:44:52 +0000351 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristyaff6d802011-04-26 01:46:31 +0000352 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000353 if (status == MagickFalse)
354 break;
355 }
356 (void) CloseBlob(image);
357 return(MagickTrue);
358}