Prepare new maemo release
[maemo-rb.git] / tools / bmp2rb.c
blob7fee1e617726982d5b5af059e591b4712eb37519
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <stdbool.h>
37 #include <unistd.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <fcntl.h>
43 #define debugf printf
45 #ifdef __GNUC__
46 #define STRUCT_PACKED __attribute__((packed))
47 #else
48 #define STRUCT_PACKED
49 #pragma pack (push, 2)
50 #endif
52 struct Fileheader
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 */
70 } STRUCT_PACKED;
72 struct RGBQUAD
74 unsigned char rgbBlue;
75 unsigned char rgbGreen;
76 unsigned char rgbRed;
77 unsigned char rgbReserved;
78 } STRUCT_PACKED;
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;
98 #ifndef O_BINARY
99 #define O_BINARY 0 /* systems that don't have O_BINARY won't make a difference
100 on text and binary files */
101 #endif
103 /****************************************************************************
104 * read_bmp_file()
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);
120 unsigned short data;
121 unsigned char *bmp;
122 int width, height;
123 int padded_width;
124 int size;
125 int row, col, i;
126 int numcolors, compression;
127 int depth;
129 if (fd == -1)
131 debugf("error - can't open '%s'\n", filename);
132 return 1;
134 if (read(fd, &fh, sizeof(struct Fileheader)) !=
135 sizeof(struct Fileheader))
137 debugf("error - can't Read Fileheader Stucture\n");
138 close(fd);
139 return 2;
142 compression = readint(&fh.Compression);
144 if (compression != 0)
146 debugf("error - Unsupported compression %d\n", compression);
147 close(fd);
148 return 3;
151 depth = readshort(&fh.BitCount);
153 if (depth <= 8)
155 numcolors = readint(&fh.ClrUsed);
156 if (numcolors == 0)
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");
163 close(fd);
164 return 4;
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");
179 close(fd);
180 return 5;
183 if (lseek(fd, (off_t)readint(&fh.OffBits), SEEK_SET) < 0)
185 debugf("error - Can't seek to start of image data\n");
186 close(fd);
187 return 6;
189 if (read(fd, (unsigned char*)bmp, (int)size) != size)
191 debugf("error - Can't read image\n");
192 close(fd);
193 return 7;
196 close(fd);
197 *get_width = width;
198 *get_height = height;
200 switch (depth)
202 case 1:
203 for (row = 0; row < height; row++)
204 for (col = 0; col < width; col++)
206 data = (bmp[(height - 1 - row) * padded_width + col / 8]
207 >> (~col & 7)) & 1;
208 (*bitmap)[row * width + col] = palette[data];
210 break;
212 case 4:
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];
220 break;
222 case 8:
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];
229 break;
231 case 16:
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;
244 break;
246 case 24:
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;
256 break;
258 case 32:
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;
268 break;
270 default: /* should never happen */
271 debugf("error - Unsupported bitmap depth %d.\n", depth);
272 return 8;
275 free(bmp);
277 return 0; /* success */
280 /****************************************************************************
281 * transform_bitmap()
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)
291 int row, col;
292 int dst_w, dst_h, dst_d;
294 switch (format)
296 case 0: /* Archos recorders, Ondio, Iriver H1x0 monochrome */
297 dst_w = width;
298 dst_h = (height + 7) / 8;
299 dst_d = 8;
300 break;
302 case 1: /* Archos player graphics library */
303 dst_w = (width + 7) / 8;
304 dst_h = height;
305 dst_d = 8;
306 break;
308 case 2: /* Iriver H1x0 4-grey */
309 dst_w = width;
310 dst_h = (height + 3) / 4;
311 dst_d = 8;
312 break;
314 case 3: /* Canonical 8-bit grayscale */
315 dst_w = width;
316 dst_h = height;
317 dst_d = 8;
318 break;
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*/
323 dst_w = width;
324 dst_h = height;
325 dst_d = 16;
326 break;
328 case 6: /* greyscale iPods 4-grey */
329 dst_w = (width + 3) / 4;
330 dst_h = height;
331 dst_d = 8;
332 break;
334 case 7: /* greyscale X5 remote 4-grey */
335 dst_w = width;
336 dst_h = (height + 7) / 8;
337 dst_d = 16;
338 break;
340 default: /* unknown */
341 debugf("error - Undefined destination format\n");
342 return 1;
345 *dest = (unsigned short *)malloc(dst_w * dst_h * sizeof(short));
346 if (*dest == NULL)
348 debugf("error - Out of memory.\n");
349 return 2;
351 memset(*dest, 0, dst_w * dst_h * sizeof(short));
352 *dst_width = dst_w;
353 *dst_height = dst_h;
354 *dst_depth = dst_d;
356 switch (format)
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);
365 break;
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);
374 break;
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));
383 break;
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]);
391 break;
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++)
398 unsigned short rgb =
399 (((src[row * width + col].rgbRed >> 3) << 11) |
400 ((src[row * width + col].rgbGreen >> 2) << 5) |
401 ((src[row * width + col].rgbBlue >> 3)));
403 if (format == 4)
404 (*dest)[row * dst_w + col] = rgb;
405 else
406 (*dest)[row * dst_w + col] = ((rgb&0xff00)>>8)|((rgb&0x00ff)<<8);
408 break;
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));
417 break;
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);
428 break;
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++)
434 unsigned short rgb =
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;
441 break;
444 return 0;
447 /****************************************************************************
448 * generate_c_source()
450 * Outputs a C source code with the bitmap in an array, accompanied by
451 * some #define's
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, bool t_mono, bool create_bm)
458 FILE *f;
459 FILE *fh;
460 int i, a;
461 char header_name[1024];
462 bool have_header = header_dir && header_dir[0];
463 create_bm = have_header && create_bm;
465 if (!id || !id[0])
466 id = "bitmap";
468 f = stdout;
470 if (have_header)
472 snprintf(header_name,sizeof(header_name),"%s/%s.h",header_dir,id);
473 fh = fopen(header_name,"w+");
475 if (fh == NULL)
477 debugf("error - can't open '%s'\n", header_name);
478 return;
480 fprintf(fh,
481 "#define BMPHEIGHT_%s %d\n"
482 "#define BMPWIDTH_%s %d\n",
483 id, height, id, width);
484 if (t_depth <= 8)
485 fprintf(fh, "extern const unsigned char %s[];\n", id);
486 else
487 fprintf(fh, "extern const unsigned short %s[];\n", id);
489 if (create_bm)
491 fprintf(f, "#include \"lcd.h\"\n");
492 fprintf(fh, "extern const struct bitmap bm_%s;\n", id);
494 fclose(fh);
495 } else {
496 fprintf(f,
497 "#define BMPHEIGHT_%s %d\n"
498 "#define BMPWIDTH_%s %d\n",
499 id, height, id, width);
502 if (create_bm) {
503 fprintf(f, "#include \"%s\"\n", header_name);
506 if (t_depth <= 8)
507 fprintf(f, "const unsigned char %s[] = {\n", id);
508 else
509 fprintf(f, "const unsigned short %s[] = {\n", id);
511 for (i = 0; i < t_height; i++)
513 for (a = 0; a < t_width; a++)
515 if (t_depth <= 8)
516 fprintf(f, "0x%02x,%c", t_bitmap[i * t_width + a],
517 (a + 1) % 13 ? ' ' : '\n');
518 else
519 fprintf(f, "0x%04x,%c", t_bitmap[i * t_width + a],
520 (a + 1) % 10 ? ' ' : '\n');
522 fprintf(f, "\n");
525 fprintf(f, "\n};\n\n");
527 if (create_bm) {
528 char format_line[] = " .format = FORMAT_NATIVE, \n";
529 fprintf(f, "const struct bitmap bm_%s = { \n"
530 " .width = BMPWIDTH_%s, \n"
531 " .height = BMPHEIGHT_%s, \n"
532 "%s"
533 " .data = (unsigned char*)%s,\n"
534 "};\n",
535 id, id, id,
536 t_mono ? "" : format_line,
537 id);
541 void generate_raw_file(const unsigned short *t_bitmap,
542 int t_width, int t_height, int t_depth)
544 FILE *f;
545 int i, a;
546 unsigned char lo,hi;
548 f = stdout;
550 for (i = 0; i < t_height; i++)
552 for (a = 0; a < t_width; a++)
554 if (t_depth <= 8)
556 lo = (t_bitmap[i * t_width + a] & 0x00ff);
557 fwrite(&lo, 1, 1, f);
559 else
561 lo = (t_bitmap[i * t_width + a] & 0x00ff);
562 hi = (t_bitmap[i * t_width + a] & 0xff00) >> 8;
563 fwrite(&lo, 1, 1, f);
564 fwrite(&hi, 1, 1, f);
570 /****************************************************************************
571 * generate_ascii()
573 * Outputs an ascii picture of the bitmap
574 ****************************************************************************/
576 void generate_ascii(int width, int height, struct RGBQUAD *bitmap)
578 FILE *f;
579 int x, y;
581 f = stdout;
583 /* for screen output debugging */
584 for (y = 0; y < height; y++)
586 for (x = 0; x < width; x++)
588 fprintf(f, (brightness(bitmap[y * width + x]) & 0x80) ? " " : "*");
590 fprintf(f, "\n");
594 void print_usage(void)
596 printf("Usage: %s [-i <id>] [-a] <bitmap file>\n"
597 "\t-i <id> Bitmap name (default is filename without extension)\n"
598 "\t-h <dir> Create header file in <dir>/<id>.h\n"
599 "\t-a Show ascii picture of bitmap\n"
600 "\t-b Create bitmap struct along with pixel array\n"
601 "\t-r Generate RAW file (little-endian)\n"
602 "\t-f <n> Generate destination format n, default = 0\n"
603 "\t 0 Archos recorder, Ondio, Iriver H1x0 mono\n"
604 , APPLICATION_NAME);
605 printf("\t 1 Archos player graphics library\n"
606 "\t 2 Iriver H1x0 4-grey\n"
607 "\t 3 Canonical 8-bit greyscale\n"
608 "\t 4 16-bit packed 5-6-5 RGB (iriver H300)\n"
609 "\t 5 16-bit packed and byte-swapped 5-6-5 RGB (iPod, Fuzev2)\n"
610 "\t 6 Greyscale iPod 4-grey\n"
611 "\t 7 Greyscale X5 remote 4-grey\n"
612 "\t 8 16-bit packed 5-6-5 RGB with a vertical stride\n");
613 printf("build date: " __DATE__ "\n\n");
616 int main(int argc, char **argv)
618 char *bmp_filename = NULL;
619 char *id = NULL;
620 char* header_dir = NULL;
621 int i;
622 int ascii = false;
623 int format = 0;
624 struct RGBQUAD *bitmap = NULL;
625 unsigned short *t_bitmap = NULL;
626 int width, height;
627 int t_width, t_height, t_depth;
628 bool raw = false;
629 bool create_bm = false;
632 for (i = 1;i < argc;i++)
634 if (argv[i][0] == '-')
636 switch (argv[i][1])
638 case 'h': /* .h filename */
639 if (argv[i][2])
641 header_dir = &argv[i][2];
643 else if (argc > i+1)
645 header_dir = argv[i+1];
646 i++;
648 else
650 print_usage();
651 exit(1);
653 break;
655 case 'i': /* ID */
656 if (argv[i][2])
658 id = &argv[i][2];
660 else if (argc > i+1)
662 id = argv[i+1];
663 i++;
665 else
667 print_usage();
668 exit(1);
670 break;
672 case 'a': /* Ascii art */
673 ascii = true;
674 break;
676 case 'b':
677 create_bm = true;
678 break;
680 case 'r': /* Raw File */
681 raw = true;
682 break;
684 case 'f':
685 if (argv[i][2])
687 format = atoi(&argv[i][2]);
689 else if (argc > i+1)
691 format = atoi(argv[i+1]);
692 i++;
694 else
696 print_usage();
697 exit(1);
699 break;
701 default:
702 print_usage();
703 exit(1);
704 break;
707 else
709 if (!bmp_filename)
711 bmp_filename = argv[i];
713 else
715 print_usage();
716 exit(1);
721 if (!bmp_filename)
723 print_usage();
724 exit(1);
727 if (!id)
729 char *ptr=strrchr(bmp_filename, '/');
730 if (ptr)
731 ptr++;
732 else
733 ptr = bmp_filename;
734 id = strdup(ptr);
735 for (i = 0; id[i]; i++)
736 if (id[i] == '.')
737 id[i] = '\0';
740 if (read_bmp_file(bmp_filename, &width, &height, &bitmap))
741 exit(1);
744 if (ascii)
746 generate_ascii(width, height, bitmap);
748 else
750 if (transform_bitmap(bitmap, width, height, format, &t_bitmap,
751 &t_width, &t_height, &t_depth))
752 exit(1);
753 if(raw)
754 generate_raw_file(t_bitmap, t_width, t_height, t_depth);
755 else
756 generate_c_source(id, header_dir, width, height, t_bitmap,
757 t_width, t_height, t_depth,
758 format <= 1, create_bm);
761 return 0;