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