1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
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.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
19 /****************************************************************************
21 * Converts BMP files to Rockbox bitmap format
23 * 1999-05-03 Linus Nielsen Feltzing
25 * 2005-07-06 Jens Arnold
26 * added reading of 4, 16, 24 and 32 bit bmps
27 * added 2 new target formats (playergfx and iriver 4-grey)
29 ****************************************************************************/
36 #include <sys/types.h>
43 #define STRUCT_PACKED __attribute__((packed))
46 #pragma pack (push, 2)
51 unsigned short Type
; /* signature - 'BM' */
52 unsigned int Size
; /* file size in bytes */
53 unsigned short Reserved1
; /* 0 */
54 unsigned short Reserved2
; /* 0 */
55 unsigned int OffBits
; /* offset to bitmap */
56 unsigned int StructSize
; /* size of this struct (40) */
57 unsigned int Width
; /* bmap width in pixels */
58 unsigned int Height
; /* bmap height in pixels */
59 unsigned short Planes
; /* num planes - always 1 */
60 unsigned short BitCount
; /* bits per pixel */
61 unsigned int Compression
; /* compression flag */
62 unsigned int SizeImage
; /* image size in bytes */
63 int XPelsPerMeter
; /* horz resolution */
64 int YPelsPerMeter
; /* vert resolution */
65 unsigned int ClrUsed
; /* 0 -> color table size */
66 unsigned int ClrImportant
; /* important color count */
71 unsigned char rgbBlue
;
72 unsigned char rgbGreen
;
74 unsigned char rgbReserved
;
77 short readshort(void* value
)
79 unsigned char* bytes
= (unsigned char*) value
;
80 return bytes
[0] | (bytes
[1] << 8);
83 int readint(void* value
)
85 unsigned char* bytes
= (unsigned char*) value
;
86 return bytes
[0] | (bytes
[1] << 8) | (bytes
[2] << 16) | (bytes
[3] << 24);
89 unsigned char brightness(struct RGBQUAD color
)
91 return (3 * (unsigned int)color
.rgbRed
+ 6 * (unsigned int)color
.rgbGreen
92 + (unsigned int)color
.rgbBlue
) / 10;
96 #define O_BINARY 0 /* systems that don't have O_BINARY won't make a difference
97 on text and binary files */
100 /****************************************************************************
103 * Reads an uncompressed BMP file and puts the data in a 4-byte-per-pixel
104 * (RGBQUAD) array. Returns 0 on success.
106 ***************************************************************************/
108 int read_bmp_file(char* filename
,
109 int *get_width
, /* in pixels */
110 int *get_height
, /* in pixels */
111 struct RGBQUAD
**bitmap
)
113 struct Fileheader fh
;
114 struct RGBQUAD palette
[256];
116 int fd
= open(filename
, O_RDONLY
| O_BINARY
);
123 int numcolors
, compression
;
128 debugf("error - can't open '%s'\n", filename
);
131 if (read(fd
, &fh
, sizeof(struct Fileheader
)) !=
132 sizeof(struct Fileheader
))
134 debugf("error - can't Read Fileheader Stucture\n");
139 compression
= readint(&fh
.Compression
);
141 if (compression
!= 0)
143 debugf("error - Unsupported compression %ld\n", compression
);
148 depth
= readshort(&fh
.BitCount
);
152 numcolors
= readint(&fh
.ClrUsed
);
154 numcolors
= 1 << depth
;
156 if (read(fd
, &palette
[0], numcolors
* sizeof(struct RGBQUAD
))
157 != numcolors
* sizeof(struct RGBQUAD
))
159 debugf("error - Can't read bitmap's color palette\n");
165 width
= readint(&fh
.Width
);
166 height
= readint(&fh
.Height
);
167 padded_width
= ((width
* depth
+ 31) / 8) & ~3; /* aligned 4-bytes boundaries */
169 size
= padded_width
* height
; /* read this many bytes */
170 bmp
= (unsigned char *)malloc(size
);
171 *bitmap
= (struct RGBQUAD
*)malloc(width
* height
* sizeof(struct RGBQUAD
));
173 if ((bmp
== NULL
) || (*bitmap
== NULL
))
175 debugf("error - Out of memory\n");
180 if (lseek(fd
, (off_t
)readint(&fh
.OffBits
), SEEK_SET
) < 0)
182 debugf("error - Can't seek to start of image data\n");
186 if (read(fd
, (unsigned char*)bmp
, (int)size
) != size
)
188 debugf("error - Can't read image\n");
195 *get_height
= height
;
200 for (row
= 0; row
< height
; row
++)
201 for (col
= 0; col
< width
; col
++)
203 data
= (bmp
[(height
- 1 - row
) * padded_width
+ col
/ 8]
205 (*bitmap
)[row
* width
+ col
] = palette
[data
];
210 for (row
= 0; row
< height
; row
++)
211 for (col
= 0; col
< width
; col
++)
213 data
= (bmp
[(height
- 1 - row
) * padded_width
+ col
/ 2]
214 >> (4 * (~col
& 1))) & 0x0F;
215 (*bitmap
)[row
* width
+ col
] = palette
[data
];
220 for (row
= 0; row
< height
; row
++)
221 for (col
= 0; col
< width
; col
++)
223 data
= bmp
[(height
- 1 - row
) * padded_width
+ col
];
224 (*bitmap
)[row
* width
+ col
] = palette
[data
];
229 for (row
= 0; row
< height
; row
++)
230 for (col
= 0; col
< width
; col
++)
232 data
= readshort(&bmp
[(height
- 1 - row
) * padded_width
+ 2 * col
]);
233 (*bitmap
)[row
* width
+ col
].rgbRed
=
234 ((data
>> 7) & 0xF8) | ((data
>> 12) & 0x07);
235 (*bitmap
)[row
* width
+ col
].rgbGreen
=
236 ((data
>> 2) & 0xF8) | ((data
>> 7) & 0x07);
237 (*bitmap
)[row
* width
+ col
].rgbBlue
=
238 ((data
<< 3) & 0xF8) | ((data
>> 2) & 0x07);
239 (*bitmap
)[row
* width
+ col
].rgbReserved
= 0;
244 for (row
= 0; row
< height
; row
++)
245 for (col
= 0; col
< width
; col
++)
247 i
= (height
- 1 - row
) * padded_width
+ 3 * col
;
248 (*bitmap
)[row
* width
+ col
].rgbRed
= bmp
[i
+2];
249 (*bitmap
)[row
* width
+ col
].rgbGreen
= bmp
[i
+1];
250 (*bitmap
)[row
* width
+ col
].rgbBlue
= bmp
[i
];
251 (*bitmap
)[row
* width
+ col
].rgbReserved
= 0;
256 for (row
= 0; row
< height
; row
++)
257 for (col
= 0; col
< width
; col
++)
259 i
= (height
- 1 - row
) * padded_width
+ 4 * col
;
260 (*bitmap
)[row
* width
+ col
].rgbRed
= bmp
[i
+2];
261 (*bitmap
)[row
* width
+ col
].rgbGreen
= bmp
[i
+1];
262 (*bitmap
)[row
* width
+ col
].rgbBlue
= bmp
[i
];
263 (*bitmap
)[row
* width
+ col
].rgbReserved
= 0;
267 default: /* should never happen */
268 debugf("error - Unsupported bitmap depth %d.\n", depth
);
274 return 0; /* success */
277 /****************************************************************************
280 * Transform a 4-byte-per-pixel bitmap (RGBQUAD) into one of the supported
281 * destination formats
282 ****************************************************************************/
284 int transform_bitmap(const struct RGBQUAD
*src
, int width
, int height
,
285 int format
, unsigned short **dest
, int *dst_width
,
286 int *dst_height
, int *dst_depth
)
289 int dst_w
, dst_h
, dst_d
;
293 case 0: /* Archos recorders, Ondio, Iriver H1x0 monochrome */
295 dst_h
= (height
+ 7) / 8;
299 case 1: /* Archos player graphics library */
300 dst_w
= (width
+ 7) / 8;
305 case 2: /* Iriver H1x0 4-grey */
307 dst_h
= (height
+ 3) / 4;
311 case 3: /* Canonical 8-bit grayscale */
317 case 4: /* 16-bit packed RGB (5-6-5) */
318 case 5: /* 16-bit packed and byte-swapped RGB (5-6-5) */
324 case 6: /* greyscale iPods 4-grey */
325 dst_w
= (width
+ 3) / 4;
330 case 7: /* greyscale X5 remote 4-grey */
332 dst_h
= (height
+ 7) / 8;
336 default: /* unknown */
337 debugf("error - Undefined destination format\n");
341 *dest
= (unsigned short *)malloc(dst_w
* dst_h
* sizeof(short));
344 debugf("error - Out of memory.\n");
347 memset(*dest
, 0, dst_w
* dst_h
* sizeof(short));
354 case 0: /* Archos recorders, Ondio, Iriver H1x0 b&w */
355 for (row
= 0; row
< height
; row
++)
356 for (col
= 0; col
< width
; col
++)
358 (*dest
)[(row
/8) * dst_w
+ col
] |=
359 (~brightness(src
[row
* width
+ col
]) & 0x80) >> (~row
& 7);
363 case 1: /* Archos player graphics library */
364 for (row
= 0; row
< height
; row
++)
365 for (col
= 0; col
< width
; col
++)
367 (*dest
)[row
* dst_w
+ (col
/8)] |=
368 (~brightness(src
[row
* width
+ col
]) & 0x80) >> (col
& 7);
372 case 2: /* Iriver H1x0 4-grey */
373 for (row
= 0; row
< height
; row
++)
374 for (col
= 0; col
< width
; col
++)
376 (*dest
)[(row
/4) * dst_w
+ col
] |=
377 (~brightness(src
[row
* width
+ col
]) & 0xC0) >> (2 * (~row
& 3));
381 case 3: /* Canonical 8-bit grayscale */
382 for (row
= 0; row
< height
; row
++)
383 for (col
= 0; col
< width
; col
++)
385 (*dest
)[row
* dst_w
+ col
] = brightness(src
[row
* width
+ col
]);
389 case 4: /* 16-bit packed RGB (5-6-5) */
390 case 5: /* 16-bit packed and byte-swapped RGB (5-6-5) */
391 for (row
= 0; row
< height
; row
++)
392 for (col
= 0; col
< width
; col
++)
395 (((src
[row
* width
+ col
].rgbRed
>> 3) << 11) |
396 ((src
[row
* width
+ col
].rgbGreen
>> 2) << 5) |
397 ((src
[row
* width
+ col
].rgbBlue
>> 3)));
400 (*dest
)[row
* dst_w
+ col
] = rgb
;
402 (*dest
)[row
* dst_w
+ col
] = ((rgb
&0xff00)>>8)|((rgb
&0x00ff)<<8);
406 case 6: /* greyscale iPods 4-grey */
407 for (row
= 0; row
< height
; row
++)
408 for (col
= 0; col
< width
; col
++)
410 (*dest
)[row
* dst_w
+ (col
/4)] |=
411 (~brightness(src
[row
* width
+ col
]) & 0xC0) >> (2 * (col
& 3));
415 case 7: /* greyscale X5 remote 4-grey */
416 for (row
= 0; row
< height
; row
++)
417 for (col
= 0; col
< width
; col
++)
419 unsigned short data
= (~brightness(src
[row
* width
+ col
]) & 0xC0) >> 6;
421 data
= (data
| (data
<< 7)) & 0x0101;
422 (*dest
)[(row
/8) * dst_w
+ col
] |= data
<< (row
& 7);
430 /****************************************************************************
431 * generate_c_source()
433 * Outputs a C source code with the bitmap in an array, accompanied by
435 ****************************************************************************/
437 void generate_c_source(char *id
, char* header_dir
, int width
, int height
,
438 const unsigned short *t_bitmap
, int t_width
,
439 int t_height
, int t_depth
)
444 char header_name
[1024];
451 if (header_dir
&& header_dir
[0])
453 snprintf(header_name
,sizeof(header_name
),"%s/%s.h",header_dir
,id
);
454 fh
= fopen(header_name
,"w+");
458 debugf("error - can't open '%s'\n", header_name
);
462 "#define BMPHEIGHT_%s %ld\n"
463 "#define BMPWIDTH_%s %ld\n",
464 id
, height
, id
, width
);
466 fprintf(fh
, "extern const unsigned char %s[];\n", id
);
468 fprintf(fh
, "extern const unsigned short %s[];\n", id
);
473 "#define BMPHEIGHT_%s %ld\n"
474 "#define BMPWIDTH_%s %ld\n",
475 id
, height
, id
, width
);
479 fprintf(f
, "const unsigned char %s[] = {\n", id
);
481 fprintf(f
, "const unsigned short %s[] = {\n", id
);
483 for (i
= 0; i
< t_height
; i
++)
485 for (a
= 0; a
< t_width
; a
++)
488 fprintf(f
, "0x%02x,%c", t_bitmap
[i
* t_width
+ a
],
489 (a
+ 1) % 13 ? ' ' : '\n');
491 fprintf(f
, "0x%04x,%c", t_bitmap
[i
* t_width
+ a
],
492 (a
+ 1) % 10 ? ' ' : '\n');
497 fprintf(f
, "\n};\n");
500 void generate_raw_file(char *id
, const unsigned short *t_bitmap
,
501 int t_width
, int t_height
, int t_depth
)
509 for (i
= 0; i
< t_height
; i
++)
511 for (a
= 0; a
< t_width
; a
++)
515 lo
= (t_bitmap
[i
* t_width
+ a
] & 0x00ff);
516 fwrite(&lo
, 1, 1, f
);
520 lo
= (t_bitmap
[i
* t_width
+ a
] & 0x00ff);
521 hi
= (t_bitmap
[i
* t_width
+ a
] & 0xff00) >> 8;
522 fwrite(&lo
, 1, 1, f
);
523 fwrite(&hi
, 1, 1, f
);
529 /****************************************************************************
532 * Outputs an ascii picture of the bitmap
533 ****************************************************************************/
535 void generate_ascii(int width
, int height
, struct RGBQUAD
*bitmap
)
542 /* for screen output debugging */
543 for (y
= 0; y
< height
; y
++)
545 for (x
= 0; x
< width
; x
++)
547 fprintf(f
, (brightness(bitmap
[y
* width
+ x
]) & 0x80) ? " " : "*");
553 void print_usage(void)
555 printf("Usage: %s [-i <id>] [-a] <bitmap file>\n"
556 "\t-i <id> Bitmap name (default is filename without extension)\n"
557 "\t-h <dir> Create header file in <dir>/<id>.h\n"
558 "\t-a Show ascii picture of bitmap\n"
559 "\t-r Generate RAW file (little-endian)\n"
560 "\t-f <n> Generate destination format n, default = 0\n"
561 "\t 0 Archos recorder, Ondio, Iriver H1x0 mono\n"
562 "\t 1 Archos player graphics library\n"
563 "\t 2 Iriver H1x0 4-grey\n"
564 "\t 3 Canonical 8-bit greyscale\n"
565 "\t 4 16-bit packed 5-6-5 RGB (iriver H300)\n"
566 "\t 5 16-bit packed and byte-swapped 5-6-5 RGB (iPod)\n"
567 "\t 6 Greyscale iPod 4-grey\n"
568 "\t 7 Greyscale X5 remote 4-grey\n"
570 printf("build date: " __DATE__
"\n\n");
573 int main(int argc
, char **argv
)
575 char *bmp_filename
= NULL
;
577 char* header_dir
= NULL
;
581 struct RGBQUAD
*bitmap
= NULL
;
582 unsigned short *t_bitmap
= NULL
;
584 int t_width
, t_height
, t_depth
;
588 for (i
= 1;i
< argc
;i
++)
590 if (argv
[i
][0] == '-')
594 case 'h': /* .h filename */
597 header_dir
= &argv
[i
][2];
601 header_dir
= argv
[i
+1];
628 case 'a': /* Ascii art */
632 case 'r': /* Raw File */
639 format
= atoi(&argv
[i
][2]);
643 format
= atoi(argv
[i
+1]);
663 bmp_filename
= argv
[i
];
681 char *ptr
=strrchr(bmp_filename
, '/');
687 for (i
= 0; id
[i
]; i
++)
692 if (read_bmp_file(bmp_filename
, &width
, &height
, &bitmap
))
698 generate_ascii(width
, height
, bitmap
);
702 if (transform_bitmap(bitmap
, width
, height
, format
, &t_bitmap
,
703 &t_width
, &t_height
, &t_depth
))
706 generate_raw_file(id
, t_bitmap
, t_width
, t_height
, t_depth
);
708 generate_c_source(id
, header_dir
, width
, height
, t_bitmap
,
709 t_width
, t_height
, t_depth
);