1 //-----------------------------------------------------------------------------
2 //
3 // ImageLib Sources
4 // Copyright (C) 2000-2009 by Denton Woods
5 // Last modified: 03/07/2009
6 //
7 // Filename: src-IL/src/il_wbmp.c
8 //
9 // Description: Reads from a Wireless Bitmap (.wbmp) file.  Specs available from
10 //				http://www.ibm.com/developerworks/wireless/library/wi-wbmp/
11 //
12 //-----------------------------------------------------------------------------
13 
14 
15 #include "il_internal.h"
16 #ifndef IL_NO_WBMP
17 #include "il_bits.h"
18 
19 
20 ILboolean	iLoadWbmpInternal(void);
21 ILuint		WbmpGetMultibyte(void);
22 ILboolean	iSaveWbmpInternal(void);
23 
24 // Reads a .wbmp file
ilLoadWbmp(ILconst_string FileName)25 ILboolean ilLoadWbmp(ILconst_string FileName)
26 {
27 	ILHANDLE	WbmpFile;
28 	ILboolean	bWbmp = IL_FALSE;
29 
30 	WbmpFile = iopenr(FileName);
31 	if (WbmpFile == NULL) {
32 		ilSetError(IL_COULD_NOT_OPEN_FILE);
33 		return bWbmp;
34 	}
35 
36 	iSetInputFile(WbmpFile);
37 
38 	bWbmp = ilLoadWbmpF(WbmpFile);
39 
40 	icloser(WbmpFile);
41 
42 	return bWbmp;
43 }
44 
45 
46 //! Reads an already-opened .wbmp file
ilLoadWbmpF(ILHANDLE File)47 ILboolean ilLoadWbmpF(ILHANDLE File)
48 {
49 	ILuint		FirstPos;
50 	ILboolean	bRet;
51 
52 	iSetInputFile(File);
53 	FirstPos = itell();
54 	bRet = iLoadWbmpInternal();
55 	iseek(FirstPos, IL_SEEK_SET);
56 
57 	return bRet;
58 }
59 
60 
61 //! Reads from a memory "lump" that contains a .wbmp
ilLoadWbmpL(const void * Lump,ILuint Size)62 ILboolean ilLoadWbmpL(const void *Lump, ILuint Size)
63 {
64 	iSetInputLump(Lump, Size);
65 	return iLoadWbmpInternal();
66 }
67 
68 
iLoadWbmpInternal(void)69 ILboolean iLoadWbmpInternal(void)
70 {
71 	ILuint	Width, Height, BitPadding, i;
72 	BITFILE	*File;
73 	ILubyte	Padding[8];
74 
75 	if (iCurImage == NULL) {
76 		ilSetError(IL_ILLEGAL_OPERATION);
77 		return IL_FALSE;
78 	}
79 
80 	if (igetc() != 0 || igetc() != 0) {  // The first two bytes have to be 0 (the "header")
81 		ilSetError(IL_INVALID_FILE_HEADER);
82 		return IL_FALSE;
83 	}
84 
85 	Width = WbmpGetMultibyte();  // Next follows the width and height.
86 	Height = WbmpGetMultibyte();
87 
88 	if (Width == 0 || Height == 0) {  // Must have at least some height and width.
89 		ilSetError(IL_INVALID_FILE_HEADER);
90 		return IL_FALSE;
91 	}
92 
93 	if (!ilTexImage(Width, Height, 1, 1, IL_LUMINANCE, IL_UNSIGNED_BYTE, NULL))
94 		return IL_FALSE;
95 	iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;  // Always has origin in the upper left.
96 
97 	BitPadding = (8 - (Width % 8)) % 8;  // Has to be aligned on a byte boundary.  The rest is padding.
98 	File = bfile(iGetFile());
99 	if (File == NULL)
100 		return IL_FALSE;  //@TODO: Error?
101 
102 	//@TODO: Do this without bread?  Would be faster, since we would not have to do
103 	//  the second loop.
104 
105 	// Reads the bits
106 	for (i = 0; i < iCurImage->Height; i++) {
107 		bread(&iCurImage->Data[iCurImage->Width * i], 1, iCurImage->Width, File);
108 		//bseek(File, BitPadding, IL_SEEK_CUR);  //@TODO: This function does not work correctly.
109 		bread(Padding, 1, BitPadding, File);  // Skip padding bits.
110 	}
111 	// Converts bit value of 1 to white and leaves 0 at 0 (2-colour images only).
112 	for (i = 0; i < iCurImage->SizeOfData; i++) {
113 		if (iCurImage->Data[i] == 1)
114 			iCurImage->Data[i] = 0xFF;  // White
115 	}
116 
117 	bclose(File);
118 
119 	return IL_TRUE;
120 }
121 
122 
WbmpGetMultibyte()123 ILuint WbmpGetMultibyte()
124 {
125 	ILuint Val = 0, i;
126 	ILubyte Cur;
127 
128 	for (i = 0; i < 5; i++) {  // Should not be more than 5 bytes.
129 		Cur = igetc();
130 		Val = (Val << 7) | (Cur & 0x7F);  // Drop the MSB of Cur.
131 		if (!(Cur & 0x80)) {  // Check the MSB and break if 0.
132 			break;
133 		}
134 	}
135 
136 	return Val;
137 }
138 
139 
WbmpPutMultibyte(ILuint Val)140 ILboolean WbmpPutMultibyte(ILuint Val)
141 {
142 	ILint	i, NumBytes = 0;
143 	ILuint	MultiVal = Val;
144 
145 	do {
146 		MultiVal >>= 7;
147 		NumBytes++;
148 	} while (MultiVal != 0);
149 
150 	for (i = NumBytes - 1; i >= 0; i--) {
151 		MultiVal = (Val >> (i * 7)) & 0x7F;
152 		if (i != 0)
153 			MultiVal |= 0x80;
154 		iputc(MultiVal);
155 	}
156 
157 	return IL_TRUE;
158 }
159 
160 
161 //! Writes a Wbmp file
ilSaveWbmp(const ILstring FileName)162 ILboolean ilSaveWbmp(const ILstring FileName)
163 {
164 	ILHANDLE	WbmpFile;
165 	ILuint		WbmpSize;
166 
167 	if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
168 		if (iFileExists(FileName)) {
169 			ilSetError(IL_FILE_ALREADY_EXISTS);
170 			return IL_FALSE;
171 		}
172 	}
173 
174 	WbmpFile = iopenw(FileName);
175 	if (WbmpFile == NULL) {
176 		ilSetError(IL_COULD_NOT_OPEN_FILE);
177 		return IL_FALSE;
178 	}
179 
180 	WbmpSize = ilSaveWbmpF(WbmpFile);
181 	iclosew(WbmpFile);
182 
183 	if (WbmpSize == 0)
184 		return IL_FALSE;
185 	return IL_TRUE;
186 }
187 
188 
189 //! Writes a .wbmp to an already-opened file
ilSaveWbmpF(ILHANDLE File)190 ILuint ilSaveWbmpF(ILHANDLE File)
191 {
192 	ILuint Pos;
193 	iSetOutputFile(File);
194 	Pos = itellw();
195 	if (iSaveWbmpInternal() == IL_FALSE)
196 		return 0;  // Error occurred
197 	return itellw() - Pos;  // Return the number of bytes written.
198 }
199 
200 
201 //! Writes a .wbmp to a memory "lump"
ilSaveWbmpL(void * Lump,ILuint Size)202 ILuint ilSaveWbmpL(void *Lump, ILuint Size)
203 {
204 	ILuint Pos;
205 	iSetOutputLump(Lump, Size);
206 	Pos = itellw();
207 	if (iSaveWbmpInternal() == IL_FALSE)
208 		return 0;  // Error occurred
209 	return itellw() - Pos;  // Return the number of bytes written.
210 }
211 
212 
213 // In il_quantizer.c
214 ILimage *iQuantizeImage(ILimage *Image, ILuint NumCols);
215 // In il_neuquant.c
216 ILimage *iNeuQuant(ILimage *Image, ILuint NumCols);
217 
218 
219 // Internal function used to save the Wbmp.
iSaveWbmpInternal()220 ILboolean iSaveWbmpInternal()
221 {
222 	ILimage	*TempImage = NULL;
223 	ILuint	i, j;
224 	ILint	k;
225 	ILubyte	Val;
226 	ILubyte	*TempData;
227 
228 	iputc(0);  // First two header values
229 	iputc(0);  //  must be 0.
230 
231 	WbmpPutMultibyte(iCurImage->Width);  // Write the width
232 	WbmpPutMultibyte(iCurImage->Height); //  and the height.
233 
234 	//TempImage = iConvertImage(iCurImage, IL_LUMINANCE, IL_UNSIGNED_BYTE);
235 	if (iGetInt(IL_QUANTIZATION_MODE) == IL_NEU_QUANT)
236 		TempImage = iNeuQuant(iCurImage, 2);
237 	else // Assume IL_WU_QUANT otherwise.
238 		TempImage = iQuantizeImage(iCurImage, 2);
239 
240 	if (TempImage == NULL)
241 		return IL_FALSE;
242 
243 	if (TempImage->Origin != IL_ORIGIN_UPPER_LEFT) {
244 		TempData = iGetFlipped(TempImage);
245 		if (TempData == NULL) {
246 			ilCloseImage(TempImage);
247 			return IL_FALSE;
248 		}
249 	} else {
250 		TempData = TempImage->Data;
251 	}
252 
253 	for (i = 0; i < TempImage->Height; i++) {
254 		for (j = 0; j < TempImage->Width; j += 8) {
255 			Val = 0;
256 			for (k = 0; k < 8; k++) {
257 				if (j + k < TempImage->Width) {
258 					//Val |= ((TempData[TempImage->Width * i + j + k] > 0x7F) ? (0x80 >> k) : 0x00);
259 					Val |= ((TempData[TempImage->Width * i + j + k] == 1) ? (0x80 >> k) : 0x00);
260 				}
261 			}
262 			iputc(Val);
263 		}
264 	}
265 
266 	if (TempData != TempImage->Data)
267 		ifree(TempData);
268 	ilCloseImage(TempImage);
269 
270 	return IL_TRUE;
271 }
272 
273 #endif//IL_NO_WBMP
274 
275