blob: 12366de20118878cbee19e97454f7dc8c454ef5d [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% W W BBBB M M PPPP %
7% W W B B MM MM P P %
8% W W W BBBB M M M PPPP %
9% WW WW B B M M P %
10% W W BBBB M M P %
11% %
12% %
13% Read/Write Wireless Bitmap (level 0) Image Format %
14% %
15% Software Design %
16% John Cristy %
17% January 2000 %
18% %
19% %
cristy16af1cb2009-12-11 21:38:29 +000020% Copyright 1999-2010 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 Include declarations.
40*/
41#include "magick/studio.h"
42#include "magick/blob.h"
43#include "magick/blob-private.h"
44#include "magick/cache.h"
45#include "magick/color-private.h"
cristye7e40552010-04-24 21:34:22 +000046#include "magick/colormap.h"
cristy3ed852e2009-09-05 21:47:34 +000047#include "magick/colorspace.h"
48#include "magick/exception.h"
49#include "magick/exception-private.h"
50#include "magick/image.h"
51#include "magick/image-private.h"
52#include "magick/list.h"
53#include "magick/magick.h"
54#include "magick/memory_.h"
55#include "magick/monitor.h"
56#include "magick/monitor-private.h"
57#include "magick/quantum-private.h"
58#include "magick/static.h"
59#include "magick/string_.h"
60#include "magick/module.h"
61
62/*
63 Forward declarations.
64*/
65static MagickBooleanType
66 WriteWBMPImage(const ImageInfo *,Image *);
67
68/*
69%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
70% %
71% %
72% %
73% R e a d W B M P I m a g e %
74% %
75% %
76% %
77%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
78%
79% ReadWBMPImage() reads a WBMP (level 0) image file and returns it. It
80% allocates the memory necessary for the new Image structure and returns a
81% pointer to the new image.
82%
83% ReadWBMPImage was contributed by Milan Votava <votava@mageo.cz>.
84%
85% The format of the ReadWBMPImage method is:
86%
87% Image *ReadWBMPImage(const ImageInfo *image_info,
88% ExceptionInfo *exception)
89%
90% A description of each parameter follows:
91%
92% o image_info: the image info.
93%
94% o exception: return any errors or warnings in this structure.
95%
96*/
97
cristybb503372010-05-27 20:51:26 +000098static MagickBooleanType WBMPReadInteger(Image *image,size_t *value)
cristy3ed852e2009-09-05 21:47:34 +000099{
100 int
101 byte;
102
103 *value=0;
104 do
105 {
106 byte=ReadBlobByte(image);
107 if (byte == EOF)
108 return(MagickFalse);
109 *value<<=7;
110 *value|=(unsigned int) (byte & 0x7f);
111 } while (byte & 0x80);
112 return(MagickTrue);
113}
114
115static Image *ReadWBMPImage(const ImageInfo *image_info,
116 ExceptionInfo *exception)
117{
118 Image
119 *image;
120
121 int
122 byte;
123
cristybb503372010-05-27 20:51:26 +0000124 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000125 y;
126
127 MagickBooleanType
128 status;
129
130 register IndexPacket
131 *indexes;
132
cristybb503372010-05-27 20:51:26 +0000133 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000134 x;
135
136 register PixelPacket
137 *q;
138
cristybb503372010-05-27 20:51:26 +0000139 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000140 i;
141
142 unsigned char
143 bit;
144
145 unsigned short
146 header;
147
148 /*
149 Open image file.
150 */
151 assert(image_info != (const ImageInfo *) NULL);
152 assert(image_info->signature == MagickSignature);
153 if (image_info->debug != MagickFalse)
154 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
155 image_info->filename);
156 assert(exception != (ExceptionInfo *) NULL);
157 assert(exception->signature == MagickSignature);
158 image=AcquireImage(image_info);
159 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
160 if (status == MagickFalse)
161 {
162 image=DestroyImageList(image);
163 return((Image *) NULL);
164 }
165 if (ReadBlob(image,2,(unsigned char *) &header) == 0)
166 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
167 if (header != 0)
168 ThrowReaderException(CoderError,"OnlyLevelZerofilesSupported");
169 /*
170 Initialize image structure.
171 */
172 if (WBMPReadInteger(image,&image->columns) == MagickFalse)
173 ThrowReaderException(CorruptImageError,"CorruptWBMPimage");
174 if (WBMPReadInteger(image,&image->rows) == MagickFalse)
175 ThrowReaderException(CorruptImageError,"CorruptWBMPimage");
176 if ((image->columns == 0) || (image->rows == 0))
177 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
178 for (i=0; i < image->offset; i++)
179 if (ReadBlobByte(image) == EOF)
180 {
181 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
182 image->filename);
183 break;
184 }
185 if (AcquireImageColormap(image,2) == MagickFalse)
186 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
187 if (image_info->ping != MagickFalse)
188 {
189 (void) CloseBlob(image);
190 return(GetFirstImageInList(image));
191 }
192 /*
193 Convert bi-level image to pixel packets.
194 */
cristybb503372010-05-27 20:51:26 +0000195 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000196 {
197 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
198 if (q == (PixelPacket *) NULL)
199 break;
200 indexes=GetAuthenticIndexQueue(image);
201 bit=0;
202 byte=0;
cristybb503372010-05-27 20:51:26 +0000203 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000204 {
205 if (bit == 0)
206 {
207 byte=ReadBlobByte(image);
208 if (byte == EOF)
209 ThrowReaderException(CorruptImageError,"CorruptImage");
210 }
211 indexes[x]=(IndexPacket) ((byte & (0x01 << (7-bit))) ? 1 : 0);
212 bit++;
213 if (bit == 8)
214 bit=0;
215 }
216 if (SyncAuthenticPixels(image,exception) == MagickFalse)
217 break;
cristycee97112010-05-28 00:44:52 +0000218 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
219 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000220 if (status == MagickFalse)
221 break;
222 }
223 (void) SyncImage(image);
224 if (EOFBlob(image) != MagickFalse)
225 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
226 image->filename);
227 (void) CloseBlob(image);
228 return(GetFirstImageInList(image));
229}
230
231/*
232%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
233% %
234% %
235% %
236% R e g i s t e r W B M P I m a g e %
237% %
238% %
239% %
240%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
241%
242% RegisterWBMPImage() adds attributes for the WBMP image format to
243% the list of supported formats. The attributes include the image format
244% tag, a method to read and/or write the format, whether the format
245% supports the saving of more than one frame to the same file or blob,
246% whether the format supports native in-memory I/O, and a brief
247% description of the format.
248%
249% The format of the RegisterWBMPImage method is:
250%
cristybb503372010-05-27 20:51:26 +0000251% size_t RegisterWBMPImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000252%
253*/
cristybb503372010-05-27 20:51:26 +0000254ModuleExport size_t RegisterWBMPImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000255{
256 MagickInfo
257 *entry;
258
259 entry=SetMagickInfo("WBMP");
260 entry->decoder=(DecodeImageHandler *) ReadWBMPImage;
261 entry->encoder=(EncodeImageHandler *) WriteWBMPImage;
262 entry->adjoin=MagickFalse;
263 entry->description=ConstantString("Wireless Bitmap (level 0) image");
264 entry->module=ConstantString("WBMP");
265 (void) RegisterMagickInfo(entry);
266 return(MagickImageCoderSignature);
267}
268
269/*
270%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
271% %
272% %
273% %
274% U n r e g i s t e r W B M P I m a g e %
275% %
276% %
277% %
278%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
279%
280% UnregisterWBMPImage() removes format registrations made by the
281% WBMP module from the list of supported formats.
282%
283% The format of the UnregisterWBMPImage method is:
284%
285% UnregisterWBMPImage(void)
286%
287*/
288ModuleExport void UnregisterWBMPImage(void)
289{
290 (void) UnregisterMagickInfo("WBMP");
291}
292
293/*
294%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
295% %
296% %
297% %
298% W r i t e W B M P I m a g e %
299% %
300% %
301% %
302%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
303%
304% WriteWBMPImage() writes an image to a file in the Wireless Bitmap
305% (level 0) image format.
306%
307% WriteWBMPImage was contributed by Milan Votava <votava@mageo.cz>.
308%
309% The format of the WriteWBMPImage method is:
310%
311% MagickBooleanType WriteWBMPImage(const ImageInfo *image_info,
312% Image *image)
313%
314% A description of each parameter follows.
315%
316% o image_info: the image info.
317%
318% o image: The image.
319%
320%
321*/
322
cristybb503372010-05-27 20:51:26 +0000323static void WBMPWriteInteger(Image *image,const size_t value)
cristy3ed852e2009-09-05 21:47:34 +0000324{
325 int
326 bits,
327 flag,
328 n;
329
cristybb503372010-05-27 20:51:26 +0000330 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000331 i;
332
333 unsigned char
334 buffer[5],
335 octet;
336
337 n=1;
338 bits=28;
339 flag=MagickFalse;
340 for (i=4; i >= 0; i--)
341 {
342 octet=(unsigned char) ((value >> bits) & 0x7f);
343 if ((flag == 0) && (octet != 0))
344 {
345 flag=MagickTrue;
346 n=i+1;
347 }
348 buffer[4-i]=octet | (i && (flag || octet))*(0x01 << 7);
349 bits-=7;
350 }
351 (void) WriteBlob(image,(size_t) n,buffer+5-n);
352}
353
354static MagickBooleanType WriteWBMPImage(const ImageInfo *image_info,
355 Image *image)
356{
cristybb503372010-05-27 20:51:26 +0000357 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000358 y;
359
360 MagickBooleanType
361 status;
362
363 register const IndexPacket
364 *indexes;
365
366 register const PixelPacket
367 *p;
368
cristybb503372010-05-27 20:51:26 +0000369 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000370 x;
371
372 unsigned char
373 bit,
374 byte;
375
376 /*
377 Open output image file.
378 */
379 assert(image_info != (const ImageInfo *) NULL);
380 assert(image_info->signature == MagickSignature);
381 assert(image != (Image *) NULL);
382 assert(image->signature == MagickSignature);
383 if (image->debug != MagickFalse)
384 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
385 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
386 if (status == MagickFalse)
387 return(status);
388 if (image->colorspace != RGBColorspace)
389 (void) TransformImageColorspace(image,RGBColorspace);
390 /*
391 Convert image to a bi-level image.
392 */
393 (void) SetImageType(image,BilevelType);
394 (void) WriteBlobMSBShort(image,0);
395 WBMPWriteInteger(image,image->columns);
396 WBMPWriteInteger(image,image->rows);
cristybb503372010-05-27 20:51:26 +0000397 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000398 {
399 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
400 if (p == (const PixelPacket *) NULL)
401 break;
402 indexes=GetVirtualIndexQueue(image);
403 bit=0;
404 byte=0;
cristybb503372010-05-27 20:51:26 +0000405 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000406 {
407 if (PixelIntensity(p) >= ((MagickRealType) QuantumRange/2.0))
408 byte|=0x1 << (7-bit);
409 bit++;
410 if (bit == 8)
411 {
412 (void) WriteBlobByte(image,byte);
413 bit=0;
414 byte=0;
415 }
416 p++;
417 }
418 if (bit != 0)
419 (void) WriteBlobByte(image,byte);
cristycee97112010-05-28 00:44:52 +0000420 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
421 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000422 if (status == MagickFalse)
423 break;
424 }
425 (void) CloseBlob(image);
426 return(MagickTrue);
427}