/src/graphicsmagick/coders/wbmp.c
Line | Count | Source |
1 | | /* |
2 | | % Copyright (C) 2003-2020 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 | | |
45 | | /* |
46 | | Forward declarations. |
47 | | */ |
48 | | static unsigned int |
49 | | WriteWBMPImage(const ImageInfo *,Image *); |
50 | | |
51 | | /* |
52 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
53 | | % % |
54 | | % % |
55 | | % % |
56 | | % R e a d W B M P I m a g e % |
57 | | % % |
58 | | % % |
59 | | % % |
60 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
61 | | % |
62 | | % Method ReadWBMPImage reads a WBMP (level 0) image file and returns it. It |
63 | | % allocates the memory necessary for the new Image structure and returns a |
64 | | % pointer to the new image. |
65 | | % |
66 | | % ReadWBMPImage was contributed by Milan Votava <votava@mageo.cz>. |
67 | | % |
68 | | % The format of the ReadWBMPImage method is: |
69 | | % |
70 | | % Image *ReadWBMPImage(const ImageInfo *image_info, |
71 | | % ExceptionInfo *exception) |
72 | | % |
73 | | % A description of each parameter follows: |
74 | | % |
75 | | % o image: Method ReadWBMPImage returns a pointer to the image after |
76 | | % reading. A null image is returned if there is a memory shortage or |
77 | | % if the image cannot be read. |
78 | | % |
79 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
80 | | % |
81 | | % o exception: return any errors or warnings in this structure. |
82 | | % |
83 | | % |
84 | | */ |
85 | | |
86 | | static unsigned int WBMPReadInteger(Image *image,unsigned long *value) |
87 | 1.30k | { |
88 | 1.30k | int |
89 | 1.30k | byte; |
90 | | |
91 | 1.30k | *value=0; |
92 | 1.30k | do |
93 | 4.74M | { |
94 | 4.74M | byte=ReadBlobByte(image); |
95 | 4.74M | if (byte == EOF) |
96 | 32 | return(False); |
97 | 4.74M | *value<<=7; |
98 | 4.74M | *value|=(unsigned int) (byte & 0x7f); |
99 | 4.74M | } while (byte & 0x80); |
100 | 1.27k | return(True); |
101 | 1.30k | } |
102 | | |
103 | | static Image *ReadWBMPImage(const ImageInfo *image_info, |
104 | | ExceptionInfo *exception) |
105 | 681 | { |
106 | 681 | Image |
107 | 681 | *image; |
108 | | |
109 | 681 | int |
110 | 681 | byte; |
111 | | |
112 | 681 | long |
113 | 681 | y; |
114 | | |
115 | 681 | register IndexPacket |
116 | 681 | *indexes; |
117 | | |
118 | 681 | register long |
119 | 681 | x; |
120 | | |
121 | 681 | register PixelPacket |
122 | 681 | *q; |
123 | | |
124 | 681 | register long |
125 | 681 | i; |
126 | | |
127 | 681 | unsigned char |
128 | 681 | bit; |
129 | | |
130 | 681 | unsigned int |
131 | 681 | status; |
132 | | |
133 | 681 | unsigned short |
134 | 681 | header; |
135 | | |
136 | | /* |
137 | | Open image file. |
138 | | */ |
139 | 681 | assert(image_info != (const ImageInfo *) NULL); |
140 | 681 | assert(image_info->signature == MagickSignature); |
141 | 681 | assert(exception != (ExceptionInfo *) NULL); |
142 | 681 | assert(exception->signature == MagickSignature); |
143 | 681 | image=AllocateImage(image_info); |
144 | 681 | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
145 | 681 | if (status == False) |
146 | 681 | ThrowReaderException(FileOpenError,UnableToOpenFile,image); |
147 | 681 | if (ReadBlob(image,2,(char *) &header) != 2) |
148 | 679 | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
149 | 679 | if (header != 0U) |
150 | 660 | ThrowReaderException(CoderError,OnlyLevelZerofilesSupported,image); |
151 | | /* |
152 | | Initialize image structure. |
153 | | */ |
154 | 660 | if (WBMPReadInteger(image,&image->columns) == False) |
155 | 649 | ThrowReaderException(CorruptImageError,CorruptImage,image); |
156 | 649 | if (WBMPReadInteger(image,&image->rows) == False) |
157 | 628 | ThrowReaderException(CorruptImageError,CorruptImage,image); |
158 | 628 | if ((image->columns == 0) || (image->rows == 0)) |
159 | 624 | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
160 | 624 | for (i=0; i < image->offset; i++) |
161 | 0 | { |
162 | 0 | if (EOF == ReadBlobByte(image)) |
163 | 0 | ThrowException(exception,CorruptImageError,UnexpectedEndOfFile, |
164 | 0 | image->filename); |
165 | 0 | } |
166 | 624 | if (!AllocateImageColormap(image,2)) |
167 | 624 | ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
168 | 624 | if (image_info->ping) |
169 | 0 | { |
170 | 0 | CloseBlob(image); |
171 | 0 | StopTimer(&image->timer); |
172 | 0 | return(image); |
173 | 0 | } |
174 | | /* |
175 | | Convert bi-level image to pixel packets. |
176 | | */ |
177 | 121k | for (y=0; y < (long) image->rows; y++) |
178 | 120k | { |
179 | 120k | q=SetImagePixels(image,0,y,image->columns,1); |
180 | 120k | if (q == (PixelPacket *) NULL) |
181 | 222 | break; |
182 | 120k | indexes=AccessMutableIndexes(image); |
183 | 120k | bit=0; |
184 | 120k | byte=0; |
185 | 43.5M | for (x=0; x < (long) image->columns; x++) |
186 | 43.3M | { |
187 | 43.3M | if (bit == 0) |
188 | 5.46M | { |
189 | 5.46M | byte=ReadBlobByte(image); |
190 | 5.46M | if (byte == EOF) |
191 | 5.46M | ThrowReaderException(CorruptImageError,CorruptImage,image); |
192 | 5.46M | } |
193 | 43.3M | indexes[x]=(byte & (0x01 << (7-bit))) ? 1 : 0; |
194 | 43.3M | bit++; |
195 | 43.3M | if (bit == 8) |
196 | 5.39M | bit=0; |
197 | 43.3M | } |
198 | 120k | if (!SyncImagePixels(image)) |
199 | 0 | break; |
200 | 120k | if (QuantumTick(y,image->rows)) |
201 | 16.7k | if (!MagickMonitorFormatted(y,image->rows,exception,LoadImageText, |
202 | 16.7k | image->filename, |
203 | 16.7k | image->columns,image->rows)) |
204 | 0 | break; |
205 | 120k | } |
206 | 488 | (void) SyncImage(image); |
207 | 488 | if (EOFBlob(image)) |
208 | 0 | ThrowException(exception,CorruptImageError,UnexpectedEndOfFile, |
209 | 488 | image->filename); |
210 | 488 | CloseBlob(image); |
211 | 488 | StopTimer(&image->timer); |
212 | 488 | return(image); |
213 | 624 | } |
214 | | |
215 | | /* |
216 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
217 | | % % |
218 | | % % |
219 | | % % |
220 | | % R e g i s t e r W B M P I m a g e % |
221 | | % % |
222 | | % % |
223 | | % % |
224 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
225 | | % |
226 | | % Method RegisterWBMPImage adds attributes for the WBMP image format to |
227 | | % the list of supported formats. The attributes include the image format |
228 | | % tag, a method to read and/or write the format, whether the format |
229 | | % supports the saving of more than one frame to the same file or blob, |
230 | | % whether the format supports native in-memory I/O, and a brief |
231 | | % description of the format. |
232 | | % |
233 | | % The format of the RegisterWBMPImage method is: |
234 | | % |
235 | | % RegisterWBMPImage(void) |
236 | | % |
237 | | */ |
238 | | ModuleExport void RegisterWBMPImage(void) |
239 | 1 | { |
240 | 1 | MagickInfo |
241 | 1 | *entry; |
242 | | |
243 | 1 | entry=SetMagickInfo("WBMP"); |
244 | 1 | entry->decoder=(DecoderHandler) ReadWBMPImage; |
245 | 1 | entry->encoder=(EncoderHandler) WriteWBMPImage; |
246 | 1 | entry->adjoin=False; |
247 | 1 | entry->description="Wireless Bitmap (level 0) image"; |
248 | 1 | entry->module="WBMP"; |
249 | 1 | (void) RegisterMagickInfo(entry); |
250 | 1 | } |
251 | | |
252 | | /* |
253 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
254 | | % % |
255 | | % % |
256 | | % % |
257 | | % U n r e g i s t e r W B M P I m a g e % |
258 | | % % |
259 | | % % |
260 | | % % |
261 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
262 | | % |
263 | | % Method UnregisterWBMPImage removes format registrations made by the |
264 | | % WBMP module from the list of supported formats. |
265 | | % |
266 | | % The format of the UnregisterWBMPImage method is: |
267 | | % |
268 | | % UnregisterWBMPImage(void) |
269 | | % |
270 | | */ |
271 | | ModuleExport void UnregisterWBMPImage(void) |
272 | 0 | { |
273 | 0 | (void) UnregisterMagickInfo("WBMP"); |
274 | 0 | } |
275 | | |
276 | | /* |
277 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
278 | | % % |
279 | | % % |
280 | | % % |
281 | | % W r i t e W B M P I m a g e % |
282 | | % % |
283 | | % % |
284 | | % % |
285 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
286 | | % |
287 | | % Method WriteWBMPImage writes an image to a file in the Wireless Bitmap |
288 | | % (level 0) image format. |
289 | | % |
290 | | % WriteWBMPImage was contributed by Milan Votava <votava@mageo.cz>. |
291 | | % |
292 | | % The format of the WriteWBMPImage method is: |
293 | | % |
294 | | % unsigned int WriteWBMPImage(const ImageInfo *image_info,Image *image) |
295 | | % |
296 | | % A description of each parameter follows. |
297 | | % |
298 | | % o status: Method WriteWBMPImage return True if the image is written. |
299 | | % False is returned is there is a memory shortage or if the image file |
300 | | % fails to write. |
301 | | % |
302 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
303 | | % |
304 | | % o image: A pointer to an Image structure. |
305 | | % |
306 | | % |
307 | | */ |
308 | | |
309 | | static void WBMPWriteInteger(Image *image,const unsigned long value) |
310 | 398 | { |
311 | 398 | int |
312 | 398 | bits, |
313 | 398 | flag, |
314 | 398 | n; |
315 | | |
316 | 398 | register long |
317 | 398 | i; |
318 | | |
319 | 398 | unsigned char |
320 | 398 | buffer[5], |
321 | 398 | octet; |
322 | | |
323 | 398 | n=1; |
324 | 398 | bits=28; |
325 | 398 | flag=False; |
326 | 2.38k | for(i=4; i >= 0; i--) |
327 | 1.99k | { |
328 | 1.99k | octet=(unsigned char) ((value >> bits) & 0x7f); |
329 | 1.99k | if (!flag && octet) |
330 | 398 | { |
331 | 398 | flag=True; |
332 | 398 | n=i+1; |
333 | 398 | } |
334 | 1.99k | buffer[4-i]=octet | (i && (flag || octet))*(0x01 << 7); |
335 | 1.99k | bits-=7; |
336 | 1.99k | } |
337 | 398 | (void) WriteBlob(image,n,(char *) buffer+5-n); |
338 | 398 | } |
339 | | |
340 | | static unsigned int WriteWBMPImage(const ImageInfo *image_info,Image *image) |
341 | 199 | { |
342 | 199 | long |
343 | 199 | y; |
344 | | |
345 | 199 | register const PixelPacket |
346 | 199 | *p; |
347 | | |
348 | 199 | register const IndexPacket |
349 | 199 | *indexes; |
350 | | |
351 | 199 | register long |
352 | 199 | x; |
353 | | |
354 | 199 | unsigned char |
355 | 199 | bit, |
356 | 199 | byte, |
357 | 199 | polarity; |
358 | | |
359 | 199 | unsigned int |
360 | 199 | status; |
361 | | |
362 | | /* |
363 | | Open output image file. |
364 | | */ |
365 | 199 | assert(image_info != (const ImageInfo *) NULL); |
366 | 199 | assert(image_info->signature == MagickSignature); |
367 | 199 | assert(image != (Image *) NULL); |
368 | 199 | assert(image->signature == MagickSignature); |
369 | 199 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); |
370 | 199 | if (status == False) |
371 | 199 | ThrowWriterException(FileOpenError,UnableToOpenFile,image); |
372 | 199 | (void) TransformColorspace(image,RGBColorspace); |
373 | | /* |
374 | | Convert image to a bi-level image. |
375 | | */ |
376 | 199 | (void) SetImageType(image,BilevelType); |
377 | 199 | polarity=PixelIntensityToQuantum(&image->colormap[0]) < (MaxRGB/2); |
378 | 199 | if (image->colors == 2) |
379 | 199 | polarity=PixelIntensityToQuantum(&image->colormap[0]) < |
380 | 199 | PixelIntensityToQuantum(&image->colormap[1]); |
381 | 199 | (void) WriteBlobMSBShort(image,0); |
382 | 199 | WBMPWriteInteger(image,image->columns); |
383 | 199 | WBMPWriteInteger(image,image->rows); |
384 | 97.7k | for (y=0; y < (long) image->rows; y++) |
385 | 97.5k | { |
386 | 97.5k | p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception); |
387 | 97.5k | if (p == (const PixelPacket *) NULL) |
388 | 0 | break; |
389 | 97.5k | indexes=AccessImmutableIndexes(image); |
390 | 97.5k | bit=0; |
391 | 97.5k | byte=0; |
392 | 28.7M | for (x=0; x < (long) image->columns; x++) |
393 | 28.6M | { |
394 | 28.6M | if (indexes[x] == polarity) |
395 | 5.63M | byte|=0x1 << (7-bit); |
396 | 28.6M | bit++; |
397 | 28.6M | if (bit == 8) |
398 | 3.55M | { |
399 | 3.55M | (void) WriteBlobByte(image,byte); |
400 | 3.55M | bit=0; |
401 | 3.55M | byte=0; |
402 | 3.55M | } |
403 | 28.6M | } |
404 | 97.5k | if (bit != 0) |
405 | 61.9k | (void) WriteBlobByte(image,byte); |
406 | 97.5k | if (QuantumTick(y,image->rows)) |
407 | 14.0k | if (!MagickMonitorFormatted(y,image->rows,&image->exception, |
408 | 14.0k | SaveImageText,image->filename, |
409 | 14.0k | image->columns,image->rows)) |
410 | 0 | break; |
411 | 97.5k | } |
412 | 199 | status &= CloseBlob(image); |
413 | 199 | return(status); |
414 | 199 | } |