blob: 18b37f9cf65d00f4cdd219198242d93f89c7eb73 [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
Mats Lidell8a700fe2002-08-16 14:02:48 +000073
Daniel Stenberg2d81cf92003-05-21 06:31:44 +000074short readshort(void* value)
75{
76 unsigned char* bytes = (unsigned char*) value;
77 return bytes[0] | (bytes[1] << 8);
78}
79
80int readlong(void* value)
81{
82 unsigned char* bytes = (unsigned char*) value;
83 return bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24);
84}
Mats Lidell8a700fe2002-08-16 14:02:48 +000085
86/*********************************************************************
87 * read_bmp_file()
88 *
89 * Reads a 8bit BMP file and puts the data in a 1-pixel-per-byte
90 * array. Returns 0 on success.
91 *
92 *********************************************************************/
93int read_bmp_file(char* filename,
94 int *get_width, /* in pixels */
95 int *get_height, /* in pixels */
96 char **bitmap)
97{
Daniel Stenberg793ca182002-08-21 12:11:51 +000098 struct Fileheader fh;
99 struct RGBQUAD palette[2]; /* two colors only */
Mats Lidell8a700fe2002-08-16 14:02:48 +0000100
Daniel Stenberg793ca182002-08-21 12:11:51 +0000101 unsigned int bitmap_width, bitmap_height;
Mats Lidell8a700fe2002-08-16 14:02:48 +0000102
Daniel Stenberg793ca182002-08-21 12:11:51 +0000103 long PaddedWidth;
104 int background;
105 int fd = open(filename, O_RDONLY);
106 long size;
107 unsigned int row, col;
108 int l;
109 unsigned char *bmp;
110 int width;
111 int depth;
Mats Lidell8a700fe2002-08-16 14:02:48 +0000112
Daniel Stenberg793ca182002-08-21 12:11:51 +0000113 if(fd == -1)
114 {
115 debugf("error - can't open '%s'\n", filename);
116 return 1;
117 }
118 else
Mats Lidell8a700fe2002-08-16 14:02:48 +0000119 {
120 if(read(fd, &fh, sizeof(struct Fileheader)) !=
121 sizeof(struct Fileheader))
Daniel Stenberg793ca182002-08-21 12:11:51 +0000122 {
123 debugf("error - can't Read Fileheader Stucture\n");
124 close(fd);
125 return 2;
126 }
Mats Lidell8a700fe2002-08-16 14:02:48 +0000127
Daniel Stenberg793ca182002-08-21 12:11:51 +0000128 /* Exit if more than 8 bits */
Daniel Stenberg2d81cf92003-05-21 06:31:44 +0000129 depth = readshort(&fh.BitCount);
Daniel Stenberg793ca182002-08-21 12:11:51 +0000130 if(depth > 8)
131 {
132 debugf("error - Bitmap uses more than 8 bit depth, got %d\n",
133 depth);
134 close(fd);
135 return 2;
136 }
Mats Lidell8a700fe2002-08-16 14:02:48 +0000137
Daniel Stenberg793ca182002-08-21 12:11:51 +0000138 /* Exit if too wide */
Daniel Stenberg2d81cf92003-05-21 06:31:44 +0000139 if(readlong(&fh.Width) > 112)
Daniel Stenberg793ca182002-08-21 12:11:51 +0000140 {
141 debugf("error - Bitmap is too wide (%d pixels, max is 112)\n",
Daniel Stenberg2d81cf92003-05-21 06:31:44 +0000142 readlong(&fh.Width));
Daniel Stenberg793ca182002-08-21 12:11:51 +0000143 close(fd);
144 return 3;
145 }
Mats Lidell8a700fe2002-08-16 14:02:48 +0000146
Daniel Stenberg793ca182002-08-21 12:11:51 +0000147 /* Exit if too high */
Daniel Stenberg2d81cf92003-05-21 06:31:44 +0000148 if(readlong(&fh.Height) > 64)
Daniel Stenberg793ca182002-08-21 12:11:51 +0000149 {
150 debugf("error - Bitmap is too high (%d pixels, max is 64)\n",
Daniel Stenberg2d81cf92003-05-21 06:31:44 +0000151 readlong(&fh.Height));
Daniel Stenberg793ca182002-08-21 12:11:51 +0000152 close(fd);
153 return 4;
154 }
155
156 for(l=0;l < 2;l++)
157 {
158 if(read(fd, &palette[l],sizeof(struct RGBQUAD)) !=
159 sizeof(struct RGBQUAD))
160 {
161 debugf("error - Can't read bitmap's color palette\n");
162 close(fd);
163 return 5;
164 }
165 }
166 if(depth == 8 ) {
167 /* pass the other palettes */
168 lseek(fd, 254*sizeof(struct RGBQUAD), SEEK_CUR);
169 }
Mats Lidell8a700fe2002-08-16 14:02:48 +0000170
Daniel Stenberg793ca182002-08-21 12:11:51 +0000171 /* Try to guess the foreground and background colors.
172 We assume that the foreground color is the darkest. */
173 if(((int)palette[0].rgbRed +
174 (int)palette[0].rgbGreen +
175 (int)palette[0].rgbBlue) >
176 ((int)palette[1].rgbRed +
177 (int)palette[1].rgbGreen +
178 (int)palette[1].rgbBlue))
179 {
Mats Lidell8a700fe2002-08-16 14:02:48 +0000180 background = 0;
Daniel Stenberg793ca182002-08-21 12:11:51 +0000181 }
182 else
183 {
Mats Lidell8a700fe2002-08-16 14:02:48 +0000184 background = 1;
Daniel Stenberg793ca182002-08-21 12:11:51 +0000185 }
Mats Lidell8a700fe2002-08-16 14:02:48 +0000186
Daniel Stenberg2d81cf92003-05-21 06:31:44 +0000187 width = readlong(&fh.Width);
Daniel Stenberg793ca182002-08-21 12:11:51 +0000188
189 if(depth == 8)
190 PaddedWidth = ((width+3)&(~0x3)); /* aligned 4-bytes boundaries */
191 else
192 PaddedWidth = ((width+31)&(~0x1f))/8;
193
Daniel Stenberg2d81cf92003-05-21 06:31:44 +0000194 size = PaddedWidth*readlong(&fh.Height);
Mats Lidell8a700fe2002-08-16 14:02:48 +0000195
196 bmp = (unsigned char *)malloc(size);
197 *bitmap = (unsigned char *)malloc(size);
198
199 if(bmp == NULL)
200 {
201 debugf("error - Out of memory\n");
202 close(fd);
203 return 6;
204 }
205 else
206 {
207 if(read(fd, (unsigned char*)bmp,(long)size) != size) {
208 debugf("error - Can't read image\n");
209 close(fd);
210 return 7;
211 }
212 }
213
Daniel Stenberg2d81cf92003-05-21 06:31:44 +0000214 bitmap_height = readlong(&fh.Height);
215 bitmap_width = readlong(&fh.Width);
Mats Lidell8a700fe2002-08-16 14:02:48 +0000216
217 *get_width = bitmap_width;
218 *get_height = bitmap_height;
219
Daniel Stenberg793ca182002-08-21 12:11:51 +0000220 if(depth == 8)
221 {
222 /* Now convert the bitmap into an array with 1 byte per pixel,
223 exactly the size of the image */
224 for(row = 0;row < bitmap_height;row++) {
225 for(col = 0;col < bitmap_width;col++) {
226 if(bmp[(bitmap_height-1 -row) * PaddedWidth + col]) {
227 (*bitmap)[ (row/8) * bitmap_width + col ] &=
228 ~ (1<<(row&7));
229 }
230 else {
231 (*bitmap)[ (row/8) * bitmap_width + col ] |=
232 1<<(row&7);
233 }
234 }
Mats Lidell8a700fe2002-08-16 14:02:48 +0000235 }
Daniel Stenberg793ca182002-08-21 12:11:51 +0000236 }
237 else
238 {
239 int bit;
240 int byte;
241 /* monocrome BMP conversion uses 8 pixels per byte */
242 for(row = 0; row < bitmap_height; row++) {
243 bit = 7;
244 byte = 0;
245 for(col = 0;col < bitmap_width;col++) {
246 if((bmp[(bitmap_height - row - 1) * PaddedWidth + byte] &
247 (1 << bit))) {
248 (*bitmap)[(row/8) * bitmap_width + col ] &=
249 ~(1<<(row&7));
250 }
251 else {
252 (*bitmap)[(row/8) * bitmap_width + col ] |=
253 1<<(row&7);
254 }
255 if(bit) {
256 bit--;
257 }
258 else {
259 bit = 7;
260 byte++;
261 }
262 }
Mats Lidell8a700fe2002-08-16 14:02:48 +0000263 }
Mats Lidell8a700fe2002-08-16 14:02:48 +0000264 }
265
266 free(bmp);
267
268 }
269 close(fd);
270 return 0; /* success */
271}
272
273/*********************************************************************
274** generate_c_source()
275**
276** Outputs a C source code with the bitmap in an array, accompanied by
277** some #define's
278**********************************************************************/
279void generate_c_source(char *id, int width, int height, unsigned char *bitmap)
280{
281 FILE *f;
282 unsigned int i, a, eline;
283
284 f = stdout;
285
Daniel Stenberg8c789752002-08-19 08:04:48 +0000286 if(!id || !id[0])
287 id = "bitmap";
288
289 fprintf(f,
290 "#define BMPHEIGHT_%s %d"
291 "\n#define BMPWIDTH_%s %d"
292 "\nconst unsigned char %s[] = {\n",
293 id, height, id, width, id );
Mats Lidell8a700fe2002-08-16 14:02:48 +0000294
295 for(i=0, eline=0; i< height; i+=8, eline++) {
Daniel Stenberge1fbb122002-08-21 16:34:41 +0000296 for (a=0; a<width; a++)
297 fprintf(f, "0x%02x,%c", bitmap[eline*width + a],
298 (a+1)%13?' ':'\n');
Mats Lidell8a700fe2002-08-16 14:02:48 +0000299 fprintf(f, "\n");
300 }
301
302
Mats Lidell4b12d882002-08-21 10:45:17 +0000303 fprintf(f, "\n};\n");
Mats Lidell8a700fe2002-08-16 14:02:48 +0000304}
305
306
307/*********************************************************************
308** generate_ascii()
309**
310** Outputs an ascii picture of the bitmap
311**********************************************************************/
312void generate_ascii(int width, int height, unsigned char *bitmap)
313{
314 FILE *f;
315 unsigned int i, eline;
316
317 f = stdout;
318
319 /* for screen output debugging */
320 for(i=0, eline=0; i< height; i+=8, eline++) {
321 unsigned int x, y;
322 for(y=0; y<8 && (i+y < height); y++) {
323 for(x=0; x < width; x++) {
324
325 if(bitmap[eline*width + x] & (1<<y)) {
326 fprintf(f, "*");
327 }
328 else
329 fprintf(f, " ");
330 }
331 fprintf(f, "\n");
332 }
333 }
334}
335
336void print_usage(void)
337{
338 printf("Usage: %s [-i <id>] [-a] <bitmap file>\n"
339 "\t-i <id> Bitmap name (default is filename without extension)\n"
340 "\t-a Show ascii picture of bitmap\n",
341 APPLICATION_NAME);
342 printf("build date: " __DATE__ "\n\n");
343}
344
345int main(int argc, char **argv)
346{
347 char *bmp_filename = NULL;
348 char *id = NULL;
349 int i;
350 int height, width;
351 int ascii = false;
352 char* bitmap = NULL;
353
354
355 for(i = 1;i < argc;i++)
356 {
357 if(argv[i][0] == '-')
358 {
359 switch(argv[i][1])
360 {
361 case 'i': /* ID */
362 if(argv[i][2])
363 {
364 id = &argv[i][2];
365 }
366 else if(argc > i+1)
367 {
368 id = argv[i+1];
369 i++;
370 }
371 else
372 {
373 print_usage();
374 exit(1);
375 }
376 break;
377
378 case 'a': /* Assembly */
379 ascii = true;
380 break;
381
382 default:
383 print_usage();
384 exit(1);
385 break;
386 }
387 }
388 else
389 {
390 if(!bmp_filename)
391 {
392 bmp_filename = argv[i];
393 }
394 else
395 {
396 print_usage();
397 exit(1);
398 }
399 }
400 }
401
402 if (!bmp_filename)
403 {
404 print_usage();
405 exit(1);
406 }
407
408 if (!id)
409 {
Daniel Stenberge86218b2003-03-19 21:42:50 +0000410 char *ptr=strrchr(bmp_filename, '/');
411 if(ptr)
412 ptr++;
413 else
414 ptr = bmp_filename;
415 id = strdup(ptr);
416 for (i = 0; id[i]; i++)
417 if (id[i] == '.')
418 id[i] = '\0';
Mats Lidell8a700fe2002-08-16 14:02:48 +0000419 }
420
421 if (read_bmp_file(bmp_filename, &width, &height, &bitmap))
422 return 0;
423
424 if (ascii)
425 generate_ascii(width, height, bitmap);
426 else
427 generate_c_source(id, width, height, bitmap);
428
429 return 0;
430}