/src/freeimage-svn/FreeImage/trunk/Source/FreeImage/PluginWBMP.cpp
Line | Count | Source |
1 | | // ========================================================== |
2 | | // Wireless Bitmap Format Loader and Writer |
3 | | // |
4 | | // Design and implementation by |
5 | | // - Hervé Drolon <drolon@infonie.fr> |
6 | | // |
7 | | // This file is part of FreeImage 3 |
8 | | // |
9 | | // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY |
10 | | // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES |
11 | | // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE |
12 | | // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED |
13 | | // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT |
14 | | // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY |
15 | | // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL |
16 | | // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER |
17 | | // THIS DISCLAIMER. |
18 | | // |
19 | | // Use at your own risk! |
20 | | // ========================================================== |
21 | | |
22 | | #include "FreeImage.h" |
23 | | #include "Utilities.h" |
24 | | |
25 | | // ---------------------------------------------------------- |
26 | | // Wireless Bitmap Format |
27 | | // ---------------------- |
28 | | // The WBMP format enables graphical information to be sent to a variety of handsets. |
29 | | // The WBMP format is terminal independent and describes only graphical information. |
30 | | |
31 | | // IMPLEMENTATION NOTES: |
32 | | // ------------------------ |
33 | | // The WBMP format is configured according to a type field value (TypeField below), |
34 | | // which maps to all relevant image encoding information, such as: |
35 | | // · Pixel organisation and encoding |
36 | | // · Palette organisation and encoding |
37 | | // · Compression characteristics |
38 | | // · Animation encoding |
39 | | // For each TypeField value, all relevant image characteristics are |
40 | | // fully specified as part of the WAP documentation. |
41 | | // Currently, a simple compact, monochrome image format is defined |
42 | | // within the WBMP type space : |
43 | | // |
44 | | // Image Type Identifier, multi-byte integer 0 |
45 | | // Image Format description 0 B/W, no compression |
46 | | // ------------------------------------------------------------------------------- |
47 | | |
48 | | // WBMP Header |
49 | | |
50 | | #ifdef _WIN32 |
51 | | #pragma pack(push, 1) |
52 | | #else |
53 | | #pragma pack(1) |
54 | | #endif |
55 | | |
56 | | typedef struct tagWBMPHEADER { |
57 | | WORD TypeField; // Image type identifier of multi-byte length |
58 | | BYTE FixHeaderField; // Octet of general header information |
59 | | BYTE ExtHeaderFields; // Zero or more extension header fields |
60 | | WORD Width; // Multi-byte width field |
61 | | WORD Height; // Multi-byte height field |
62 | | } WBMPHEADER; |
63 | | |
64 | | #ifdef _WIN32 |
65 | | #pragma pack(pop) |
66 | | #else |
67 | | #pragma pack() |
68 | | #endif |
69 | | |
70 | | // The extension headers may be of type binary 00 through binary 11, defined as follows. |
71 | | |
72 | | // - Type 00 indicates a multi-byte bitfield used to specify additional header information. |
73 | | // The first bit is set if a type 00, extension header is set if more data follows. |
74 | | // The other bits are reserved for future use. |
75 | | // - Type 01 - reserved for future use. |
76 | | // - Type 10 - reserved for future use. |
77 | | // - Type 11 indicates a sequence of parameter/value pairs. These can be used for |
78 | | // optimisations and special purpose extensions, eg, animation image formats. |
79 | | // The parameter size tells the length (1-8 bytes) of the following parameter name. |
80 | | // The value size gives the length (1-16 bytes) of the following parameter value. |
81 | | // The concatenation flag indicates whether another parameter/value pair will follow |
82 | | // after reading the specified bytes of data. |
83 | | |
84 | | // ========================================================== |
85 | | // Internal functions |
86 | | // ========================================================== |
87 | | |
88 | | static DWORD |
89 | 0 | multiByteRead(FreeImageIO *io, fi_handle handle) { |
90 | | // Multi-byte encoding / decoding |
91 | | // ------------------------------- |
92 | | // A multi-byte integer consists of a series of octets, where the most significant bit |
93 | | // is the continuation flag, and the remaining seven bits are a scalar value. |
94 | | // The continuation flag is used to indicate that an octet is not the end of the multi-byte |
95 | | // sequence. |
96 | |
|
97 | 0 | DWORD Out = 0; |
98 | 0 | BYTE In = 0; |
99 | |
|
100 | 0 | while (io->read_proc(&In, 1, 1, handle)) { |
101 | 0 | Out += (In & 0x7F); |
102 | |
|
103 | 0 | if ((In & 0x80) == 0x00) |
104 | 0 | break; |
105 | | |
106 | 0 | Out <<= 7; |
107 | 0 | } |
108 | |
|
109 | 0 | return Out; |
110 | 0 | } |
111 | | |
112 | | static void |
113 | 0 | multiByteWrite(FreeImageIO *io, fi_handle handle, DWORD In) { |
114 | 0 | BYTE Out, k = 1; |
115 | | |
116 | 0 | while (In & (0x7F << 7*k)) |
117 | 0 | k++; |
118 | | |
119 | 0 | while (k > 1) { |
120 | 0 | k--; |
121 | |
|
122 | 0 | Out = (BYTE)(0x80 | (In >> 7*k) & 0xFF); |
123 | |
|
124 | 0 | io->write_proc(&Out, 1, 1, handle); |
125 | 0 | } |
126 | |
|
127 | 0 | Out = (BYTE)(In & 0x7F); |
128 | |
|
129 | 0 | io->write_proc(&Out, 1, 1, handle); |
130 | 0 | } |
131 | | |
132 | | static void |
133 | 0 | readExtHeader(FreeImageIO *io, fi_handle handle, BYTE b) { |
134 | | // Extension header fields |
135 | | // ------------------------ |
136 | | // Read the extension header fields |
137 | | // (since we don't use them for the moment, we skip them). |
138 | |
|
139 | 0 | switch (b & 0x60) { |
140 | | // Type 00: read multi-byte bitfield |
141 | | |
142 | 0 | case 0x00: |
143 | 0 | { |
144 | 0 | DWORD info = multiByteRead(io, handle); |
145 | 0 | break; |
146 | 0 | } |
147 | | |
148 | | // Type 11: read a sequence of parameter/value pairs. |
149 | | |
150 | 0 | case 0x60: |
151 | 0 | { |
152 | 0 | BYTE sizeParamIdent = (b & 0x70) >> 4; // Size of Parameter Identifier (in bytes) |
153 | 0 | BYTE sizeParamValue = (b & 0x0F); // Size of Parameter Value (in bytes) |
154 | | |
155 | 0 | BYTE *Ident = (BYTE*)malloc(sizeParamIdent * sizeof(BYTE)); |
156 | 0 | BYTE *Value = (BYTE*)malloc(sizeParamValue * sizeof(BYTE)); |
157 | | |
158 | 0 | io->read_proc(Ident, sizeParamIdent, 1, handle); |
159 | 0 | io->read_proc(Value, sizeParamValue, 1, handle); |
160 | | |
161 | 0 | free(Ident); |
162 | 0 | free(Value); |
163 | 0 | break; |
164 | 0 | } |
165 | | |
166 | | // reserved for future use |
167 | | |
168 | 0 | case 0x20: // Type 01 |
169 | 0 | case 0x40: // Type 10 |
170 | 0 | break; |
171 | 0 | } |
172 | 0 | } |
173 | | |
174 | | // ========================================================== |
175 | | // Plugin Interface |
176 | | // ========================================================== |
177 | | |
178 | | static int s_format_id; |
179 | | |
180 | | // ========================================================== |
181 | | // Plugin Implementation |
182 | | // ========================================================== |
183 | | |
184 | | static const char * DLL_CALLCONV |
185 | 2 | Format() { |
186 | 2 | return "WBMP"; |
187 | 2 | } |
188 | | |
189 | | static const char * DLL_CALLCONV |
190 | 0 | Description() { |
191 | 0 | return "Wireless Bitmap"; |
192 | 0 | } |
193 | | |
194 | | static const char * DLL_CALLCONV |
195 | 0 | Extension() { |
196 | 0 | return "wap,wbmp,wbm"; |
197 | 0 | } |
198 | | |
199 | | static const char * DLL_CALLCONV |
200 | 0 | RegExpr() { |
201 | 0 | return NULL; |
202 | 0 | } |
203 | | |
204 | | static const char * DLL_CALLCONV |
205 | 0 | MimeType() { |
206 | 0 | return "image/vnd.wap.wbmp"; |
207 | 0 | } |
208 | | |
209 | | static BOOL DLL_CALLCONV |
210 | 0 | SupportsExportDepth(int depth) { |
211 | 0 | return ( |
212 | 0 | (depth == 1) |
213 | 0 | ); |
214 | 0 | } |
215 | | |
216 | | static BOOL DLL_CALLCONV |
217 | 0 | SupportsExportType(FREE_IMAGE_TYPE type) { |
218 | 0 | return (type == FIT_BITMAP) ? TRUE : FALSE; |
219 | 0 | } |
220 | | |
221 | | // ---------------------------------------------------------- |
222 | | |
223 | | static FIBITMAP * DLL_CALLCONV |
224 | 0 | Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { |
225 | 0 | WORD x, y, width, height; |
226 | 0 | FIBITMAP *dib; |
227 | 0 | BYTE *bits; // pointer to dib data |
228 | 0 | RGBQUAD *pal; // pointer to dib palette |
229 | |
|
230 | 0 | WBMPHEADER header; |
231 | |
|
232 | 0 | if (handle) { |
233 | 0 | try { |
234 | | // Read header information |
235 | | // ----------------------- |
236 | | |
237 | | // Type |
238 | |
|
239 | 0 | header.TypeField = (WORD)multiByteRead(io, handle); |
240 | |
|
241 | 0 | if (header.TypeField != 0) { |
242 | 0 | throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; |
243 | 0 | } |
244 | | |
245 | | // FixHeaderField |
246 | | |
247 | 0 | io->read_proc(&header.FixHeaderField, 1, 1, handle); |
248 | | |
249 | | // ExtHeaderFields |
250 | | // 1 = more will follow, 0 = last octet |
251 | |
|
252 | 0 | if (header.FixHeaderField & 0x80) { |
253 | 0 | header.ExtHeaderFields = 0x80; |
254 | |
|
255 | 0 | while(header.ExtHeaderFields & 0x80) { |
256 | 0 | io->read_proc(&header.ExtHeaderFields, 1, 1, handle); |
257 | |
|
258 | 0 | readExtHeader(io, handle, header.ExtHeaderFields); |
259 | 0 | } |
260 | 0 | } |
261 | | |
262 | | // width & height |
263 | |
|
264 | 0 | width = (WORD)multiByteRead(io, handle); |
265 | 0 | height = (WORD)multiByteRead(io, handle); |
266 | | |
267 | | // Allocate a new dib |
268 | |
|
269 | 0 | dib = FreeImage_Allocate(width, height, 1); |
270 | 0 | if (!dib) { |
271 | 0 | throw FI_MSG_ERROR_DIB_MEMORY; |
272 | 0 | } |
273 | | |
274 | | // write the palette data |
275 | | |
276 | 0 | pal = FreeImage_GetPalette(dib); |
277 | 0 | pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 0; |
278 | 0 | pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255; |
279 | | |
280 | | // read the bitmap data |
281 | | |
282 | 0 | int line = FreeImage_GetLine(dib); |
283 | |
|
284 | 0 | for (y = 0; y < height; y++) { |
285 | 0 | bits = FreeImage_GetScanLine(dib, height - 1 - y); |
286 | |
|
287 | 0 | for (x = 0; x < line; x++) { |
288 | 0 | io->read_proc(&bits[x], 1, 1, handle); |
289 | 0 | } |
290 | 0 | } |
291 | |
|
292 | 0 | return dib; |
293 | |
|
294 | 0 | } catch(const char *text) { |
295 | 0 | FreeImage_OutputMessageProc(s_format_id, text); |
296 | |
|
297 | 0 | return NULL; |
298 | 0 | } |
299 | |
|
300 | 0 | } |
301 | | |
302 | 0 | return NULL; |
303 | 0 | } |
304 | | |
305 | | static BOOL DLL_CALLCONV |
306 | 0 | Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) { |
307 | 0 | BYTE *bits; // pointer to dib data |
308 | |
|
309 | 0 | if ((dib) && (handle)) { |
310 | 0 | try { |
311 | 0 | if (FreeImage_GetBPP(dib) != 1) |
312 | 0 | throw "Only 1-bit depth bitmaps can be saved as WBMP"; |
313 | | |
314 | | // write the header |
315 | | |
316 | 0 | WBMPHEADER header; |
317 | 0 | header.TypeField = 0; // Type 0: B/W, no compression |
318 | 0 | header.FixHeaderField = 0; // No ExtHeaderField |
319 | 0 | header.Width = (WORD)FreeImage_GetWidth(dib); // Image width |
320 | 0 | header.Height = (WORD)FreeImage_GetHeight(dib); // Image height |
321 | |
|
322 | 0 | multiByteWrite(io, handle, header.TypeField); |
323 | | |
324 | 0 | io->write_proc(&header.FixHeaderField, 1, 1, handle); |
325 | |
|
326 | 0 | multiByteWrite(io, handle, header.Width); |
327 | 0 | multiByteWrite(io, handle, header.Height); |
328 | | |
329 | | // write the bitmap data |
330 | |
|
331 | 0 | WORD linelength = (WORD)FreeImage_GetLine(dib); |
332 | |
|
333 | 0 | for (WORD y = 0; y < header.Height; y++) { |
334 | 0 | bits = FreeImage_GetScanLine(dib, header.Height - 1 - y); |
335 | |
|
336 | 0 | io->write_proc(&bits[0], linelength, 1, handle); |
337 | 0 | } |
338 | |
|
339 | 0 | return TRUE; |
340 | |
|
341 | 0 | } catch (const char* text) { |
342 | 0 | FreeImage_OutputMessageProc(s_format_id, text); |
343 | 0 | } |
344 | 0 | } |
345 | | |
346 | 0 | return FALSE; |
347 | 0 | } |
348 | | |
349 | | // ========================================================== |
350 | | // Init |
351 | | // ========================================================== |
352 | | |
353 | | void DLL_CALLCONV |
354 | 2 | InitWBMP(Plugin *plugin, int format_id) { |
355 | 2 | s_format_id = format_id; |
356 | | |
357 | 2 | plugin->format_proc = Format; |
358 | 2 | plugin->description_proc = Description; |
359 | 2 | plugin->extension_proc = Extension; |
360 | 2 | plugin->regexpr_proc = RegExpr; |
361 | 2 | plugin->open_proc = NULL; |
362 | 2 | plugin->close_proc = NULL; |
363 | 2 | plugin->pagecount_proc = NULL; |
364 | 2 | plugin->pagecapability_proc = NULL; |
365 | 2 | plugin->load_proc = Load; |
366 | 2 | plugin->save_proc = Save; |
367 | 2 | plugin->validate_proc = NULL; |
368 | 2 | plugin->mime_proc = MimeType; |
369 | 2 | plugin->supports_export_bpp_proc = SupportsExportDepth; |
370 | 2 | plugin->supports_export_type_proc = SupportsExportType; |
371 | | plugin->supports_icc_profiles_proc = NULL; |
372 | 2 | } |