/src/graphicsmagick/coders/wbmp.c
Line | Count | Source |
1 | | /* |
2 | | % Copyright (C) 2003-2026 GraphicsMagick Group |
3 | | % Copyright (C) 2002 ImageMagick Studio |
4 | | % Copyright 1991-1999 E. I. du Pont de Nemours and Company |
5 | | % |
6 | | % This program is covered by multiple licenses, which are described in |
7 | | % Copyright.txt. You should have received a copy of Copyright.txt with this |
8 | | % package; otherwise see http://www.graphicsmagick.org/www/Copyright.html. |
9 | | % |
10 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
11 | | % % |
12 | | % % |
13 | | % % |
14 | | % W W BBBB M M PPPP % |
15 | | % W W B B MM MM P P % |
16 | | % W W W BBBB M M M PPPP % |
17 | | % WW WW B B M M P % |
18 | | % W W BBBB M M P % |
19 | | % % |
20 | | % % |
21 | | % Read/Write Wireless Bitmap (level 0) Image Format. % |
22 | | % % |
23 | | % % |
24 | | % Software Design % |
25 | | % John Cristy % |
26 | | % January 2000 % |
27 | | % % |
28 | | % % |
29 | | % % |
30 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
31 | | % |
32 | | % |
33 | | */ |
34 | | /* |
35 | | Include declarations. |
36 | | */ |
37 | | #include "magick/studio.h" |
38 | | #include "magick/blob.h" |
39 | | #include "magick/colormap.h" |
40 | | #include "magick/magick.h" |
41 | | #include "magick/monitor.h" |
42 | | #include "magick/pixel_cache.h" |
43 | | #include "magick/utility.h" |
44 | | #include "magick/static.h" |
45 | | |
46 | | /* |
47 | | Forward declarations. |
48 | | */ |
49 | | static unsigned int |
50 | | WriteWBMPImage(const ImageInfo *,Image *); |
51 | | |
52 | | /* |
53 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
54 | | % % |
55 | | % % |
56 | | % % |
57 | | % R e a d W B M P I m a g e % |
58 | | % % |
59 | | % % |
60 | | % % |
61 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
62 | | % |
63 | | % Method ReadWBMPImage reads a WBMP (level 0) image file and returns it. It |
64 | | % allocates the memory necessary for the new Image structure and returns a |
65 | | % pointer to the new image. |
66 | | % |
67 | | % ReadWBMPImage was contributed by Milan Votava <votava@mageo.cz>. |
68 | | % |
69 | | % The format of the ReadWBMPImage method is: |
70 | | % |
71 | | % Image *ReadWBMPImage(const ImageInfo *image_info, |
72 | | % ExceptionInfo *exception) |
73 | | % |
74 | | % A description of each parameter follows: |
75 | | % |
76 | | % o image: Method ReadWBMPImage returns a pointer to the image after |
77 | | % reading. A null image is returned if there is a memory shortage or |
78 | | % if the image cannot be read. |
79 | | % |
80 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
81 | | % |
82 | | % o exception: return any errors or warnings in this structure. |
83 | | % |
84 | | % |
85 | | */ |
86 | | |
87 | | static unsigned int WBMPReadInteger(Image *image,unsigned long *value) |
88 | 1.43k | { |
89 | 1.43k | int |
90 | 1.43k | byte; |
91 | | |
92 | 1.43k | *value=0; |
93 | 1.43k | do |
94 | 4.41M | { |
95 | 4.41M | byte=ReadBlobByte(image); |
96 | 4.41M | if (byte == EOF) |
97 | 34 | return(False); |
98 | 4.41M | *value<<=7; |
99 | 4.41M | *value|=(unsigned int) (byte & 0x7f); |
100 | 4.41M | } while (byte & 0x80); |
101 | 1.40k | return(True); |
102 | 1.43k | } |
103 | | |
104 | | static Image *ReadWBMPImage(const ImageInfo *image_info, |
105 | | ExceptionInfo *exception) |
106 | 748 | { |
107 | 748 | Image |
108 | 748 | *image; |
109 | | |
110 | 748 | int |
111 | 748 | byte; |
112 | | |
113 | 748 | long |
114 | 748 | y; |
115 | | |
116 | 748 | register IndexPacket |
117 | 748 | *indexes; |
118 | | |
119 | 748 | register long |
120 | 748 | x; |
121 | | |
122 | 748 | register PixelPacket |
123 | 748 | *q; |
124 | | |
125 | 748 | register long |
126 | 748 | i; |
127 | | |
128 | 748 | unsigned char |
129 | 748 | bit; |
130 | | |
131 | 748 | unsigned int |
132 | 748 | status; |
133 | | |
134 | 748 | unsigned short |
135 | 748 | header; |
136 | | |
137 | | /* |
138 | | Open image file. |
139 | | */ |
140 | 748 | assert(image_info != (const ImageInfo *) NULL); |
141 | 748 | assert(image_info->signature == MagickSignature); |
142 | 748 | assert(exception != (ExceptionInfo *) NULL); |
143 | 748 | assert(exception->signature == MagickSignature); |
144 | 748 | image=AllocateImage(image_info); |
145 | 748 | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
146 | 748 | if (status == False) |
147 | 748 | ThrowReaderException(FileOpenError,UnableToOpenFile,image); |
148 | 748 | if (ReadBlob(image,2,(char *) &header) != 2) |
149 | 745 | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
150 | 745 | if (header != 0U) |
151 | 725 | ThrowReaderException(CoderError,OnlyLevelZerofilesSupported,image); |
152 | | /* |
153 | | Initialize image structure. |
154 | | */ |
155 | 725 | if (WBMPReadInteger(image,&image->columns) == False) |
156 | 711 | ThrowReaderException(CorruptImageError,CorruptImage,image); |
157 | 711 | if (WBMPReadInteger(image,&image->rows) == False) |
158 | 691 | ThrowReaderException(CorruptImageError,CorruptImage,image); |
159 | 691 | if ((image->columns == 0) || (image->rows == 0)) |
160 | 687 | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
161 | 687 | for (i=0; i < image->offset; i++) |
162 | 0 | { |
163 | 0 | if (EOF == ReadBlobByte(image)) |
164 | 0 | ThrowException(exception,CorruptImageError,UnexpectedEndOfFile, |
165 | 0 | image->filename); |
166 | 0 | } |
167 | 687 | if (!AllocateImageColormap(image,2)) |
168 | 687 | ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
169 | 687 | if (image_info->ping) |
170 | 0 | { |
171 | 0 | CloseBlob(image); |
172 | 0 | StopTimer(&image->timer); |
173 | 0 | return(image); |
174 | 0 | } |
175 | | /* |
176 | | Convert bi-level image to pixel packets. |
177 | | */ |
178 | 139k | for (y=0; y < (long) image->rows; y++) |
179 | 138k | { |
180 | 138k | q=SetImagePixels(image,0,y,image->columns,1); |
181 | 138k | if (q == (PixelPacket *) NULL) |
182 | 230 | break; |
183 | 138k | indexes=AccessMutableIndexes(image); |
184 | 138k | bit=0; |
185 | 138k | byte=0; |
186 | 56.9M | for (x=0; x < (long) image->columns; x++) |
187 | 56.8M | { |
188 | 56.8M | if (bit == 0) |
189 | 7.15M | { |
190 | 7.15M | byte=ReadBlobByte(image); |
191 | 7.15M | if (byte == EOF) |
192 | 7.15M | ThrowReaderException(CorruptImageError,CorruptImage,image); |
193 | 7.15M | } |
194 | 56.8M | indexes[x]=(byte & (0x01 << (7-bit))) ? 1 : 0; |
195 | 56.8M | bit++; |
196 | 56.8M | if (bit == 8) |
197 | 7.06M | bit=0; |
198 | 56.8M | } |
199 | 138k | if (!SyncImagePixels(image)) |
200 | 0 | break; |
201 | 138k | if (QuantumTick(y,image->rows)) |
202 | 17.5k | if (!MagickMonitorFormatted(y,image->rows,exception,LoadImageText, |
203 | 17.5k | image->filename, |
204 | 17.5k | image->columns,image->rows)) |
205 | 0 | break; |
206 | 138k | } |
207 | 506 | (void) SyncImage(image); |
208 | 506 | if (EOFBlob(image)) |
209 | 0 | ThrowException(exception,CorruptImageError,UnexpectedEndOfFile, |
210 | 506 | image->filename); |
211 | 506 | CloseBlob(image); |
212 | 506 | StopTimer(&image->timer); |
213 | 506 | return(image); |
214 | 687 | } |
215 | | |
216 | | /* |
217 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
218 | | % % |
219 | | % % |
220 | | % % |
221 | | % R e g i s t e r W B M P I m a g e % |
222 | | % % |
223 | | % % |
224 | | % % |
225 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
226 | | % |
227 | | % Method RegisterWBMPImage adds attributes for the WBMP image format to |
228 | | % the list of supported formats. The attributes include the image format |
229 | | % tag, a method to read and/or write the format, whether the format |
230 | | % supports the saving of more than one frame to the same file or blob, |
231 | | % whether the format supports native in-memory I/O, and a brief |
232 | | % description of the format. |
233 | | % |
234 | | % The format of the RegisterWBMPImage method is: |
235 | | % |
236 | | % RegisterWBMPImage(void) |
237 | | % |
238 | | */ |
239 | | ModuleExport void RegisterWBMPImage(void) |
240 | 1 | { |
241 | 1 | MagickInfo |
242 | 1 | *entry; |
243 | | |
244 | | /* WBMP is the most common extension */ |
245 | 1 | entry=SetMagickInfo("WBMP"); |
246 | 1 | entry->decoder=(DecoderHandler) ReadWBMPImage; |
247 | 1 | entry->encoder=(EncoderHandler) WriteWBMPImage; |
248 | 1 | entry->adjoin=False; |
249 | 1 | entry->description="Wireless Bitmap (level 0) image"; |
250 | 1 | entry->module="WBMP"; |
251 | 1 | (void) RegisterMagickInfo(entry); |
252 | | |
253 | | /* WBM is a less common extension */ |
254 | 1 | entry=SetMagickInfo("WBM"); |
255 | 1 | entry->decoder=(DecoderHandler) ReadWBMPImage; |
256 | 1 | entry->encoder=(EncoderHandler) WriteWBMPImage; |
257 | 1 | entry->adjoin=False; |
258 | 1 | entry->description="Wireless Bitmap (level 0) image"; |
259 | 1 | entry->module="WBMP"; |
260 | 1 | entry->stealth=MagickTrue; /* Don't list in '-list format' output */ |
261 | 1 | (void) RegisterMagickInfo(entry); |
262 | | |
263 | | /* WBP is the least common extension */ |
264 | 1 | entry=SetMagickInfo("WBP"); |
265 | 1 | entry->decoder=(DecoderHandler) ReadWBMPImage; |
266 | 1 | entry->encoder=(EncoderHandler) WriteWBMPImage; |
267 | 1 | entry->adjoin=False; |
268 | 1 | entry->description="Wireless Bitmap (level 0) image"; |
269 | 1 | entry->module="WBMP"; |
270 | 1 | entry->stealth=MagickTrue; /* Don't list in '-list format' output */ |
271 | 1 | (void) RegisterMagickInfo(entry); |
272 | 1 | } |
273 | | |
274 | | /* |
275 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
276 | | % % |
277 | | % % |
278 | | % % |
279 | | % U n r e g i s t e r W B M P I m a g e % |
280 | | % % |
281 | | % % |
282 | | % % |
283 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
284 | | % |
285 | | % Method UnregisterWBMPImage removes format registrations made by the |
286 | | % WBMP module from the list of supported formats. |
287 | | % |
288 | | % The format of the UnregisterWBMPImage method is: |
289 | | % |
290 | | % UnregisterWBMPImage(void) |
291 | | % |
292 | | */ |
293 | | ModuleExport void UnregisterWBMPImage(void) |
294 | 0 | { |
295 | 0 | (void) UnregisterMagickInfo("WBMP"); |
296 | 0 | (void) UnregisterMagickInfo("WBM"); |
297 | 0 | (void) UnregisterMagickInfo("WBP"); |
298 | 0 | } |
299 | | |
300 | | /* |
301 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
302 | | % % |
303 | | % % |
304 | | % % |
305 | | % W r i t e W B M P I m a g e % |
306 | | % % |
307 | | % % |
308 | | % % |
309 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
310 | | % |
311 | | % Method WriteWBMPImage writes an image to a file in the Wireless Bitmap |
312 | | % (level 0) image format. |
313 | | % |
314 | | % WriteWBMPImage was contributed by Milan Votava <votava@mageo.cz>. |
315 | | % |
316 | | % The format of the WriteWBMPImage method is: |
317 | | % |
318 | | % unsigned int WriteWBMPImage(const ImageInfo *image_info,Image *image) |
319 | | % |
320 | | % A description of each parameter follows. |
321 | | % |
322 | | % o status: Method WriteWBMPImage return True if the image is written. |
323 | | % False is returned is there is a memory shortage or if the image file |
324 | | % fails to write. |
325 | | % |
326 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
327 | | % |
328 | | % o image: A pointer to an Image structure. |
329 | | % |
330 | | % |
331 | | */ |
332 | | |
333 | | static void WBMPWriteInteger(Image *image,const unsigned long value) |
334 | 414 | { |
335 | 414 | int |
336 | 414 | bits, |
337 | 414 | flag, |
338 | 414 | n; |
339 | | |
340 | 414 | register long |
341 | 414 | i; |
342 | | |
343 | 414 | unsigned char |
344 | 414 | buffer[5], |
345 | 414 | octet; |
346 | | |
347 | 414 | n=1; |
348 | 414 | bits=28; |
349 | 414 | flag=False; |
350 | 2.48k | for(i=4; i >= 0; i--) |
351 | 2.07k | { |
352 | 2.07k | octet=(unsigned char) ((value >> bits) & 0x7f); |
353 | 2.07k | if (!flag && octet) |
354 | 414 | { |
355 | 414 | flag=True; |
356 | 414 | n=i+1; |
357 | 414 | } |
358 | 2.07k | buffer[4-i]=octet | (i && (flag || octet))*(0x01 << 7); |
359 | 2.07k | bits-=7; |
360 | 2.07k | } |
361 | 414 | (void) WriteBlob(image,n,(char *) buffer+5-n); |
362 | 414 | } |
363 | | |
364 | | static unsigned int WriteWBMPImage(const ImageInfo *image_info,Image *image) |
365 | 207 | { |
366 | 207 | long |
367 | 207 | y; |
368 | | |
369 | 207 | register const PixelPacket |
370 | 207 | *p; |
371 | | |
372 | 207 | register const IndexPacket |
373 | 207 | *indexes; |
374 | | |
375 | 207 | register long |
376 | 207 | x; |
377 | | |
378 | 207 | unsigned char |
379 | 207 | bit, |
380 | 207 | byte, |
381 | 207 | polarity; |
382 | | |
383 | 207 | unsigned int |
384 | 207 | status; |
385 | | |
386 | | /* |
387 | | Open output image file. |
388 | | */ |
389 | 207 | assert(image_info != (const ImageInfo *) NULL); |
390 | 207 | assert(image_info->signature == MagickSignature); |
391 | 207 | assert(image != (Image *) NULL); |
392 | 207 | assert(image->signature == MagickSignature); |
393 | 207 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); |
394 | 207 | if (status == False) |
395 | 207 | ThrowWriterException(FileOpenError,UnableToOpenFile,image); |
396 | 207 | if (TransformColorspace(image,RGBColorspace) == MagickFail) |
397 | 207 | ThrowWriterException(CoderError,UnableToTransformColorspace,image); |
398 | | /* |
399 | | Convert image to a bi-level image. |
400 | | */ |
401 | 207 | if (SetImageType(image,BilevelType) == MagickFail) |
402 | 207 | ThrowWriterException(CoderError,UnableToSetImageType,image); |
403 | 207 | polarity=PixelIntensityToQuantum(&image->colormap[0]) < (MaxRGB/2); |
404 | 207 | if (image->colors == 2) |
405 | 207 | polarity=PixelIntensityToQuantum(&image->colormap[0]) < |
406 | 207 | PixelIntensityToQuantum(&image->colormap[1]); |
407 | 207 | (void) WriteBlobMSBShort(image,0); |
408 | 207 | WBMPWriteInteger(image,image->columns); |
409 | 207 | WBMPWriteInteger(image,image->rows); |
410 | 97.7k | for (y=0; y < (long) image->rows; y++) |
411 | 97.5k | { |
412 | 97.5k | p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception); |
413 | 97.5k | if (p == (const PixelPacket *) NULL) |
414 | 0 | break; |
415 | 97.5k | indexes=AccessImmutableIndexes(image); |
416 | 97.5k | bit=0; |
417 | 97.5k | byte=0; |
418 | 29.9M | for (x=0; x < (long) image->columns; x++) |
419 | 29.8M | { |
420 | 29.8M | if (indexes[x] == polarity) |
421 | 8.04M | byte|=0x1 << (7-bit); |
422 | 29.8M | bit++; |
423 | 29.8M | if (bit == 8) |
424 | 3.70M | { |
425 | 3.70M | (void) WriteBlobByte(image,byte); |
426 | 3.70M | bit=0; |
427 | 3.70M | byte=0; |
428 | 3.70M | } |
429 | 29.8M | } |
430 | 97.5k | if (bit != 0) |
431 | 69.4k | (void) WriteBlobByte(image,byte); |
432 | 97.5k | if (QuantumTick(y,image->rows)) |
433 | 14.1k | if (!MagickMonitorFormatted(y,image->rows,&image->exception, |
434 | 14.1k | SaveImageText,image->filename, |
435 | 14.1k | image->columns,image->rows)) |
436 | 0 | break; |
437 | 97.5k | } |
438 | 207 | status &= CloseBlob(image); |
439 | 207 | return(status); |
440 | 207 | } |