1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 /****************************************************************************
23 * Converts BMP files to Rockbox bitmap format
25 * 1999-05-03 Linus Nielsen Feltzing
27 * 2005-07-06 Jens Arnold
28 * added reading of 4, 16, 24 and 32 bit bmps
29 * added 2 new target formats (playergfx and iriver 4-grey)
31 ****************************************************************************/
39 #include <sys/types.h>
46 #define STRUCT_PACKED __attribute__((packed))
49 #pragma pack (push, 2)
54 unsigned short Type
; /* signature - 'BM' */
55 unsigned int Size
; /* file size in bytes */
56 unsigned short Reserved1
; /* 0 */
57 unsigned short Reserved2
; /* 0 */
58 unsigned int OffBits
; /* offset to bitmap */
59 unsigned int StructSize
; /* size of this struct (40) */
60 unsigned int Width
; /* bmap width in pixels */
61 unsigned int Height
; /* bmap height in pixels */
62 unsigned short Planes
; /* num planes - always 1 */
63 unsigned short BitCount
; /* bits per pixel */
64 unsigned int Compression
; /* compression flag */
65 unsigned int SizeImage
; /* image size in bytes */
66 int XPelsPerMeter
; /* horz resolution */
67 int YPelsPerMeter
; /* vert resolution */
68 unsigned int ClrUsed
; /* 0 -> color table size */
69 unsigned int ClrImportant
; /* important color count */
74 unsigned char rgbBlue
;
75 unsigned char rgbGreen
;
77 unsigned char rgbReserved
;
80 short readshort(void* value
)
82 unsigned char* bytes
= (unsigned char*) value
;
83 return bytes
[0] | (bytes
[1] << 8);
86 int readint(void* value
)
88 unsigned char* bytes
= (unsigned char*) value
;
89 return bytes
[0] | (bytes
[1] << 8) | (bytes
[2] << 16) | (bytes
[3] << 24);
92 unsigned char brightness(struct RGBQUAD color
)
94 return (3 * (unsigned int)color
.rgbRed
+ 6 * (unsigned int)color
.rgbGreen
95 + (unsigned int)color
.rgbBlue
) / 10;
99 #define O_BINARY 0 /* systems that don't have O_BINARY won't make a difference
100 on text and binary files */
103 /****************************************************************************
106 * Reads an uncompressed BMP file and puts the data in a 4-byte-per-pixel
107 * (RGBQUAD) array. Returns 0 on success.
109 ***************************************************************************/
111 int read_bmp_file(char* filename
,
112 int *get_width
, /* in pixels */
113 int *get_height
, /* in pixels */
114 struct RGBQUAD
**bitmap
)
116 struct Fileheader fh
;
117 struct RGBQUAD palette
[256];
119 int fd
= open(filename
, O_RDONLY
| O_BINARY
);
126 int numcolors
, compression
;
131 debugf("error - can't open '%s'\n", filename
);
134 if (read(fd
, &fh
, sizeof(struct Fileheader
)) !=
135 sizeof(struct Fileheader
))
137 debugf("error - can't Read Fileheader Stucture\n");
142 compression
= readint(&fh
.Compression
);
144 if (compression
!= 0)
146 debugf("error - Unsupported compression %d\n", compression
);
151 depth
= readshort(&fh
.BitCount
);
155 numcolors
= readint(&fh
.ClrUsed
);
157 numcolors
= 1 << depth
;
159 if (read(fd
, &palette
[0], numcolors
* sizeof(struct RGBQUAD
))
160 != (int)(numcolors
* sizeof(struct RGBQUAD
)))
162 debugf("error - Can't read bitmap's color palette\n");
168 width
= readint(&fh
.Width
);
169 height
= readint(&fh
.Height
);
170 padded_width
= ((width
* depth
+ 31) / 8) & ~3; /* aligned 4-bytes boundaries */
172 size
= padded_width
* height
; /* read this many bytes */
173 bmp
= (unsigned char *)malloc(size
);
174 *bitmap
= (struct RGBQUAD
*)malloc(width
* height
* sizeof(struct RGBQUAD
));
176 if ((bmp
== NULL
) || (*bitmap
== NULL
))
178 debugf("error - Out of memory\n");
183 if (lseek(fd
, (off_t
)readint(&fh
.OffBits
), SEEK_SET
) < 0)
185 debugf("error - Can't seek to start of image data\n");
189 if (read(fd
, (unsigned char*)bmp
, (int)size
) != size
)
191 debugf("error - Can't read image\n");
198 *get_height
= height
;
203 for (row
= 0; row
< height
; row
++)
204 for (col
= 0; col
< width
; col
++)
206 data
= (bmp
[(height
- 1 - row
) * padded_width
+ col
/ 8]
208 (*bitmap
)[row
* width
+ col
] = palette
[data
];
213 for (row
= 0; row
< height
; row
++)
214 for (col
= 0; col
< width
; col
++)
216 data
= (bmp
[(height
- 1 - row
) * padded_width
+ col
/ 2]
217 >> (4 * (~col
& 1))) & 0x0F;
218 (*bitmap
)[row
* width
+ col
] = palette
[data
];
223 for (row
= 0; row
< height
; row
++)
224 for (col
= 0; col
< width
; col
++)
226 data
= bmp
[(height
- 1 - row
) * padded_width
+ col
];
227 (*bitmap
)[row
* width
+ col
] = palette
[data
];
232 for (row
= 0; row
< height
; row
++)
233 for (col
= 0; col
< width
; col
++)
235 data
= readshort(&bmp
[(height
- 1 - row
) * padded_width
+ 2 * col
]);
236 (*bitmap
)[row
* width
+ col
].rgbRed
=
237 ((data
>> 7) & 0xF8) | ((data
>> 12) & 0x07);
238 (*bitmap
)[row
* width
+ col
].rgbGreen
=
239 ((data
>> 2) & 0xF8) | ((data
>> 7) & 0x07);
240 (*bitmap
)[row
* width
+ col
].rgbBlue
=
241 ((data
<< 3) & 0xF8) | ((data
>> 2) & 0x07);
242 (*bitmap
)[row
* width
+ col
].rgbReserved
= 0;
247 for (row
= 0; row
< height
; row
++)
248 for (col
= 0; col
< width
; col
++)
250 i
= (height
- 1 - row
) * padded_width
+ 3 * col
;
251 (*bitmap
)[row
* width
+ col
].rgbRed
= bmp
[i
+2];
252 (*bitmap
)[row
* width
+ col
].rgbGreen
= bmp
[i
+1];
253 (*bitmap
)[row
* width
+ col
].rgbBlue
= bmp
[i
];
254 (*bitmap
)[row
* width
+ col
].rgbReserved
= 0;
259 for (row
= 0; row
< height
; row
++)
260 for (col
= 0; col
< width
; col
++)
262 i
= (height
- 1 - row
) * padded_width
+ 4 * col
;
263 (*bitmap
)[row
* width
+ col
].rgbRed
= bmp
[i
+2];
264 (*bitmap
)[row
* width
+ col
].rgbGreen
= bmp
[i
+1];
265 (*bitmap
)[row
* width
+ col
].rgbBlue
= bmp
[i
];
266 (*bitmap
)[row
* width
+ col
].rgbReserved
= 0;
270 default: /* should never happen */
271 debugf("error - Unsupported bitmap depth %d.\n", depth
);
277 return 0; /* success */
280 /****************************************************************************
283 * Transform a 4-byte-per-pixel bitmap (RGBQUAD) into one of the supported
284 * destination formats
285 ****************************************************************************/
287 int transform_bitmap(const struct RGBQUAD
*src
, int width
, int height
,
288 int format
, unsigned short **dest
, int *dst_width
,
289 int *dst_height
, int *dst_depth
)
292 int dst_w
, dst_h
, dst_d
;
296 case 0: /* Archos recorders, Ondio, Iriver H1x0 monochrome */
298 dst_h
= (height
+ 7) / 8;
302 case 1: /* Archos player graphics library */
303 dst_w
= (width
+ 7) / 8;
308 case 2: /* Iriver H1x0 4-grey */
310 dst_h
= (height
+ 3) / 4;
314 case 3: /* Canonical 8-bit grayscale */
320 case 4: /* 16-bit packed RGB (5-6-5) */
321 case 5: /* 16-bit packed and byte-swapped RGB (5-6-5) */
322 case 8: /* 16-bit packed RGB (5-6-5) vertical stride*/
328 case 6: /* greyscale iPods 4-grey */
329 dst_w
= (width
+ 3) / 4;
334 case 7: /* greyscale X5 remote 4-grey */
336 dst_h
= (height
+ 7) / 8;
340 default: /* unknown */
341 debugf("error - Undefined destination format\n");
345 *dest
= (unsigned short *)malloc(dst_w
* dst_h
* sizeof(short));
348 debugf("error - Out of memory.\n");
351 memset(*dest
, 0, dst_w
* dst_h
* sizeof(short));
358 case 0: /* Archos recorders, Ondio, Iriver H1x0 b&w */
359 for (row
= 0; row
< height
; row
++)
360 for (col
= 0; col
< width
; col
++)
362 (*dest
)[(row
/8) * dst_w
+ col
] |=
363 (~brightness(src
[row
* width
+ col
]) & 0x80) >> (~row
& 7);
367 case 1: /* Archos player graphics library */
368 for (row
= 0; row
< height
; row
++)
369 for (col
= 0; col
< width
; col
++)
371 (*dest
)[row
* dst_w
+ (col
/8)] |=
372 (~brightness(src
[row
* width
+ col
]) & 0x80) >> (col
& 7);
376 case 2: /* Iriver H1x0 4-grey */
377 for (row
= 0; row
< height
; row
++)
378 for (col
= 0; col
< width
; col
++)
380 (*dest
)[(row
/4) * dst_w
+ col
] |=
381 (~brightness(src
[row
* width
+ col
]) & 0xC0) >> (2 * (~row
& 3));
385 case 3: /* Canonical 8-bit grayscale */
386 for (row
= 0; row
< height
; row
++)
387 for (col
= 0; col
< width
; col
++)
389 (*dest
)[row
* dst_w
+ col
] = brightness(src
[row
* width
+ col
]);
393 case 4: /* 16-bit packed RGB (5-6-5) */
394 case 5: /* 16-bit packed and byte-swapped RGB (5-6-5) */
395 for (row
= 0; row
< height
; row
++)
396 for (col
= 0; col
< width
; col
++)
399 (((src
[row
* width
+ col
].rgbRed
>> 3) << 11) |
400 ((src
[row
* width
+ col
].rgbGreen
>> 2) << 5) |
401 ((src
[row
* width
+ col
].rgbBlue
>> 3)));
404 (*dest
)[row
* dst_w
+ col
] = rgb
;
406 (*dest
)[row
* dst_w
+ col
] = ((rgb
&0xff00)>>8)|((rgb
&0x00ff)<<8);
410 case 6: /* greyscale iPods 4-grey */
411 for (row
= 0; row
< height
; row
++)
412 for (col
= 0; col
< width
; col
++)
414 (*dest
)[row
* dst_w
+ (col
/4)] |=
415 (~brightness(src
[row
* width
+ col
]) & 0xC0) >> (2 * (col
& 3));
419 case 7: /* greyscale X5 remote 4-grey */
420 for (row
= 0; row
< height
; row
++)
421 for (col
= 0; col
< width
; col
++)
423 unsigned short data
= (~brightness(src
[row
* width
+ col
]) & 0xC0) >> 6;
425 data
= (data
| (data
<< 7)) & 0x0101;
426 (*dest
)[(row
/8) * dst_w
+ col
] |= data
<< (row
& 7);
430 case 8: /* 16-bit packed RGB (5-6-5) vertical stride*/
431 for (row
= 0; row
< height
; row
++)
432 for (col
= 0; col
< width
; col
++)
435 (((src
[row
* width
+ col
].rgbRed
>> 3) << 11) |
436 ((src
[row
* width
+ col
].rgbGreen
>> 2) << 5) |
437 ((src
[row
* width
+ col
].rgbBlue
>> 3)));
439 (*dest
)[col
* dst_h
+ row
] = rgb
;
447 /****************************************************************************
448 * generate_c_source()
450 * Outputs a C source code with the bitmap in an array, accompanied by
452 ****************************************************************************/
454 void generate_c_source(char *id
, char* header_dir
, int width
, int height
,
455 const unsigned short *t_bitmap
, int t_width
,
456 int t_height
, int t_depth
)
461 char header_name
[1024];
468 if (header_dir
&& header_dir
[0])
470 snprintf(header_name
,sizeof(header_name
),"%s/%s.h",header_dir
,id
);
471 fh
= fopen(header_name
,"w+");
475 debugf("error - can't open '%s'\n", header_name
);
479 "#define BMPHEIGHT_%s %d\n"
480 "#define BMPWIDTH_%s %d\n",
481 id
, height
, id
, width
);
483 fprintf(fh
, "extern const unsigned char %s[];\n", id
);
485 fprintf(fh
, "extern const unsigned short %s[];\n", id
);
490 "#define BMPHEIGHT_%s %d\n"
491 "#define BMPWIDTH_%s %d\n",
492 id
, height
, id
, width
);
496 fprintf(f
, "const unsigned char %s[] = {\n", id
);
498 fprintf(f
, "const unsigned short %s[] = {\n", id
);
500 for (i
= 0; i
< t_height
; i
++)
502 for (a
= 0; a
< t_width
; a
++)
505 fprintf(f
, "0x%02x,%c", t_bitmap
[i
* t_width
+ a
],
506 (a
+ 1) % 13 ? ' ' : '\n');
508 fprintf(f
, "0x%04x,%c", t_bitmap
[i
* t_width
+ a
],
509 (a
+ 1) % 10 ? ' ' : '\n');
514 fprintf(f
, "\n};\n");
517 void generate_raw_file(const unsigned short *t_bitmap
,
518 int t_width
, int t_height
, int t_depth
)
526 for (i
= 0; i
< t_height
; i
++)
528 for (a
= 0; a
< t_width
; a
++)
532 lo
= (t_bitmap
[i
* t_width
+ a
] & 0x00ff);
533 fwrite(&lo
, 1, 1, f
);
537 lo
= (t_bitmap
[i
* t_width
+ a
] & 0x00ff);
538 hi
= (t_bitmap
[i
* t_width
+ a
] & 0xff00) >> 8;
539 fwrite(&lo
, 1, 1, f
);
540 fwrite(&hi
, 1, 1, f
);
546 /****************************************************************************
549 * Outputs an ascii picture of the bitmap
550 ****************************************************************************/
552 void generate_ascii(int width
, int height
, struct RGBQUAD
*bitmap
)
559 /* for screen output debugging */
560 for (y
= 0; y
< height
; y
++)
562 for (x
= 0; x
< width
; x
++)
564 fprintf(f
, (brightness(bitmap
[y
* width
+ x
]) & 0x80) ? " " : "*");
570 void print_usage(void)
572 printf("Usage: %s [-i <id>] [-a] <bitmap file>\n"
573 "\t-i <id> Bitmap name (default is filename without extension)\n"
574 "\t-h <dir> Create header file in <dir>/<id>.h\n"
575 "\t-a Show ascii picture of bitmap\n"
576 "\t-r Generate RAW file (little-endian)\n"
577 "\t-f <n> Generate destination format n, default = 0\n"
578 "\t 0 Archos recorder, Ondio, Iriver H1x0 mono\n"
580 printf("\t 1 Archos player graphics library\n"
581 "\t 2 Iriver H1x0 4-grey\n"
582 "\t 3 Canonical 8-bit greyscale\n"
583 "\t 4 16-bit packed 5-6-5 RGB (iriver H300)\n"
584 "\t 5 16-bit packed and byte-swapped 5-6-5 RGB (iPod)\n"
585 "\t 6 Greyscale iPod 4-grey\n"
586 "\t 7 Greyscale X5 remote 4-grey\n"
587 "\t 8 16-bit packed 5-6-5 RGB with a vertical stride\n");
588 printf("build date: " __DATE__
"\n\n");
591 int main(int argc
, char **argv
)
593 char *bmp_filename
= NULL
;
595 char* header_dir
= NULL
;
599 struct RGBQUAD
*bitmap
= NULL
;
600 unsigned short *t_bitmap
= NULL
;
602 int t_width
, t_height
, t_depth
;
606 for (i
= 1;i
< argc
;i
++)
608 if (argv
[i
][0] == '-')
612 case 'h': /* .h filename */
615 header_dir
= &argv
[i
][2];
619 header_dir
= argv
[i
+1];
646 case 'a': /* Ascii art */
650 case 'r': /* Raw File */
657 format
= atoi(&argv
[i
][2]);
661 format
= atoi(argv
[i
+1]);
681 bmp_filename
= argv
[i
];
699 char *ptr
=strrchr(bmp_filename
, '/');
705 for (i
= 0; id
[i
]; i
++)
710 if (read_bmp_file(bmp_filename
, &width
, &height
, &bitmap
))
716 generate_ascii(width
, height
, bitmap
);
720 if (transform_bitmap(bitmap
, width
, height
, format
, &t_bitmap
,
721 &t_width
, &t_height
, &t_depth
))
724 generate_raw_file(t_bitmap
, t_width
, t_height
, t_depth
);
726 generate_c_source(id
, header_dir
, width
, height
, t_bitmap
,
727 t_width
, t_height
, t_depth
);