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
multiByteRead(FreeImageIO * io,fi_handle handle)89 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 DWORD Out = 0;
98 BYTE In = 0;
99
100 while (io->read_proc(&In, 1, 1, handle)) {
101 Out += (In & 0x7F);
102
103 if ((In & 0x80) == 0x00)
104 break;
105
106 Out <<= 7;
107 }
108
109 return Out;
110 }
111
112 static void
multiByteWrite(FreeImageIO * io,fi_handle handle,DWORD In)113 multiByteWrite(FreeImageIO *io, fi_handle handle, DWORD In) {
114 BYTE Out, k = 1;
115
116 while (In & (0x7F << 7*k))
117 k++;
118
119 while (k > 1) {
120 k--;
121
122 Out = (BYTE)(0x80 | (In >> 7*k) & 0xFF);
123
124 io->write_proc(&Out, 1, 1, handle);
125 }
126
127 Out = (BYTE)(In & 0x7F);
128
129 io->write_proc(&Out, 1, 1, handle);
130 }
131
132 static void
readExtHeader(FreeImageIO * io,fi_handle handle,BYTE b)133 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 switch (b & 0x60) {
140 // Type 00: read multi-byte bitfield
141
142 case 0x00:
143 {
144 DWORD info = multiByteRead(io, handle);
145 break;
146 }
147
148 // Type 11: read a sequence of parameter/value pairs.
149
150 case 0x60:
151 {
152 BYTE sizeParamIdent = (b & 0x70) >> 4; // Size of Parameter Identifier (in bytes)
153 BYTE sizeParamValue = (b & 0x0F); // Size of Parameter Value (in bytes)
154
155 BYTE *Ident = (BYTE*)malloc(sizeParamIdent * sizeof(BYTE));
156 BYTE *Value = (BYTE*)malloc(sizeParamValue * sizeof(BYTE));
157
158 io->read_proc(Ident, sizeParamIdent, 1, handle);
159 io->read_proc(Value, sizeParamValue, 1, handle);
160
161 free(Ident);
162 free(Value);
163 break;
164 }
165
166 // reserved for future use
167
168 case 0x20: // Type 01
169 case 0x40: // Type 10
170 break;
171 }
172 }
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
Format()185 Format() {
186 return "WBMP";
187 }
188
189 static const char * DLL_CALLCONV
Description()190 Description() {
191 return "Wireless Bitmap";
192 }
193
194 static const char * DLL_CALLCONV
Extension()195 Extension() {
196 return "wap,wbmp,wbm";
197 }
198
199 static const char * DLL_CALLCONV
RegExpr()200 RegExpr() {
201 return NULL;
202 }
203
204 static const char * DLL_CALLCONV
MimeType()205 MimeType() {
206 return "image/vnd.wap.wbmp";
207 }
208
209 static BOOL DLL_CALLCONV
SupportsExportDepth(int depth)210 SupportsExportDepth(int depth) {
211 return (
212 (depth == 1)
213 );
214 }
215
216 static BOOL DLL_CALLCONV
SupportsExportType(FREE_IMAGE_TYPE type)217 SupportsExportType(FREE_IMAGE_TYPE type) {
218 return (type == FIT_BITMAP) ? TRUE : FALSE;
219 }
220
221 // ----------------------------------------------------------
222
223 static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO * io,fi_handle handle,int page,int flags,void * data)224 Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
225 WORD x, y, width, height;
226 FIBITMAP *dib;
227 BYTE *bits; // pointer to dib data
228 RGBQUAD *pal; // pointer to dib palette
229
230 WBMPHEADER header;
231
232 if (handle) {
233 try {
234 // Read header information
235 // -----------------------
236
237 // Type
238
239 header.TypeField = (WORD)multiByteRead(io, handle);
240
241 if (header.TypeField != 0) {
242 throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
243 }
244
245 // FixHeaderField
246
247 io->read_proc(&header.FixHeaderField, 1, 1, handle);
248
249 // ExtHeaderFields
250 // 1 = more will follow, 0 = last octet
251
252 if (header.FixHeaderField & 0x80) {
253 header.ExtHeaderFields = 0x80;
254
255 while(header.ExtHeaderFields & 0x80) {
256 io->read_proc(&header.ExtHeaderFields, 1, 1, handle);
257
258 readExtHeader(io, handle, header.ExtHeaderFields);
259 }
260 }
261
262 // width & height
263
264 width = (WORD)multiByteRead(io, handle);
265 height = (WORD)multiByteRead(io, handle);
266
267 // Allocate a new dib
268
269 dib = FreeImage_Allocate(width, height, 1);
270 if (!dib) {
271 throw FI_MSG_ERROR_DIB_MEMORY;
272 }
273
274 // write the palette data
275
276 pal = FreeImage_GetPalette(dib);
277 pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 0;
278 pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255;
279
280 // read the bitmap data
281
282 int line = FreeImage_GetLine(dib);
283
284 for (y = 0; y < height; y++) {
285 bits = FreeImage_GetScanLine(dib, height - 1 - y);
286
287 for (x = 0; x < line; x++) {
288 io->read_proc(&bits[x], 1, 1, handle);
289 }
290 }
291
292 return dib;
293
294 } catch(const char *text) {
295 FreeImage_OutputMessageProc(s_format_id, text);
296
297 return NULL;
298 }
299
300 }
301
302 return NULL;
303 }
304
305 static BOOL DLL_CALLCONV
Save(FreeImageIO * io,FIBITMAP * dib,fi_handle handle,int page,int flags,void * data)306 Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
307 BYTE *bits; // pointer to dib data
308
309 if ((dib) && (handle)) {
310 try {
311 if (FreeImage_GetBPP(dib) != 1)
312 throw "Only 1-bit depth bitmaps can be saved as WBMP";
313
314 // write the header
315
316 WBMPHEADER header;
317 header.TypeField = 0; // Type 0: B/W, no compression
318 header.FixHeaderField = 0; // No ExtHeaderField
319 header.Width = (WORD)FreeImage_GetWidth(dib); // Image width
320 header.Height = (WORD)FreeImage_GetHeight(dib); // Image height
321
322 multiByteWrite(io, handle, header.TypeField);
323
324 io->write_proc(&header.FixHeaderField, 1, 1, handle);
325
326 multiByteWrite(io, handle, header.Width);
327 multiByteWrite(io, handle, header.Height);
328
329 // write the bitmap data
330
331 WORD linelength = (WORD)FreeImage_GetLine(dib);
332
333 for (WORD y = 0; y < header.Height; y++) {
334 bits = FreeImage_GetScanLine(dib, header.Height - 1 - y);
335
336 io->write_proc(&bits[0], linelength, 1, handle);
337 }
338
339 return TRUE;
340
341 } catch (const char* text) {
342 FreeImage_OutputMessageProc(s_format_id, text);
343 }
344 }
345
346 return FALSE;
347 }
348
349 // ==========================================================
350 // Init
351 // ==========================================================
352
353 void DLL_CALLCONV
InitWBMP(Plugin * plugin,int format_id)354 InitWBMP(Plugin *plugin, int format_id) {
355 s_format_id = format_id;
356
357 plugin->format_proc = Format;
358 plugin->description_proc = Description;
359 plugin->extension_proc = Extension;
360 plugin->regexpr_proc = RegExpr;
361 plugin->open_proc = NULL;
362 plugin->close_proc = NULL;
363 plugin->pagecount_proc = NULL;
364 plugin->pagecapability_proc = NULL;
365 plugin->load_proc = Load;
366 plugin->save_proc = Save;
367 plugin->validate_proc = NULL;
368 plugin->mime_proc = MimeType;
369 plugin->supports_export_bpp_proc = SupportsExportDepth;
370 plugin->supports_export_type_proc = SupportsExportType;
371 plugin->supports_icc_profiles_proc = NULL;
372 }
373