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) */
327 case 6: /* greyscale iPods 4-grey */
328 dst_w
= (width
+ 3) / 4;
333 case 7: /* greyscale X5 remote 4-grey */
335 dst_h
= (height
+ 7) / 8;
339 default: /* unknown */
340 debugf("error - Undefined destination format\n");
344 *dest
= (unsigned short *)malloc(dst_w
* dst_h
* sizeof(short));
347 debugf("error - Out of memory.\n");
350 memset(*dest
, 0, dst_w
* dst_h
* sizeof(short));
357 case 0: /* Archos recorders, Ondio, Iriver H1x0 b&w */
358 for (row
= 0; row
< height
; row
++)
359 for (col
= 0; col
< width
; col
++)
361 (*dest
)[(row
/8) * dst_w
+ col
] |=
362 (~brightness(src
[row
* width
+ col
]) & 0x80) >> (~row
& 7);
366 case 1: /* Archos player graphics library */
367 for (row
= 0; row
< height
; row
++)
368 for (col
= 0; col
< width
; col
++)
370 (*dest
)[row
* dst_w
+ (col
/8)] |=
371 (~brightness(src
[row
* width
+ col
]) & 0x80) >> (col
& 7);
375 case 2: /* Iriver H1x0 4-grey */
376 for (row
= 0; row
< height
; row
++)
377 for (col
= 0; col
< width
; col
++)
379 (*dest
)[(row
/4) * dst_w
+ col
] |=
380 (~brightness(src
[row
* width
+ col
]) & 0xC0) >> (2 * (~row
& 3));
384 case 3: /* Canonical 8-bit grayscale */
385 for (row
= 0; row
< height
; row
++)
386 for (col
= 0; col
< width
; col
++)
388 (*dest
)[row
* dst_w
+ col
] = brightness(src
[row
* width
+ col
]);
392 case 4: /* 16-bit packed RGB (5-6-5) */
393 case 5: /* 16-bit packed and byte-swapped RGB (5-6-5) */
394 for (row
= 0; row
< height
; row
++)
395 for (col
= 0; col
< width
; col
++)
398 (((src
[row
* width
+ col
].rgbRed
>> 3) << 11) |
399 ((src
[row
* width
+ col
].rgbGreen
>> 2) << 5) |
400 ((src
[row
* width
+ col
].rgbBlue
>> 3)));
403 (*dest
)[row
* dst_w
+ col
] = rgb
;
405 (*dest
)[row
* dst_w
+ col
] = ((rgb
&0xff00)>>8)|((rgb
&0x00ff)<<8);
409 case 6: /* greyscale iPods 4-grey */
410 for (row
= 0; row
< height
; row
++)
411 for (col
= 0; col
< width
; col
++)
413 (*dest
)[row
* dst_w
+ (col
/4)] |=
414 (~brightness(src
[row
* width
+ col
]) & 0xC0) >> (2 * (col
& 3));
418 case 7: /* greyscale X5 remote 4-grey */
419 for (row
= 0; row
< height
; row
++)
420 for (col
= 0; col
< width
; col
++)
422 unsigned short data
= (~brightness(src
[row
* width
+ col
]) & 0xC0) >> 6;
424 data
= (data
| (data
<< 7)) & 0x0101;
425 (*dest
)[(row
/8) * dst_w
+ col
] |= data
<< (row
& 7);
433 /****************************************************************************
434 * generate_c_source()
436 * Outputs a C source code with the bitmap in an array, accompanied by
438 ****************************************************************************/
440 void generate_c_source(char *id
, char* header_dir
, int width
, int height
,
441 const unsigned short *t_bitmap
, int t_width
,
442 int t_height
, int t_depth
)
447 char header_name
[1024];
454 if (header_dir
&& header_dir
[0])
456 snprintf(header_name
,sizeof(header_name
),"%s/%s.h",header_dir
,id
);
457 fh
= fopen(header_name
,"w+");
461 debugf("error - can't open '%s'\n", header_name
);
465 "#define BMPHEIGHT_%s %d\n"
466 "#define BMPWIDTH_%s %d\n",
467 id
, height
, id
, width
);
469 fprintf(fh
, "extern const unsigned char %s[];\n", id
);
471 fprintf(fh
, "extern const unsigned short %s[];\n", id
);
476 "#define BMPHEIGHT_%s %d\n"
477 "#define BMPWIDTH_%s %d\n",
478 id
, height
, id
, width
);
482 fprintf(f
, "const unsigned char %s[] = {\n", id
);
484 fprintf(f
, "const unsigned short %s[] = {\n", id
);
486 for (i
= 0; i
< t_height
; i
++)
488 for (a
= 0; a
< t_width
; a
++)
491 fprintf(f
, "0x%02x,%c", t_bitmap
[i
* t_width
+ a
],
492 (a
+ 1) % 13 ? ' ' : '\n');
494 fprintf(f
, "0x%04x,%c", t_bitmap
[i
* t_width
+ a
],
495 (a
+ 1) % 10 ? ' ' : '\n');
500 fprintf(f
, "\n};\n");
503 void generate_raw_file(const unsigned short *t_bitmap
,
504 int t_width
, int t_height
, int t_depth
)
512 for (i
= 0; i
< t_height
; i
++)
514 for (a
= 0; a
< t_width
; a
++)
518 lo
= (t_bitmap
[i
* t_width
+ a
] & 0x00ff);
519 fwrite(&lo
, 1, 1, f
);
523 lo
= (t_bitmap
[i
* t_width
+ a
] & 0x00ff);
524 hi
= (t_bitmap
[i
* t_width
+ a
] & 0xff00) >> 8;
525 fwrite(&lo
, 1, 1, f
);
526 fwrite(&hi
, 1, 1, f
);
532 /****************************************************************************
535 * Outputs an ascii picture of the bitmap
536 ****************************************************************************/
538 void generate_ascii(int width
, int height
, struct RGBQUAD
*bitmap
)
545 /* for screen output debugging */
546 for (y
= 0; y
< height
; y
++)
548 for (x
= 0; x
< width
; x
++)
550 fprintf(f
, (brightness(bitmap
[y
* width
+ x
]) & 0x80) ? " " : "*");
556 void print_usage(void)
558 printf("Usage: %s [-i <id>] [-a] <bitmap file>\n"
559 "\t-i <id> Bitmap name (default is filename without extension)\n"
560 "\t-h <dir> Create header file in <dir>/<id>.h\n"
561 "\t-a Show ascii picture of bitmap\n"
562 "\t-r Generate RAW file (little-endian)\n"
563 "\t-f <n> Generate destination format n, default = 0\n"
564 "\t 0 Archos recorder, Ondio, Iriver H1x0 mono\n"
566 printf("\t 1 Archos player graphics library\n"
567 "\t 2 Iriver H1x0 4-grey\n"
568 "\t 3 Canonical 8-bit greyscale\n"
569 "\t 4 16-bit packed 5-6-5 RGB (iriver H300)\n"
570 "\t 5 16-bit packed and byte-swapped 5-6-5 RGB (iPod)\n"
571 "\t 6 Greyscale iPod 4-grey\n"
572 "\t 7 Greyscale X5 remote 4-grey\n");
573 printf("build date: " __DATE__
"\n\n");
576 int main(int argc
, char **argv
)
578 char *bmp_filename
= NULL
;
580 char* header_dir
= NULL
;
584 struct RGBQUAD
*bitmap
= NULL
;
585 unsigned short *t_bitmap
= NULL
;
587 int t_width
, t_height
, t_depth
;
591 for (i
= 1;i
< argc
;i
++)
593 if (argv
[i
][0] == '-')
597 case 'h': /* .h filename */
600 header_dir
= &argv
[i
][2];
604 header_dir
= argv
[i
+1];
631 case 'a': /* Ascii art */
635 case 'r': /* Raw File */
642 format
= atoi(&argv
[i
][2]);
646 format
= atoi(argv
[i
+1]);
666 bmp_filename
= argv
[i
];
684 char *ptr
=strrchr(bmp_filename
, '/');
690 for (i
= 0; id
[i
]; i
++)
695 if (read_bmp_file(bmp_filename
, &width
, &height
, &bitmap
))
701 generate_ascii(width
, height
, bitmap
);
705 if (transform_bitmap(bitmap
, width
, height
, format
, &t_bitmap
,
706 &t_width
, &t_height
, &t_depth
))
709 generate_raw_file(t_bitmap
, t_width
, t_height
, t_depth
);
711 generate_c_source(id
, header_dir
, width
, height
, t_bitmap
,
712 t_width
, t_height
, t_depth
);