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 ****************************************************************************/
37 #include <sys/types.h>
44 #define STRUCT_PACKED __attribute__((packed))
47 #pragma pack (push, 2)
52 unsigned short Type
; /* signature - 'BM' */
53 unsigned int Size
; /* file size in bytes */
54 unsigned short Reserved1
; /* 0 */
55 unsigned short Reserved2
; /* 0 */
56 unsigned int OffBits
; /* offset to bitmap */
57 unsigned int StructSize
; /* size of this struct (40) */
58 unsigned int Width
; /* bmap width in pixels */
59 unsigned int Height
; /* bmap height in pixels */
60 unsigned short Planes
; /* num planes - always 1 */
61 unsigned short BitCount
; /* bits per pixel */
62 unsigned int Compression
; /* compression flag */
63 unsigned int SizeImage
; /* image size in bytes */
64 int XPelsPerMeter
; /* horz resolution */
65 int YPelsPerMeter
; /* vert resolution */
66 unsigned int ClrUsed
; /* 0 -> color table size */
67 unsigned int ClrImportant
; /* important color count */
72 unsigned char rgbBlue
;
73 unsigned char rgbGreen
;
75 unsigned char rgbReserved
;
78 short readshort(void* value
)
80 unsigned char* bytes
= (unsigned char*) value
;
81 return bytes
[0] | (bytes
[1] << 8);
84 int readint(void* value
)
86 unsigned char* bytes
= (unsigned char*) value
;
87 return bytes
[0] | (bytes
[1] << 8) | (bytes
[2] << 16) | (bytes
[3] << 24);
90 unsigned char brightness(struct RGBQUAD color
)
92 return (3 * (unsigned int)color
.rgbRed
+ 6 * (unsigned int)color
.rgbGreen
93 + (unsigned int)color
.rgbBlue
) / 10;
97 #define O_BINARY 0 /* systems that don't have O_BINARY won't make a difference
98 on text and binary files */
101 /****************************************************************************
104 * Reads an uncompressed BMP file and puts the data in a 4-byte-per-pixel
105 * (RGBQUAD) array. Returns 0 on success.
107 ***************************************************************************/
109 int read_bmp_file(char* filename
,
110 int *get_width
, /* in pixels */
111 int *get_height
, /* in pixels */
112 struct RGBQUAD
**bitmap
)
114 struct Fileheader fh
;
115 struct RGBQUAD palette
[256];
117 int fd
= open(filename
, O_RDONLY
| O_BINARY
);
124 int numcolors
, compression
;
129 debugf("error - can't open '%s'\n", filename
);
132 if (read(fd
, &fh
, sizeof(struct Fileheader
)) !=
133 sizeof(struct Fileheader
))
135 debugf("error - can't Read Fileheader Stucture\n");
140 compression
= readint(&fh
.Compression
);
142 if (compression
!= 0)
144 debugf("error - Unsupported compression %d\n", compression
);
149 depth
= readshort(&fh
.BitCount
);
153 numcolors
= readint(&fh
.ClrUsed
);
155 numcolors
= 1 << depth
;
157 if (read(fd
, &palette
[0], numcolors
* sizeof(struct RGBQUAD
))
158 != (int)(numcolors
* sizeof(struct RGBQUAD
)))
160 debugf("error - Can't read bitmap's color palette\n");
166 width
= readint(&fh
.Width
);
167 height
= readint(&fh
.Height
);
168 padded_width
= ((width
* depth
+ 31) / 8) & ~3; /* aligned 4-bytes boundaries */
170 size
= padded_width
* height
; /* read this many bytes */
171 bmp
= (unsigned char *)malloc(size
);
172 *bitmap
= (struct RGBQUAD
*)malloc(width
* height
* sizeof(struct RGBQUAD
));
174 if ((bmp
== NULL
) || (*bitmap
== NULL
))
176 debugf("error - Out of memory\n");
181 if (lseek(fd
, (off_t
)readint(&fh
.OffBits
), SEEK_SET
) < 0)
183 debugf("error - Can't seek to start of image data\n");
187 if (read(fd
, (unsigned char*)bmp
, (int)size
) != size
)
189 debugf("error - Can't read image\n");
196 *get_height
= height
;
201 for (row
= 0; row
< height
; row
++)
202 for (col
= 0; col
< width
; col
++)
204 data
= (bmp
[(height
- 1 - row
) * padded_width
+ col
/ 8]
206 (*bitmap
)[row
* width
+ col
] = palette
[data
];
211 for (row
= 0; row
< height
; row
++)
212 for (col
= 0; col
< width
; col
++)
214 data
= (bmp
[(height
- 1 - row
) * padded_width
+ col
/ 2]
215 >> (4 * (~col
& 1))) & 0x0F;
216 (*bitmap
)[row
* width
+ col
] = palette
[data
];
221 for (row
= 0; row
< height
; row
++)
222 for (col
= 0; col
< width
; col
++)
224 data
= bmp
[(height
- 1 - row
) * padded_width
+ col
];
225 (*bitmap
)[row
* width
+ col
] = palette
[data
];
230 for (row
= 0; row
< height
; row
++)
231 for (col
= 0; col
< width
; col
++)
233 data
= readshort(&bmp
[(height
- 1 - row
) * padded_width
+ 2 * col
]);
234 (*bitmap
)[row
* width
+ col
].rgbRed
=
235 ((data
>> 7) & 0xF8) | ((data
>> 12) & 0x07);
236 (*bitmap
)[row
* width
+ col
].rgbGreen
=
237 ((data
>> 2) & 0xF8) | ((data
>> 7) & 0x07);
238 (*bitmap
)[row
* width
+ col
].rgbBlue
=
239 ((data
<< 3) & 0xF8) | ((data
>> 2) & 0x07);
240 (*bitmap
)[row
* width
+ col
].rgbReserved
= 0;
245 for (row
= 0; row
< height
; row
++)
246 for (col
= 0; col
< width
; col
++)
248 i
= (height
- 1 - row
) * padded_width
+ 3 * col
;
249 (*bitmap
)[row
* width
+ col
].rgbRed
= bmp
[i
+2];
250 (*bitmap
)[row
* width
+ col
].rgbGreen
= bmp
[i
+1];
251 (*bitmap
)[row
* width
+ col
].rgbBlue
= bmp
[i
];
252 (*bitmap
)[row
* width
+ col
].rgbReserved
= 0;
257 for (row
= 0; row
< height
; row
++)
258 for (col
= 0; col
< width
; col
++)
260 i
= (height
- 1 - row
) * padded_width
+ 4 * col
;
261 (*bitmap
)[row
* width
+ col
].rgbRed
= bmp
[i
+2];
262 (*bitmap
)[row
* width
+ col
].rgbGreen
= bmp
[i
+1];
263 (*bitmap
)[row
* width
+ col
].rgbBlue
= bmp
[i
];
264 (*bitmap
)[row
* width
+ col
].rgbReserved
= 0;
268 default: /* should never happen */
269 debugf("error - Unsupported bitmap depth %d.\n", depth
);
275 return 0; /* success */
278 /****************************************************************************
281 * Transform a 4-byte-per-pixel bitmap (RGBQUAD) into one of the supported
282 * destination formats
283 ****************************************************************************/
285 int transform_bitmap(const struct RGBQUAD
*src
, int width
, int height
,
286 int format
, unsigned short **dest
, int *dst_width
,
287 int *dst_height
, int *dst_depth
)
290 int dst_w
, dst_h
, dst_d
;
294 case 0: /* Archos recorders, Ondio, Iriver H1x0 monochrome */
296 dst_h
= (height
+ 7) / 8;
300 case 1: /* Archos player graphics library */
301 dst_w
= (width
+ 7) / 8;
306 case 2: /* Iriver H1x0 4-grey */
308 dst_h
= (height
+ 3) / 4;
312 case 3: /* Canonical 8-bit grayscale */
318 case 4: /* 16-bit packed RGB (5-6-5) */
319 case 5: /* 16-bit packed and byte-swapped RGB (5-6-5) */
325 case 6: /* greyscale iPods 4-grey */
326 dst_w
= (width
+ 3) / 4;
331 case 7: /* greyscale X5 remote 4-grey */
333 dst_h
= (height
+ 7) / 8;
337 default: /* unknown */
338 debugf("error - Undefined destination format\n");
342 *dest
= (unsigned short *)malloc(dst_w
* dst_h
* sizeof(short));
345 debugf("error - Out of memory.\n");
348 memset(*dest
, 0, dst_w
* dst_h
* sizeof(short));
355 case 0: /* Archos recorders, Ondio, Iriver H1x0 b&w */
356 for (row
= 0; row
< height
; row
++)
357 for (col
= 0; col
< width
; col
++)
359 (*dest
)[(row
/8) * dst_w
+ col
] |=
360 (~brightness(src
[row
* width
+ col
]) & 0x80) >> (~row
& 7);
364 case 1: /* Archos player graphics library */
365 for (row
= 0; row
< height
; row
++)
366 for (col
= 0; col
< width
; col
++)
368 (*dest
)[row
* dst_w
+ (col
/8)] |=
369 (~brightness(src
[row
* width
+ col
]) & 0x80) >> (col
& 7);
373 case 2: /* Iriver H1x0 4-grey */
374 for (row
= 0; row
< height
; row
++)
375 for (col
= 0; col
< width
; col
++)
377 (*dest
)[(row
/4) * dst_w
+ col
] |=
378 (~brightness(src
[row
* width
+ col
]) & 0xC0) >> (2 * (~row
& 3));
382 case 3: /* Canonical 8-bit grayscale */
383 for (row
= 0; row
< height
; row
++)
384 for (col
= 0; col
< width
; col
++)
386 (*dest
)[row
* dst_w
+ col
] = brightness(src
[row
* width
+ col
]);
390 case 4: /* 16-bit packed RGB (5-6-5) */
391 case 5: /* 16-bit packed and byte-swapped RGB (5-6-5) */
392 for (row
= 0; row
< height
; row
++)
393 for (col
= 0; col
< width
; col
++)
396 (((src
[row
* width
+ col
].rgbRed
>> 3) << 11) |
397 ((src
[row
* width
+ col
].rgbGreen
>> 2) << 5) |
398 ((src
[row
* width
+ col
].rgbBlue
>> 3)));
401 (*dest
)[row
* dst_w
+ col
] = rgb
;
403 (*dest
)[row
* dst_w
+ col
] = ((rgb
&0xff00)>>8)|((rgb
&0x00ff)<<8);
407 case 6: /* greyscale iPods 4-grey */
408 for (row
= 0; row
< height
; row
++)
409 for (col
= 0; col
< width
; col
++)
411 (*dest
)[row
* dst_w
+ (col
/4)] |=
412 (~brightness(src
[row
* width
+ col
]) & 0xC0) >> (2 * (col
& 3));
416 case 7: /* greyscale X5 remote 4-grey */
417 for (row
= 0; row
< height
; row
++)
418 for (col
= 0; col
< width
; col
++)
420 unsigned short data
= (~brightness(src
[row
* width
+ col
]) & 0xC0) >> 6;
422 data
= (data
| (data
<< 7)) & 0x0101;
423 (*dest
)[(row
/8) * dst_w
+ col
] |= data
<< (row
& 7);
431 /****************************************************************************
432 * generate_c_source()
434 * Outputs a C source code with the bitmap in an array, accompanied by
436 ****************************************************************************/
438 void generate_c_source(char *id
, char* header_dir
, int width
, int height
,
439 const unsigned short *t_bitmap
, int t_width
,
440 int t_height
, int t_depth
)
445 char header_name
[1024];
452 if (header_dir
&& header_dir
[0])
454 snprintf(header_name
,sizeof(header_name
),"%s/%s.h",header_dir
,id
);
455 fh
= fopen(header_name
,"w+");
459 debugf("error - can't open '%s'\n", header_name
);
463 "#define BMPHEIGHT_%s %d\n"
464 "#define BMPWIDTH_%s %d\n",
465 id
, height
, id
, width
);
467 fprintf(fh
, "extern const unsigned char %s[];\n", id
);
469 fprintf(fh
, "extern const unsigned short %s[];\n", id
);
474 "#define BMPHEIGHT_%s %d\n"
475 "#define BMPWIDTH_%s %d\n",
476 id
, height
, id
, width
);
480 fprintf(f
, "const unsigned char %s[] = {\n", id
);
482 fprintf(f
, "const unsigned short %s[] = {\n", id
);
484 for (i
= 0; i
< t_height
; i
++)
486 for (a
= 0; a
< t_width
; a
++)
489 fprintf(f
, "0x%02x,%c", t_bitmap
[i
* t_width
+ a
],
490 (a
+ 1) % 13 ? ' ' : '\n');
492 fprintf(f
, "0x%04x,%c", t_bitmap
[i
* t_width
+ a
],
493 (a
+ 1) % 10 ? ' ' : '\n');
498 fprintf(f
, "\n};\n");
501 void generate_raw_file(const unsigned short *t_bitmap
,
502 int t_width
, int t_height
, int t_depth
)
510 for (i
= 0; i
< t_height
; i
++)
512 for (a
= 0; a
< t_width
; a
++)
516 lo
= (t_bitmap
[i
* t_width
+ a
] & 0x00ff);
517 fwrite(&lo
, 1, 1, f
);
521 lo
= (t_bitmap
[i
* t_width
+ a
] & 0x00ff);
522 hi
= (t_bitmap
[i
* t_width
+ a
] & 0xff00) >> 8;
523 fwrite(&lo
, 1, 1, f
);
524 fwrite(&hi
, 1, 1, f
);
530 /****************************************************************************
533 * Outputs an ascii picture of the bitmap
534 ****************************************************************************/
536 void generate_ascii(int width
, int height
, struct RGBQUAD
*bitmap
)
543 /* for screen output debugging */
544 for (y
= 0; y
< height
; y
++)
546 for (x
= 0; x
< width
; x
++)
548 fprintf(f
, (brightness(bitmap
[y
* width
+ x
]) & 0x80) ? " " : "*");
554 void print_usage(void)
556 printf("Usage: %s [-i <id>] [-a] <bitmap file>\n"
557 "\t-i <id> Bitmap name (default is filename without extension)\n"
558 "\t-h <dir> Create header file in <dir>/<id>.h\n"
559 "\t-a Show ascii picture of bitmap\n"
560 "\t-r Generate RAW file (little-endian)\n"
561 "\t-f <n> Generate destination format n, default = 0\n"
562 "\t 0 Archos recorder, Ondio, Iriver H1x0 mono\n"
564 printf("\t 1 Archos player graphics library\n"
565 "\t 2 Iriver H1x0 4-grey\n"
566 "\t 3 Canonical 8-bit greyscale\n"
567 "\t 4 16-bit packed 5-6-5 RGB (iriver H300)\n"
568 "\t 5 16-bit packed and byte-swapped 5-6-5 RGB (iPod)\n"
569 "\t 6 Greyscale iPod 4-grey\n"
570 "\t 7 Greyscale X5 remote 4-grey\n");
571 printf("build date: " __DATE__
"\n\n");
574 int main(int argc
, char **argv
)
576 char *bmp_filename
= NULL
;
578 char* header_dir
= NULL
;
582 struct RGBQUAD
*bitmap
= NULL
;
583 unsigned short *t_bitmap
= NULL
;
585 int t_width
, t_height
, t_depth
;
589 for (i
= 1;i
< argc
;i
++)
591 if (argv
[i
][0] == '-')
595 case 'h': /* .h filename */
598 header_dir
= &argv
[i
][2];
602 header_dir
= argv
[i
+1];
629 case 'a': /* Ascii art */
633 case 'r': /* Raw File */
640 format
= atoi(&argv
[i
][2]);
644 format
= atoi(argv
[i
+1]);
664 bmp_filename
= argv
[i
];
682 char *ptr
=strrchr(bmp_filename
, '/');
688 for (i
= 0; id
[i
]; i
++)
693 if (read_bmp_file(bmp_filename
, &width
, &height
, &bitmap
))
699 generate_ascii(width
, height
, bitmap
);
703 if (transform_bitmap(bitmap
, width
, height
, format
, &t_bitmap
,
704 &t_width
, &t_height
, &t_depth
))
707 generate_raw_file(t_bitmap
, t_width
, t_height
, t_depth
);
709 generate_c_source(id
, header_dir
, width
, height
, t_bitmap
,
710 t_width
, t_height
, t_depth
);