summaryrefslogtreecommitdiff
path: root/apps/bmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/bmp.c')
-rw-r--r--apps/bmp.c584
1 files changed, 584 insertions, 0 deletions
diff --git a/apps/bmp.c b/apps/bmp.c
new file mode 100644
index 0000000000..828f855295
--- /dev/null
+++ b/apps/bmp.c
@@ -0,0 +1,584 @@
1/***************************************************************************
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 "file.h"
33
34#ifdef __GNUC__
35#define STRUCT_PACKED __attribute__((packed))
36#endif
37
38struct Fileheader
39{
40 unsigned short Type; /* signature - 'BM' */
41 unsigned long Size; /* file size in bytes */
42 unsigned short Reserved1; /* 0 */
43 unsigned short Reserved2; /* 0 */
44 unsigned long OffBits; /* offset to bitmap */
45 unsigned long StructSize; /* size of this struct (40) */
46 unsigned long Width; /* bmap width in pixels */
47 unsigned long Height; /* bmap height in pixels */
48 unsigned short Planes; /* num planes - always 1 */
49 unsigned short BitCount; /* bits per pixel */
50 unsigned long Compression; /* compression flag */
51 unsigned long SizeImage; /* image size in bytes */
52 long XPelsPerMeter; /* horz resolution */
53 long YPelsPerMeter; /* vert resolution */
54 unsigned long ClrUsed; /* 0 -> color table size */
55 unsigned long ClrImportant; /* important color count */
56} STRUCT_PACKED;
57
58struct RGBQUAD
59{
60 unsigned char rgbBlue;
61 unsigned char rgbGreen;
62 unsigned char rgbRed;
63 unsigned char rgbReserved;
64} STRUCT_PACKED;
65
66static struct Fileheader fh;
67static unsigned char* bmp;
68static struct RGBQUAD palette[2]; /* two colors only */
69
70static unsigned int bitmap_width, bitmap_height;
71static unsigned char *bitmap;
72
73#ifdef STANDALONE
74static id_str[256];
75static bool compress = false;
76static bool assembly = false;
77static unsigned char* converted_bmp;
78static unsigned char* compressed_bmp;
79static unsigned int width;
80static unsigned int converted_size;
81static unsigned int compressed_size;
82static unsigned int rounded_width;
83#endif
84
85#ifdef LITTLE_ENDIAN
86#define readshort(x) x
87#define readlong(x) x
88#else
89
90#define readshort(x) (((x&0xff00)>>8)|((x&0x00ff)<<8))
91#define readlong(x) (((x&0xff000000)>>24)| \
92 ((x&0x00ff0000)>>8) | \
93 ((x&0x0000ff00)<<8) | \
94 ((x&0x000000ff)<<24))
95#endif
96
97/*********************************************************************
98 * read_bmp_file()
99 *
100 * Reads a monochrome BMP file and puts the data in a 1-pixel-per-byte
101 * array. Returns 0 on success.
102 *
103 **********************************************/
104int read_bmp_file(char* filename,
105 int *get_width, /* in pixels */
106 int *get_height, /* in pixels */
107 char *bitmap)
108{
109 long PaddedWidth;
110 int background;
111 int fd = open(filename, O_RDONLY);
112 long size;
113 unsigned int row, col, byte, bit;
114 int l;
115 unsigned char *bmp;
116 int width;
117 int height;
118
119 if(fd == -1)
120 {
121 debugf("error - can't open '%s'\n", filename);
122 return 1;
123 }
124 else
125 {
126 if(read(fd, &fh, sizeof(struct Fileheader)) !=
127 sizeof(struct Fileheader))
128 {
129 debugf("error - can't Read Fileheader Stucture\n");
130 close(fd);
131 return 2;
132 }
133
134 /* Exit if not monochrome */
135 if(readshort(fh.BitCount) > 8)
136 {
137 debugf("error - Bitmap must be less than 8, got %d\n",
138 readshort(fh.BitCount));
139 close(fd);
140 return 2;
141 }
142
143 /* Exit if too wide */
144 if(readlong(fh.Width) > 112)
145 {
146 debugf("error - Bitmap is too wide (%d pixels, max is 112)\n",
147 readlong(fh.Width));
148 close(fd);
149 return 3;
150 }
151 debugf("Bitmap is %d pixels wide\n", readlong(fh.Width));
152
153 /* Exit if too high */
154 if(readlong(fh.Height) > 64)
155 {
156 debugf("error - Bitmap is too high (%d pixels, max is 64)\n",
157 readlong(fh.Height));
158 close(fd);
159 return 4;
160 }
161 debugf("Bitmap is %d pixels heigh\n", readlong(fh.Height));
162
163 for(l=0;l < 2;l++)
164 {
165 if(read(fd, &palette[l],sizeof(struct RGBQUAD)) !=
166 sizeof(struct RGBQUAD))
167 {
168 debugf("error - Can't read bitmap's color palette\n");
169 close(fd);
170 return 5;
171 }
172 }
173 /* pass the other palettes */
174 lseek(fd, 254*sizeof(struct RGBQUAD), SEEK_CUR);
175
176 /* Try to guess the foreground and background colors.
177 We assume that the foreground color is the darkest. */
178 if(((int)palette[0].rgbRed +
179 (int)palette[0].rgbGreen +
180 (int)palette[0].rgbBlue) >
181 ((int)palette[1].rgbRed +
182 (int)palette[1].rgbGreen +
183 (int)palette[1].rgbBlue))
184 {
185 background = 0;
186 }
187 else
188 {
189 background = 1;
190 }
191
192 /* width = readlong(fh.Width)*readshort(fh.BitCount); */
193
194 width = readlong(fh.Width);
195
196 /* PaddedWidth = ((width+31)&(~0x1f))/8; */
197 PaddedWidth = ((width+7)&(~0x7));
198 size = PaddedWidth*readlong(fh.Height);
199
200 bmp = (unsigned char *)malloc(size);
201
202 if(bmp == NULL)
203 {
204 debugf("error - Out of memory\n");
205 close(fd);
206 return 6;
207 }
208 else
209 {
210 if(read(fd, (unsigned char*)bmp,(long)size) != size) {
211 debugf("error - Can't read image\n");
212 close(fd);
213 return 7;
214 }
215 }
216
217 bitmap_height = readlong(fh.Height);
218 bitmap_width = readlong(fh.Width);
219
220 *get_width = bitmap_width;
221 *get_height = bitmap_height;
222
223#if 0
224 /* Now convert the bitmap into an array with 1 byte per pixel,
225 exactly the size of the image */
226 for(row = 0;row < bitmap_height;row++) {
227 bit = 7;
228 byte = 0;
229 for(col = 0;col < bitmap_width;col++) {
230 if((bmp[(bitmap_height - row - 1) * PaddedWidth + byte] &
231 (1 << bit))) {
232
233 bitmap[ (row/8) * bitmap_width + col ] |= 1<<(row&7);
234 }
235 else {
236 bitmap[ (row/8) * bitmap_width + col ] &= ~ 1<<(row&7);
237 }
238 if(bit) {
239 bit--;
240 }
241 else {
242 bit = 7;
243 byte++;
244 }
245 }
246 }
247#else
248 /* Now convert the bitmap into an array with 1 byte per pixel,
249 exactly the size of the image */
250
251 for(row = 0;row < bitmap_height;row++) {
252 for(col = 0;col < bitmap_width;col++) {
253 if(bmp[(bitmap_height-1 -row) * PaddedWidth + col]) {
254 bitmap[ (row/8) * bitmap_width + col ] &= ~ (1<<(row&7));
255 }
256 else {
257 bitmap[ (row/8) * bitmap_width + col ] |= 1<<(row&7);
258 }
259 }
260 }
261
262#endif
263 }
264 close(fd);
265 return 0; /* success */
266}
267
268#ifdef STANDALONE
269
270/*********************************************************************
271** read_next_converted_byte()
272**
273** Reads the next 6-pixel chunk from the 1-byte-per-pixel array,
274** padding the last byte with zeros if the size is not divisible by 6.
275**********************************************/
276unsigned char read_next_converted_byte(void)
277{
278 unsigned char dest;
279 unsigned int i;
280 static unsigned int row = 0, col = 0;
281
282 dest = 0;
283 for(i = 0;i < 6 && col < bitmap_width;i++,col++)
284 {
285 if(bitmap[row * bitmap_width + col])
286 {
287 dest |= (unsigned char)(1 << (5-i));
288 }
289 }
290
291 if(col >= bitmap_width)
292 {
293 col = 0;
294 row++;
295 }
296
297 return dest;
298}
299
300/*********************************************************************
301** convert_image()
302**
303** Converts the 1-byte-per-pixel array into a 6-pixel-per-byte array,
304** i.e the BMP_FORMAT_VANILLA format.
305**********************************************/
306void convert_image(void)
307{
308 int newsize;
309 unsigned int row, col;
310
311 rounded_width = fh.Width/6 + ((fh.Width%6)?1:0);
312 newsize = rounded_width * fh.Height;
313
314 converted_bmp = (unsigned char *)malloc(newsize);
315
316 for(row = 0;row < fh.Height;row++)
317 {
318 for(col = 0;col < rounded_width;col++)
319 {
320 converted_bmp[row * rounded_width + col] = read_next_converted_byte();
321 }
322 }
323 converted_size = rounded_width * fh.Height;
324}
325
326#define COMPRESSED_ZEROS_AHEAD 0x40
327#define COMPRESSED_ONES_AHEAD 0x80
328
329/*********************************************************************
330** compress_image()
331**
332** Compresses the BMP_FORMAT_VANILLA format with a simple RLE
333** algorithm. The output is in the BMP_FORMAT_RLE format.
334**********************************************/
335void compress_image(void)
336{
337 unsigned int i, j, count;
338 unsigned int index = 0;
339 unsigned char val;
340
341 compressed_bmp = (unsigned char *)malloc(converted_size);
342
343 for(i = 0;i < converted_size;i++)
344 {
345 val = converted_bmp[i];
346
347 if(val == 0|| val == 0x3f)
348 {
349 count = 0;
350 while(count < 0x4000 && (i + count) < converted_size &&
351 converted_bmp[i+count] == val)
352 {
353 count++;
354 }
355 if(count > 2)
356 {
357 compressed_bmp[index++] = (unsigned char)
358 (((val == 0)?COMPRESSED_ZEROS_AHEAD:COMPRESSED_ONES_AHEAD) |
359 (count >> 8));
360 compressed_bmp[index++] = (unsigned char)(count & 0xff);
361 }
362 else
363 {
364 for(j = 0;j < count;j++)
365 {
366 compressed_bmp[index++] = val;
367 }
368 }
369 i += count - 1;
370 }
371 else
372 {
373 compressed_bmp[index++] = val;
374 }
375 }
376
377 compressed_size = index;
378}
379
380/*********************************************************************
381** generate_c_source()
382**
383** Outputs a C source code with the converted/compressed bitmap in
384** an array, accompanied by some #define's
385**********************************************/
386void generate_c_source(char *id, BOOL compressed)
387{
388 FILE *f;
389 unsigned int i;
390 unsigned int size;
391 unsigned char *bmp;
392
393 size = compressed?compressed_size:converted_size;
394 bmp = compressed?compressed_bmp:converted_bmp;
395
396 f = stdout;
397
398 fprintf(f, "#define %s_WIDTH %d\n", id, rounded_width * 6);
399 fprintf(f, "#define %s_HEIGHT %d\n", id, fh.Height);
400 fprintf(f, "#define %s_SIZE %d\n", id, size + 6);
401 if(compressed)
402 {
403 fprintf(f, "#define %s_ORIGINAL_SIZE %d\n", id, converted_size);
404 }
405 fprintf(f, "#define %s_FORMAT %s\n", id,
406 compressed?"BMP_FORMAT_RLE":"BMP_FORMAT_VANILLA");
407 fprintf(f, "\nconst unsigned char bmpdata_%s[] = {", id);
408
409 /* Header */
410 fprintf(f, "\n %s, 0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,",
411 compressed?"BMP_FORMAT_RLE":"BMP_FORMAT_VANILLA",
412 size >> 8, size & 0xff, 2, fh.Height, rounded_width * 6);
413
414 for(i = 0;i < size;i++)
415 {
416 if(i % 10 == 0)
417 {
418 fprintf(f, "\n ");
419 }
420 fprintf(f, "0x%02x,", bmp[i]);
421 }
422 fprintf(f, "\n};");
423}
424
425/*********************************************************************
426** generate_asm_source()
427**
428** Outputs an ASM source code with the converted/compressed bitmap in
429** an array, the first 2 bytes describing the X and Y size
430**********************************************/
431void generate_asm_source(char *id, BOOL compressed)
432{
433 FILE *f;
434 unsigned int i;
435 unsigned int size;
436 unsigned char *bmp;
437
438 size = compressed?compressed_size:converted_size;
439 bmp = compressed?compressed_bmp:converted_bmp;
440
441 f = stdout;
442
443 fprintf(f, "bmpdata_%s:\n", id);
444 /* Header */
445 fprintf(f, "\n db %s, %.2xh,%.2xh,%.2xh,%.2xh,%.2xh,",
446 compressed?"1":"0",
447 size >> 8, size & 0xff, 2, fh.Height, rounded_width * 6);
448
449 for(i = 0;i < size;i++)
450 {
451 if(i % 10 == 0)
452 {
453 fprintf(f, "\n db ");
454 }
455 fprintf(f, "%.2xh,", bmp[i]);
456 }
457 fprintf(f, "\n");
458}
459
460void print_usage(void)
461{
462 printf("bmp2mt - Converts BMP files to MT Pro source code format\n");
463 printf("build date: " __DATE__ "\n\n");
464 printf("Usage: %s [-i <id>] [-c] [-a] <bitmap file>\n"
465 "-i <id> Bitmap ID (default is filename without extension)\n"
466 "-c Compress (BMP_FORMAT_RLE)\n"
467 "-f Frexx Format!!!\n"
468 "-a Assembly format source code\n", APPLICATION_NAME);
469}
470
471#pragma argsused
472int main(int argc, char **argv)
473{
474 char *bmp_filename = NULL;
475 char *id = NULL;
476 char errstr[80];
477 int i;
478
479 for(i = 1;i < argc;i++)
480 {
481 if(argv[i][0] == '-')
482 {
483 switch(argv[i][1])
484 {
485 case 'i': /* ID */
486 if(argv[i][2])
487 {
488 id = &argv[i][2];
489 }
490 else if(argc > i+1)
491 {
492 id = argv[i+1];
493 i++;
494 }
495 else
496 {
497 print_usage();
498 exit(1);
499 }
500 break;
501
502 case 'c': /* Compressed */
503 compress = true;
504 break;
505
506 case 'a': /* Assembly */
507 assembly = true;
508 break;
509
510 default:
511 print_usage();
512 exit(1);
513 break;
514 }
515 }
516 else
517 {
518 if(!bmp_filename)
519 {
520 bmp_filename = argv[i];
521 }
522 else
523 {
524 print_usage();
525 exit(1);
526 }
527 }
528 }
529
530 if(!bmp_filename)
531 {
532 print_usage();
533 exit(1);
534 }
535
536 if(!id)
537 {
538 id = strdup(bmp_filename);
539
540 for(i = 0;id[i];i++)
541 {
542 if(id[i] == ' ')
543 {
544 id[i] = '_';
545 }
546 else if(id[i] == '.')
547 {
548 id[i] = '\0';
549 break;
550 }
551 else
552 {
553 id[i] = (char)toupper(id[i]);
554 }
555 }
556 }
557
558 read_bmp_file(bmp_filename);
559 convert_image();
560 if(fh.Width % 6)
561 {
562
563 sprintf(errstr, "warning - width is not divisible by 6 (%d), "
564 "padding with zeros to %d\n", fh.Width, rounded_width*6);
565 print_error(errstr, 0);
566 }
567
568 if(compress)
569 {
570 compress_image();
571 }
572
573 if(assembly)
574 {
575 generate_asm_source(id, compress);
576 }
577 else
578 {
579 generate_c_source(id, compress);
580 }
581 return 0;
582}
583
584#endif