blob: cd850d1f933d102a4bbf8e207afea82fc3c1498b [file] [log] [blame]
Mats Lidell8a700fe2002-08-16 14:02:48 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19/*********************************************************************
20 *
21 * Converts BMP files to Rockbox bitmap format
22 *
23 * 1999-05-03 Linus Nielsen Feltzing
24 *
25 **********************************************/
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <stdbool.h>
31
32#include <sys/types.h>
33#include <sys/stat.h>
34#include <fcntl.h>
35
36#define debugf printf
37
38#ifdef __GNUC__
39#define STRUCT_PACKED __attribute__((packed))
40#else
41#define STRUCT_PACKED
42#pragma pack (push, 2)
43#endif
44
45struct Fileheader
46{
47 unsigned short Type; /* signature - 'BM' */
48 unsigned long Size; /* file size in bytes */
49 unsigned short Reserved1; /* 0 */
50 unsigned short Reserved2; /* 0 */
51 unsigned long OffBits; /* offset to bitmap */
52 unsigned long StructSize; /* size of this struct (40) */
53 unsigned long Width; /* bmap width in pixels */
54 unsigned long Height; /* bmap height in pixels */
55 unsigned short Planes; /* num planes - always 1 */
56 unsigned short BitCount; /* bits per pixel */
57 unsigned long Compression; /* compression flag */
58 unsigned long SizeImage; /* image size in bytes */
59 long XPelsPerMeter; /* horz resolution */
60 long YPelsPerMeter; /* vert resolution */
61 unsigned long ClrUsed; /* 0 -> color table size */
62 unsigned long ClrImportant; /* important color count */
63} STRUCT_PACKED;
64
65struct RGBQUAD
66{
67 unsigned char rgbBlue;
68 unsigned char rgbGreen;
69 unsigned char rgbRed;
70 unsigned char rgbReserved;
71} STRUCT_PACKED;
72
73#ifdef LITTLE_ENDIAN
74#define readshort(x) x
75#define readlong(x) x
76#else
77
78#define readshort(x) (((x&0xff00)>>8)|((x&0x00ff)<<8))
79#define readlong(x) (((x&0xff000000)>>24)| \
80 ((x&0x00ff0000)>>8) | \
81 ((x&0x0000ff00)<<8) | \
82 ((x&0x000000ff)<<24))
83#endif
84
85/*********************************************************************
86 * read_bmp_file()
87 *
88 * Reads a 8bit BMP file and puts the data in a 1-pixel-per-byte
89 * array. Returns 0 on success.
90 *
91 *********************************************************************/
92int read_bmp_file(char* filename,
93 int *get_width, /* in pixels */
94 int *get_height, /* in pixels */
95 char **bitmap)
96{
Daniel Stenberg793ca182002-08-21 12:11:51 +000097 struct Fileheader fh;
98 struct RGBQUAD palette[2]; /* two colors only */
Mats Lidell8a700fe2002-08-16 14:02:48 +000099
Daniel Stenberg793ca182002-08-21 12:11:51 +0000100 unsigned int bitmap_width, bitmap_height;
Mats Lidell8a700fe2002-08-16 14:02:48 +0000101
Daniel Stenberg793ca182002-08-21 12:11:51 +0000102 long PaddedWidth;
103 int background;
104 int fd = open(filename, O_RDONLY);
105 long size;
106 unsigned int row, col;
107 int l;
108 unsigned char *bmp;
109 int width;
110 int depth;
Mats Lidell8a700fe2002-08-16 14:02:48 +0000111
Daniel Stenberg793ca182002-08-21 12:11:51 +0000112 if(fd == -1)
113 {
114 debugf("error - can't open '%s'\n", filename);
115 return 1;
116 }
117 else
Mats Lidell8a700fe2002-08-16 14:02:48 +0000118 {
119 if(read(fd, &fh, sizeof(struct Fileheader)) !=
120 sizeof(struct Fileheader))
Daniel Stenberg793ca182002-08-21 12:11:51 +0000121 {
122 debugf("error - can't Read Fileheader Stucture\n");
123 close(fd);
124 return 2;
125 }
Mats Lidell8a700fe2002-08-16 14:02:48 +0000126
Daniel Stenberg793ca182002-08-21 12:11:51 +0000127 /* Exit if more than 8 bits */
128 depth = readshort(fh.BitCount);
129 if(depth > 8)
130 {
131 debugf("error - Bitmap uses more than 8 bit depth, got %d\n",
132 depth);
133 close(fd);
134 return 2;
135 }
Mats Lidell8a700fe2002-08-16 14:02:48 +0000136
Daniel Stenberg793ca182002-08-21 12:11:51 +0000137 /* Exit if too wide */
138 if(readlong(fh.Width) > 112)
139 {
140 debugf("error - Bitmap is too wide (%d pixels, max is 112)\n",
141 readlong(fh.Width));
142 close(fd);
143 return 3;
144 }
Mats Lidell8a700fe2002-08-16 14:02:48 +0000145
Daniel Stenberg793ca182002-08-21 12:11:51 +0000146 /* Exit if too high */
147 if(readlong(fh.Height) > 64)
148 {
149 debugf("error - Bitmap is too high (%d pixels, max is 64)\n",
150 readlong(fh.Height));
151 close(fd);
152 return 4;
153 }
154
155 for(l=0;l < 2;l++)
156 {
157 if(read(fd, &palette[l],sizeof(struct RGBQUAD)) !=
158 sizeof(struct RGBQUAD))
159 {
160 debugf("error - Can't read bitmap's color palette\n");
161 close(fd);
162 return 5;
163 }
164 }
165 if(depth == 8 ) {
166 /* pass the other palettes */
167 lseek(fd, 254*sizeof(struct RGBQUAD), SEEK_CUR);
168 }
Mats Lidell8a700fe2002-08-16 14:02:48 +0000169
Daniel Stenberg793ca182002-08-21 12:11:51 +0000170 /* Try to guess the foreground and background colors.
171 We assume that the foreground color is the darkest. */
172 if(((int)palette[0].rgbRed +
173 (int)palette[0].rgbGreen +
174 (int)palette[0].rgbBlue) >
175 ((int)palette[1].rgbRed +
176 (int)palette[1].rgbGreen +
177 (int)palette[1].rgbBlue))
178 {
Mats Lidell8a700fe2002-08-16 14:02:48 +0000179 background = 0;
Daniel Stenberg793ca182002-08-21 12:11:51 +0000180 }
181 else
182 {
Mats Lidell8a700fe2002-08-16 14:02:48 +0000183 background = 1;
Daniel Stenberg793ca182002-08-21 12:11:51 +0000184 }
Mats Lidell8a700fe2002-08-16 14:02:48 +0000185
186 width = readlong(fh.Width);
Daniel Stenberg793ca182002-08-21 12:11:51 +0000187
188 if(depth == 8)
189 PaddedWidth = ((width+3)&(~0x3)); /* aligned 4-bytes boundaries */
190 else
191 PaddedWidth = ((width+31)&(~0x1f))/8;
192
Mats Lidell8a700fe2002-08-16 14:02:48 +0000193 size = PaddedWidth*readlong(fh.Height);
194
195 bmp = (unsigned char *)malloc(size);
196 *bitmap = (unsigned char *)malloc(size);
197
198 if(bmp == NULL)
199 {
200 debugf("error - Out of memory\n");
201 close(fd);
202 return 6;
203 }
204 else
205 {
206 if(read(fd, (unsigned char*)bmp,(long)size) != size) {
207 debugf("error - Can't read image\n");
208 close(fd);
209 return 7;
210 }
211 }
212
213 bitmap_height = readlong(fh.Height);
214 bitmap_width = readlong(fh.Width);
215
216 *get_width = bitmap_width;
217 *get_height = bitmap_height;
218
Daniel Stenberg793ca182002-08-21 12:11:51 +0000219 if(depth == 8)
220 {
221 /* Now convert the bitmap into an array with 1 byte per pixel,
222 exactly the size of the image */
223 for(row = 0;row < bitmap_height;row++) {
224 for(col = 0;col < bitmap_width;col++) {
225 if(bmp[(bitmap_height-1 -row) * PaddedWidth + col]) {
226 (*bitmap)[ (row/8) * bitmap_width + col ] &=
227 ~ (1<<(row&7));
228 }
229 else {
230 (*bitmap)[ (row/8) * bitmap_width + col ] |=
231 1<<(row&7);
232 }
233 }
Mats Lidell8a700fe2002-08-16 14:02:48 +0000234 }
Daniel Stenberg793ca182002-08-21 12:11:51 +0000235 }
236 else
237 {
238 int bit;
239 int byte;
240 /* monocrome BMP conversion uses 8 pixels per byte */
241 for(row = 0; row < bitmap_height; row++) {
242 bit = 7;
243 byte = 0;
244 for(col = 0;col < bitmap_width;col++) {
245 if((bmp[(bitmap_height - row - 1) * PaddedWidth + byte] &
246 (1 << bit))) {
247 (*bitmap)[(row/8) * bitmap_width + col ] &=
248 ~(1<<(row&7));
249 }
250 else {
251 (*bitmap)[(row/8) * bitmap_width + col ] |=
252 1<<(row&7);
253 }
254 if(bit) {
255 bit--;
256 }
257 else {
258 bit = 7;
259 byte++;
260 }
261 }
Mats Lidell8a700fe2002-08-16 14:02:48 +0000262 }
Mats Lidell8a700fe2002-08-16 14:02:48 +0000263 }
264
265 free(bmp);
266
267 }
268 close(fd);
269 return 0; /* success */
270}
271
272/*********************************************************************
273** generate_c_source()
274**
275** Outputs a C source code with the bitmap in an array, accompanied by
276** some #define's
277**********************************************************************/
278void generate_c_source(char *id, int width, int height, unsigned char *bitmap)
279{
280 FILE *f;
281 unsigned int i, a, eline;
282
283 f = stdout;
284
Daniel Stenberg8c789752002-08-19 08:04:48 +0000285 if(!id || !id[0])
286 id = "bitmap";
287
288 fprintf(f,
289 "#define BMPHEIGHT_%s %d"
290 "\n#define BMPWIDTH_%s %d"
291 "\nconst unsigned char %s[] = {\n",
292 id, height, id, width, id );
Mats Lidell8a700fe2002-08-16 14:02:48 +0000293
294 for(i=0, eline=0; i< height; i+=8, eline++) {
Daniel Stenberge1fbb122002-08-21 16:34:41 +0000295 for (a=0; a<width; a++)
296 fprintf(f, "0x%02x,%c", bitmap[eline*width + a],
297 (a+1)%13?' ':'\n');
Mats Lidell8a700fe2002-08-16 14:02:48 +0000298 fprintf(f, "\n");
299 }
300
301
Mats Lidell4b12d882002-08-21 10:45:17 +0000302 fprintf(f, "\n};\n");
Mats Lidell8a700fe2002-08-16 14:02:48 +0000303}
304
305
306/*********************************************************************
307** generate_ascii()
308**
309** Outputs an ascii picture of the bitmap
310**********************************************************************/
311void generate_ascii(int width, int height, unsigned char *bitmap)
312{
313 FILE *f;
314 unsigned int i, eline;
315
316 f = stdout;
317
318 /* for screen output debugging */
319 for(i=0, eline=0; i< height; i+=8, eline++) {
320 unsigned int x, y;
321 for(y=0; y<8 && (i+y < height); y++) {
322 for(x=0; x < width; x++) {
323
324 if(bitmap[eline*width + x] & (1<<y)) {
325 fprintf(f, "*");
326 }
327 else
328 fprintf(f, " ");
329 }
330 fprintf(f, "\n");
331 }
332 }
333}
334
335void print_usage(void)
336{
337 printf("Usage: %s [-i <id>] [-a] <bitmap file>\n"
338 "\t-i <id> Bitmap name (default is filename without extension)\n"
339 "\t-a Show ascii picture of bitmap\n",
340 APPLICATION_NAME);
341 printf("build date: " __DATE__ "\n\n");
342}
343
344int main(int argc, char **argv)
345{
346 char *bmp_filename = NULL;
347 char *id = NULL;
348 int i;
349 int height, width;
350 int ascii = false;
351 char* bitmap = NULL;
352
353
354 for(i = 1;i < argc;i++)
355 {
356 if(argv[i][0] == '-')
357 {
358 switch(argv[i][1])
359 {
360 case 'i': /* ID */
361 if(argv[i][2])
362 {
363 id = &argv[i][2];
364 }
365 else if(argc > i+1)
366 {
367 id = argv[i+1];
368 i++;
369 }
370 else
371 {
372 print_usage();
373 exit(1);
374 }
375 break;
376
377 case 'a': /* Assembly */
378 ascii = true;
379 break;
380
381 default:
382 print_usage();
383 exit(1);
384 break;
385 }
386 }
387 else
388 {
389 if(!bmp_filename)
390 {
391 bmp_filename = argv[i];
392 }
393 else
394 {
395 print_usage();
396 exit(1);
397 }
398 }
399 }
400
401 if (!bmp_filename)
402 {
403 print_usage();
404 exit(1);
405 }
406
407 if (!id)
408 {
409 id = strdup(bmp_filename);
410 for (i = 0; id[i]; i++) if (id[i] == '.') id[i] = '\0';
411 }
412
413 if (read_bmp_file(bmp_filename, &width, &height, &bitmap))
414 return 0;
415
416 if (ascii)
417 generate_ascii(width, height, bitmap);
418 else
419 generate_c_source(id, width, height, bitmap);
420
421 return 0;
422}