1 /*
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 % Cristy %
17 % January 2000 %
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 Include declarations.
40 */
41 #include "MagickCore/studio.h"
42 #include "MagickCore/attribute.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"
49 #include "MagickCore/colorspace-private.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/string_.h"
63 #include "MagickCore/module.h"
64
65 /*
66 Forward declarations.
67 */
68 static MagickBooleanType
69 WriteWBMPImage(const ImageInfo *,Image *,ExceptionInfo *);
70
71 /*
72 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
73 % %
74 % %
75 % %
76 % R e a d W B M P I m a g e %
77 % %
78 % %
79 % %
80 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
81 %
82 % ReadWBMPImage() reads a WBMP (level 0) image file and returns it. It
83 % allocates the memory necessary for the new Image structure and returns a
84 % pointer to the new image.
85 %
86 % ReadWBMPImage was contributed by Milan Votava <votava@mageo.cz>.
87 %
88 % The format of the ReadWBMPImage method is:
89 %
90 % Image *ReadWBMPImage(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 */
100
WBMPReadInteger(Image * image,size_t * value)101 static MagickBooleanType WBMPReadInteger(Image *image,size_t *value)
102 {
103 int
104 byte;
105
106 *value=0;
107 do
108 {
109 byte=ReadBlobByte(image);
110 if (byte == EOF)
111 return(MagickFalse);
112 *value<<=7;
113 *value|=(unsigned int) (byte & 0x7f);
114 } while (byte & 0x80);
115 return(MagickTrue);
116 }
117
ReadWBMPImage(const ImageInfo * image_info,ExceptionInfo * exception)118 static Image *ReadWBMPImage(const ImageInfo *image_info,
119 ExceptionInfo *exception)
120 {
121 Image
122 *image;
123
124 int
125 byte;
126
127 MagickBooleanType
128 status;
129
130 register ssize_t
131 x;
132
133 register Quantum
134 *q;
135
136 ssize_t
137 y;
138
139 unsigned char
140 bit;
141
142 unsigned short
143 header;
144
145 /*
146 Open image file.
147 */
148 assert(image_info != (const ImageInfo *) NULL);
149 assert(image_info->signature == MagickCoreSignature);
150 if (image_info->debug != MagickFalse)
151 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
152 image_info->filename);
153 assert(exception != (ExceptionInfo *) NULL);
154 assert(exception->signature == MagickCoreSignature);
155 image=AcquireImage(image_info,exception);
156 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
157 if (status == MagickFalse)
158 {
159 image=DestroyImageList(image);
160 return((Image *) NULL);
161 }
162 header=0;
163 if (ReadBlob(image,2,(unsigned char *) &header) != 2)
164 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
165 if (header != 0)
166 ThrowReaderException(CoderError,"OnlyLevelZerofilesSupported");
167 /*
168 Initialize image structure.
169 */
170 if (WBMPReadInteger(image,&image->columns) == MagickFalse)
171 ThrowReaderException(CorruptImageError,"CorruptWBMPimage");
172 if (WBMPReadInteger(image,&image->rows) == MagickFalse)
173 ThrowReaderException(CorruptImageError,"CorruptWBMPimage");
174 if ((image->columns == 0) || (image->rows == 0))
175 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
176 if (DiscardBlobBytes(image,image->offset) == MagickFalse)
177 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
178 image->filename);
179 if (image_info->ping != MagickFalse)
180 {
181 (void) CloseBlob(image);
182 return(GetFirstImageInList(image));
183 }
184 status=SetImageExtent(image,image->columns,image->rows,exception);
185 if (status == MagickFalse)
186 return(DestroyImageList(image));
187 (void) SetImageBackgroundColor(image,exception);
188 if (AcquireImageColormap(image,2,exception) == MagickFalse)
189 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
190 /*
191 Convert bi-level image to pixel packets.
192 */
193 for (y=0; y < (ssize_t) image->rows; y++)
194 {
195 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
196 if (q == (Quantum *) NULL)
197 break;
198 bit=0;
199 byte=0;
200 for (x=0; x < (ssize_t) image->columns; x++)
201 {
202 if (bit == 0)
203 {
204 byte=ReadBlobByte(image);
205 if (byte == EOF)
206 ThrowReaderException(CorruptImageError,"CorruptImage");
207 }
208 SetPixelIndex(image,(byte & (0x01 << (7-bit))) ? 1 : 0,q);
209 bit++;
210 if (bit == 8)
211 bit=0;
212 q+=GetPixelChannels(image);
213 }
214 if (SyncAuthenticPixels(image,exception) == MagickFalse)
215 break;
216 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
217 image->rows);
218 if (status == MagickFalse)
219 break;
220 }
221 (void) SyncImage(image,exception);
222 if (EOFBlob(image) != MagickFalse)
223 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
224 image->filename);
225 (void) CloseBlob(image);
226 return(GetFirstImageInList(image));
227 }
228
229 /*
230 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
231 % %
232 % %
233 % %
234 % R e g i s t e r W B M P I m a g e %
235 % %
236 % %
237 % %
238 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
239 %
240 % RegisterWBMPImage() adds attributes for the WBMP image format to
241 % the list of supported formats. The attributes include the image format
242 % tag, a method to read and/or write the format, whether the format
243 % supports the saving of more than one frame to the same file or blob,
244 % whether the format supports native in-memory I/O, and a brief
245 % description of the format.
246 %
247 % The format of the RegisterWBMPImage method is:
248 %
249 % size_t RegisterWBMPImage(void)
250 %
251 */
RegisterWBMPImage(void)252 ModuleExport size_t RegisterWBMPImage(void)
253 {
254 MagickInfo
255 *entry;
256
257 entry=AcquireMagickInfo("WBMP","WBMP","Wireless Bitmap (level 0) image");
258 entry->decoder=(DecodeImageHandler *) ReadWBMPImage;
259 entry->encoder=(EncodeImageHandler *) WriteWBMPImage;
260 entry->flags^=CoderAdjoinFlag;
261 (void) RegisterMagickInfo(entry);
262 return(MagickImageCoderSignature);
263 }
264
265 /*
266 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
267 % %
268 % %
269 % %
270 % U n r e g i s t e r W B M P I m a g e %
271 % %
272 % %
273 % %
274 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
275 %
276 % UnregisterWBMPImage() removes format registrations made by the
277 % WBMP module from the list of supported formats.
278 %
279 % The format of the UnregisterWBMPImage method is:
280 %
281 % UnregisterWBMPImage(void)
282 %
283 */
UnregisterWBMPImage(void)284 ModuleExport void UnregisterWBMPImage(void)
285 {
286 (void) UnregisterMagickInfo("WBMP");
287 }
288
289 /*
290 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
291 % %
292 % %
293 % %
294 % W r i t e W B M P I m a g e %
295 % %
296 % %
297 % %
298 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
299 %
300 % WriteWBMPImage() writes an image to a file in the Wireless Bitmap
301 % (level 0) image format.
302 %
303 % WriteWBMPImage was contributed by Milan Votava <votava@mageo.cz>.
304 %
305 % The format of the WriteWBMPImage method is:
306 %
307 % MagickBooleanType WriteWBMPImage(const ImageInfo *image_info,
308 % Image *image,ExceptionInfo *exception)
309 %
310 % A description of each parameter follows.
311 %
312 % o image_info: the image info.
313 %
314 % o image: The image.
315 %
316 % o exception: return any errors or warnings in this structure.
317 %
318 */
319
WBMPWriteInteger(Image * image,const size_t value)320 static void WBMPWriteInteger(Image *image,const size_t value)
321 {
322 int
323 bits,
324 flag,
325 n;
326
327 register ssize_t
328 i;
329
330 unsigned char
331 buffer[5],
332 octet;
333
334 n=1;
335 bits=28;
336 flag=MagickFalse;
337 for (i=4; i >= 0; i--)
338 {
339 octet=(unsigned char) ((value >> bits) & 0x7f);
340 if ((flag == 0) && (octet != 0))
341 {
342 flag=MagickTrue;
343 n=i+1;
344 }
345 buffer[4-i]=octet | (i && (flag || octet))*(0x01 << 7);
346 bits-=7;
347 }
348 (void) WriteBlob(image,(size_t) n,buffer+5-n);
349 }
350
WriteWBMPImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)351 static MagickBooleanType WriteWBMPImage(const ImageInfo *image_info,
352 Image *image,ExceptionInfo *exception)
353 {
354 MagickBooleanType
355 status;
356
357 register const Quantum
358 *p;
359
360 register ssize_t
361 x;
362
363 ssize_t
364 y;
365
366 unsigned char
367 bit,
368 byte;
369
370 /*
371 Open output image file.
372 */
373 assert(image_info != (const ImageInfo *) NULL);
374 assert(image_info->signature == MagickCoreSignature);
375 assert(image != (Image *) NULL);
376 assert(image->signature == MagickCoreSignature);
377 if (image->debug != MagickFalse)
378 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
379 assert(exception != (ExceptionInfo *) NULL);
380 assert(exception->signature == MagickCoreSignature);
381 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
382 if (status == MagickFalse)
383 return(status);
384 (void) TransformImageColorspace(image,sRGBColorspace,exception);
385 /*
386 Convert image to a bi-level image.
387 */
388 (void) SetImageType(image,BilevelType,exception);
389 (void) WriteBlobMSBShort(image,0);
390 WBMPWriteInteger(image,image->columns);
391 WBMPWriteInteger(image,image->rows);
392 for (y=0; y < (ssize_t) image->rows; y++)
393 {
394 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
395 if (p == (const Quantum *) NULL)
396 break;
397 bit=0;
398 byte=0;
399 for (x=0; x < (ssize_t) image->columns; x++)
400 {
401 if (GetPixelLuma(image,p) >= (QuantumRange/2.0))
402 byte|=0x1 << (7-bit);
403 bit++;
404 if (bit == 8)
405 {
406 (void) WriteBlobByte(image,byte);
407 bit=0;
408 byte=0;
409 }
410 p+=GetPixelChannels(image);
411 }
412 if (bit != 0)
413 (void) WriteBlobByte(image,byte);
414 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
415 image->rows);
416 if (status == MagickFalse)
417 break;
418 }
419 (void) CloseBlob(image);
420 return(MagickTrue);
421 }
422