No need to have \n here. panicf() won't output it anyway.
[Rockbox.git] / tools / bmp2rb.c
blob7848298136f8afd511e4b0fef6d2894989660491
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <stdbool.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
40 #define debugf printf
42 #ifdef __GNUC__
43 #define STRUCT_PACKED __attribute__((packed))
44 #else
45 #define STRUCT_PACKED
46 #pragma pack (push, 2)
47 #endif
49 struct Fileheader
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 */
67 } STRUCT_PACKED;
69 struct RGBQUAD
71 unsigned char rgbBlue;
72 unsigned char rgbGreen;
73 unsigned char rgbRed;
74 unsigned char rgbReserved;
75 } STRUCT_PACKED;
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;
95 #ifndef O_BINARY
96 #define O_BINARY 0 /* systems that don't have O_BINARY won't make a difference
97 on text and binary files */
98 #endif
100 /****************************************************************************
101 * read_bmp_file()
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);
117 unsigned short data;
118 unsigned char *bmp;
119 int width, height;
120 int padded_width;
121 int size;
122 int row, col, i;
123 int numcolors, compression;
124 int depth;
126 if (fd == -1)
128 debugf("error - can't open '%s'\n", filename);
129 return 1;
131 if (read(fd, &fh, sizeof(struct Fileheader)) !=
132 sizeof(struct Fileheader))
134 debugf("error - can't Read Fileheader Stucture\n");
135 close(fd);
136 return 2;
139 compression = readint(&fh.Compression);
141 if (compression != 0)
143 debugf("error - Unsupported compression %ld\n", compression);
144 close(fd);
145 return 3;
148 depth = readshort(&fh.BitCount);
150 if (depth <= 8)
152 numcolors = readint(&fh.ClrUsed);
153 if (numcolors == 0)
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");
160 close(fd);
161 return 4;
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");
176 close(fd);
177 return 5;
180 if (lseek(fd, (off_t)readint(&fh.OffBits), SEEK_SET) < 0)
182 debugf("error - Can't seek to start of image data\n");
183 close(fd);
184 return 6;
186 if (read(fd, (unsigned char*)bmp, (int)size) != size)
188 debugf("error - Can't read image\n");
189 close(fd);
190 return 7;
193 close(fd);
194 *get_width = width;
195 *get_height = height;
197 switch (depth)
199 case 1:
200 for (row = 0; row < height; row++)
201 for (col = 0; col < width; col++)
203 data = (bmp[(height - 1 - row) * padded_width + col / 8]
204 >> (~col & 7)) & 1;
205 (*bitmap)[row * width + col] = palette[data];
207 break;
209 case 4:
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];
217 break;
219 case 8:
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];
226 break;
228 case 16:
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;
241 break;
243 case 24:
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;
253 break;
255 case 32:
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;
265 break;
267 default: /* should never happen */
268 debugf("error - Unsupported bitmap depth %d.\n", depth);
269 return 8;
272 free(bmp);
274 return 0; /* success */
277 /****************************************************************************
278 * transform_bitmap()
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)
288 int row, col;
289 int dst_w, dst_h, dst_d;
291 switch (format)
293 case 0: /* Archos recorders, Ondio, Iriver H1x0 monochrome */
294 dst_w = width;
295 dst_h = (height + 7) / 8;
296 dst_d = 8;
297 break;
299 case 1: /* Archos player graphics library */
300 dst_w = (width + 7) / 8;
301 dst_h = height;
302 dst_d = 8;
303 break;
305 case 2: /* Iriver H1x0 4-grey */
306 dst_w = width;
307 dst_h = (height + 3) / 4;
308 dst_d = 8;
309 break;
311 case 3: /* Canonical 8-bit grayscale */
312 dst_w = width;
313 dst_h = height;
314 dst_d = 8;
315 break;
317 case 4: /* 16-bit packed RGB (5-6-5) */
318 case 5: /* 16-bit packed and byte-swapped RGB (5-6-5) */
319 dst_w = width;
320 dst_h = height;
321 dst_d = 16;
322 break;
324 case 6: /* greyscale iPods 4-grey */
325 dst_w = (width + 3) / 4;
326 dst_h = height;
327 dst_d = 8;
328 break;
330 case 7: /* greyscale X5 remote 4-grey */
331 dst_w = width;
332 dst_h = (height + 7) / 8;
333 dst_d = 16;
334 break;
336 default: /* unknown */
337 debugf("error - Undefined destination format\n");
338 return 1;
341 *dest = (unsigned short *)malloc(dst_w * dst_h * sizeof(short));
342 if (*dest == NULL)
344 debugf("error - Out of memory.\n");
345 return 2;
347 memset(*dest, 0, dst_w * dst_h * sizeof(short));
348 *dst_width = dst_w;
349 *dst_height = dst_h;
350 *dst_depth = dst_d;
352 switch (format)
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);
361 break;
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);
370 break;
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));
379 break;
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]);
387 break;
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++)
394 unsigned short rgb =
395 (((src[row * width + col].rgbRed >> 3) << 11) |
396 ((src[row * width + col].rgbGreen >> 2) << 5) |
397 ((src[row * width + col].rgbBlue >> 3)));
399 if (format == 4)
400 (*dest)[row * dst_w + col] = rgb;
401 else
402 (*dest)[row * dst_w + col] = ((rgb&0xff00)>>8)|((rgb&0x00ff)<<8);
404 break;
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));
413 break;
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);
424 break;
427 return 0;
430 /****************************************************************************
431 * generate_c_source()
433 * Outputs a C source code with the bitmap in an array, accompanied by
434 * some #define's
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)
441 FILE *f;
442 FILE *fh;
443 int i, a;
444 char header_name[1024];
446 if (!id || !id[0])
447 id = "bitmap";
449 f = stdout;
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+");
456 if (fh == NULL)
458 debugf("error - can't open '%s'\n", header_name);
459 return;
461 fprintf(fh,
462 "#define BMPHEIGHT_%s %ld\n"
463 "#define BMPWIDTH_%s %ld\n",
464 id, height, id, width);
465 if (t_depth <= 8)
466 fprintf(fh, "extern const unsigned char %s[];\n", id);
467 else
468 fprintf(fh, "extern const unsigned short %s[];\n", id);
470 fclose(fh);
471 } else {
472 fprintf(f,
473 "#define BMPHEIGHT_%s %ld\n"
474 "#define BMPWIDTH_%s %ld\n",
475 id, height, id, width);
478 if (t_depth <= 8)
479 fprintf(f, "const unsigned char %s[] = {\n", id);
480 else
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++)
487 if (t_depth <= 8)
488 fprintf(f, "0x%02x,%c", t_bitmap[i * t_width + a],
489 (a + 1) % 13 ? ' ' : '\n');
490 else
491 fprintf(f, "0x%04x,%c", t_bitmap[i * t_width + a],
492 (a + 1) % 10 ? ' ' : '\n');
494 fprintf(f, "\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)
503 FILE *f;
504 int i, a;
505 unsigned char lo,hi;
507 f = stdout;
509 for (i = 0; i < t_height; i++)
511 for (a = 0; a < t_width; a++)
513 if (t_depth <= 8)
515 lo = (t_bitmap[i * t_width + a] & 0x00ff);
516 fwrite(&lo, 1, 1, f);
518 else
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 /****************************************************************************
530 * generate_ascii()
532 * Outputs an ascii picture of the bitmap
533 ****************************************************************************/
535 void generate_ascii(int width, int height, struct RGBQUAD *bitmap)
537 FILE *f;
538 int x, y;
540 f = stdout;
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) ? " " : "*");
549 fprintf(f, "\n");
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"
569 , APPLICATION_NAME);
570 printf("build date: " __DATE__ "\n\n");
573 int main(int argc, char **argv)
575 char *bmp_filename = NULL;
576 char *id = NULL;
577 char* header_dir = NULL;
578 int i;
579 int ascii = false;
580 int format = 0;
581 struct RGBQUAD *bitmap = NULL;
582 unsigned short *t_bitmap = NULL;
583 int width, height;
584 int t_width, t_height, t_depth;
585 bool raw = false;
588 for (i = 1;i < argc;i++)
590 if (argv[i][0] == '-')
592 switch (argv[i][1])
594 case 'h': /* .h filename */
595 if (argv[i][2])
597 header_dir = &argv[i][2];
599 else if (argc > i+1)
601 header_dir = argv[i+1];
602 i++;
604 else
606 print_usage();
607 exit(1);
609 break;
611 case 'i': /* ID */
612 if (argv[i][2])
614 id = &argv[i][2];
616 else if (argc > i+1)
618 id = argv[i+1];
619 i++;
621 else
623 print_usage();
624 exit(1);
626 break;
628 case 'a': /* Ascii art */
629 ascii = true;
630 break;
632 case 'r': /* Raw File */
633 raw = true;
634 break;
636 case 'f':
637 if (argv[i][2])
639 format = atoi(&argv[i][2]);
641 else if (argc > i+1)
643 format = atoi(argv[i+1]);
644 i++;
646 else
648 print_usage();
649 exit(1);
651 break;
653 default:
654 print_usage();
655 exit(1);
656 break;
659 else
661 if (!bmp_filename)
663 bmp_filename = argv[i];
665 else
667 print_usage();
668 exit(1);
673 if (!bmp_filename)
675 print_usage();
676 exit(1);
679 if (!id)
681 char *ptr=strrchr(bmp_filename, '/');
682 if (ptr)
683 ptr++;
684 else
685 ptr = bmp_filename;
686 id = strdup(ptr);
687 for (i = 0; id[i]; i++)
688 if (id[i] == '.')
689 id[i] = '\0';
692 if (read_bmp_file(bmp_filename, &width, &height, &bitmap))
693 exit(1);
696 if (ascii)
698 generate_ascii(width, height, bitmap);
700 else
702 if (transform_bitmap(bitmap, width, height, format, &t_bitmap,
703 &t_width, &t_height, &t_depth))
704 exit(1);
705 if(raw)
706 generate_raw_file(id, t_bitmap, t_width, t_height, t_depth);
707 else
708 generate_c_source(id, header_dir, width, height, t_bitmap,
709 t_width, t_height, t_depth);
712 return 0;