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 ****************************************************************************/
23 2005-04-16 Tomas Salfischberger:
24 - New BMP loader function, based on the old one (borrowed a lot of
25 calculations and checks there.)
26 - Conversion part needs some optimization, doing unneeded calulations now.
27 2006-11-18 Jens Arnold: complete rework
28 - All canonical formats supported now (1, 4, 8, 15/16, 24 and 32 bit)
29 - better protection against malformed / non-standard BMPs
30 - code heavily optimised for both size and speed
31 - dithering for 2 bit targets
41 #ifdef HAVE_REMOTE_LCD
42 #include "lcd-remote.h"
55 #define STRUCT_PACKED __attribute__((packed))
58 #pragma pack (push, 2)
61 /* BMP header structure */
63 uint16_t type
; /* signature - 'BM' */
64 uint32_t size
; /* file size in bytes */
65 uint16_t reserved1
; /* 0 */
66 uint16_t reserved2
; /* 0 */
67 uint32_t off_bits
; /* offset to bitmap */
68 uint32_t struct_size
; /* size of this struct (40) */
69 int32_t width
; /* bmap width in pixels */
70 int32_t height
; /* bmap height in pixels */
71 uint16_t planes
; /* num planes - always 1 */
72 uint16_t bit_count
; /* bits per pixel */
73 uint32_t compression
; /* compression flag */
74 uint32_t size_image
; /* image size in bytes */
75 int32_t x_pels_per_meter
; /* horz resolution */
76 int32_t y_pels_per_meter
; /* vert resolution */
77 uint32_t clr_used
; /* 0 -> color table size */
78 uint32_t clr_important
; /* important color count */
82 struct { /* Little endian */
86 unsigned char reserved
;
91 /* masks for supported BI_BITFIELDS encodings (16/32 bit), little endian */
92 static const unsigned char bitfields
[3][12] = {
93 { 0x00,0x7c,0x00,0, 0xe0,0x03,0x00,0, 0x1f,0x00,0x00,0 }, /* 15 bit */
94 { 0x00,0xf8,0x00,0, 0xe0,0x07,0x00,0, 0x1f,0x00,0x00,0 }, /* 16 bit */
95 { 0x00,0x00,0xff,0, 0x00,0xff,0x00,0, 0xff,0x00,0x00,0 }, /* 32 bit */
98 #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
99 /* canonical ordered dither matrix */
100 static const unsigned char dither_matrix
[16][16] = {
101 { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 },
102 { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 },
103 { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 },
104 { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 },
105 { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 },
106 { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 },
107 { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 },
108 { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 },
109 { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 },
110 { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 },
111 { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 },
112 { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 },
113 { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 },
114 { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 },
115 { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 },
116 { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 }
120 #if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \
121 || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH == 2) \
122 && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED))
123 static const unsigned short vi_pattern
[4] = {
124 0x0101, 0x0100, 0x0001, 0x0000
128 /* little endian functions */
129 static inline unsigned readshort(uint16_t *value
)
131 unsigned char* bytes
= (unsigned char*) value
;
132 return (unsigned)bytes
[0] | ((unsigned)bytes
[1] << 8);
135 static inline uint32_t readlong(uint32_t *value
)
137 unsigned char* bytes
= (unsigned char*) value
;
138 return (uint32_t)bytes
[0] | ((uint32_t)bytes
[1] << 8) |
139 ((uint32_t)bytes
[2] << 16) | ((uint32_t)bytes
[3] << 24);
142 static inline unsigned brightness(union rgb_union color
)
144 return (3 * (unsigned)color
.red
+ 6 * (unsigned)color
.green
145 + (unsigned)color
.blue
) / 10;
148 /******************************************************************************
151 * Reads a BMP file and puts the data in rockbox format in *bitmap.
153 *****************************************************************************/
154 int read_bmp_file(const char* filename
,
160 fd
= open(filename
, O_RDONLY
);
162 /* Exit if file opening failed */
164 DEBUGF("read_bmp_file: can't open '%s', rc: %d\n", filename
, fd
);
168 ret
= read_bmp_fd(fd
, bm
, maxsize
, format
);
173 /******************************************************************************
176 * Reads a BMP file in an open file descriptor and puts the data in rockbox
179 *****************************************************************************/
180 int read_bmp_fd(int fd
,
185 struct bmp_header bmph
;
186 int width
, height
, padded_width
;
187 int dst_height
, dst_width
;
188 int depth
, numcolors
, compression
, totalsize
;
190 int rowstart
, rowstop
, rowstep
;
192 unsigned char *bitmap
= bm
->data
;
193 uint32_t bmpbuf
[LCD_WIDTH
]; /* Buffer for one line */
194 uint32_t palette
[256];
195 #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
196 bool transparent
= false;
198 #ifdef HAVE_REMOTE_LCD
201 if (format
& FORMAT_REMOTE
) {
203 #if LCD_REMOTE_DEPTH == 1
204 format
= FORMAT_MONO
;
206 format
&= ~FORMAT_REMOTE
;
209 #endif /* HAVE_REMOTE_LCD */
210 if (format
& FORMAT_TRANSPARENT
) {
212 format
&= ~FORMAT_TRANSPARENT
;
214 if (format
& FORMAT_DITHER
) {
216 format
&= ~FORMAT_DITHER
;
221 #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
223 /* read fileheader */
224 ret
= read(fd
, &bmph
, sizeof(struct bmp_header
));
229 if (ret
!= sizeof(struct bmp_header
)) {
230 DEBUGF("read_bmp_fd: can't read BMP header.");
234 width
= readlong(&bmph
.width
);
235 if (width
> LCD_WIDTH
) {
236 DEBUGF("read_bmp_fd: Bitmap too wide (%d pixels, max is %d)\n",
241 height
= readlong(&bmph
.height
);
242 if (height
< 0) { /* Top-down BMP file */
247 } else { /* normal BMP */
248 rowstart
= height
- 1;
253 depth
= readshort(&bmph
.bit_count
);
254 padded_width
= ((width
* depth
+ 31) >> 3) & ~3; /* 4-byte boundary aligned */
256 #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
257 if (format
== FORMAT_ANY
) {
259 format
= FORMAT_MONO
;
261 format
= FORMAT_NATIVE
;
264 #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
265 /* returning image size */
269 #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
270 if (format
== FORMAT_NATIVE
) {
271 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
273 #if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)
275 dst_height
= (height
+ 7) >> 3;
276 #endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */
277 totalsize
= dst_width
* dst_height
* sizeof(fb_remote_data
);
279 #endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */
282 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
283 dst_width
= (width
+ 3) >> 2;
285 #elif LCD_PIXELFORMAT == VERTICAL_PACKING
287 dst_height
= (height
+ 3) >> 2;
288 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
290 dst_height
= (height
+ 7) >> 3;
291 #endif /* LCD_PIXELFORMAT */
292 #elif LCD_DEPTH == 16
295 #endif /* LCD_DEPTH */
296 totalsize
= dst_width
* dst_height
* sizeof(fb_data
);
299 #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
302 dst_height
= (height
+ 7) >> 3;
303 totalsize
= dst_width
* dst_height
;
306 /* Check if this fits the buffer */
307 if (totalsize
> maxsize
) {
308 DEBUGF("read_bmp_fd: Bitmap too large for buffer: "
309 "%d bytes.\n", totalsize
);
313 compression
= readlong(&bmph
.compression
);
315 numcolors
= readlong(&bmph
.clr_used
);
317 numcolors
= 1 << depth
;
319 numcolors
= (compression
== 3) ? 3 : 0;
321 if (numcolors
> 0 && numcolors
<= 256) {
322 if (read(fd
, palette
, numcolors
* sizeof(uint32_t))
323 != numcolors
* (int)sizeof(uint32_t))
325 DEBUGF("read_bmp_fd: Can't read color palette\n");
333 /* don't dither 16 bit BMP to LCD with same or larger depth */
334 #ifdef HAVE_REMOTE_LCD
339 if (compression
== 0) { /* BI_RGB, i.e. 15 bit */
342 } /* else fall through */
345 if (compression
== 3) { /* BI_BITFIELDS */
346 if (!memcmp(palette
, bitfields
[0], 12)) { /* 15 bit */
350 if (!memcmp(palette
, bitfields
[1], 12) /* 16 bit */
351 || !memcmp(palette
, bitfields
[2], 12)) /* 32 bit */
355 } /* else fall through */
358 if (compression
!= 0) { /* not BI_RGB */
359 DEBUGF("read_bmp_fd: Unsupported compression (type %d)\n",
366 /* Search to the beginning of the image data */
367 lseek(fd
, (off_t
)readlong(&bmph
.off_bits
), SEEK_SET
);
369 memset(bitmap
, 0, totalsize
);
371 /* loop to read rows and put them to buffer */
372 for (row
= rowstart
; row
!= rowstop
; row
+= rowstep
) {
378 union rgb_union q0
, q1
;
381 ret
= read(fd
, bmpbuf
, padded_width
);
382 if (ret
!= padded_width
) {
383 DEBUGF("read_bmp_fd: error reading image, read returned: %d "
384 "expected: %d\n", ret
, padded_width
);
388 /* convert whole line in-place to XRGB8888 (little endian) */
394 p
= (unsigned char*)bmpbuf
+ ((width
+ 7) >> 3);
395 mask
= 0x80 >> ((width
+ 7) & 7);
396 while (p
> (unsigned char*)bmpbuf
) {
398 for (; mask
<= 0x80; mask
<<= 1)
399 *(--rp
) = (data
& mask
) ? q1
.raw
: q0
.raw
;
407 p
= (unsigned char*)bmpbuf
+ ((width
+ 1) >> 1);
408 while (p
> (unsigned char*)bmpbuf
) {
410 *(--rp
) = palette
[data
& 0x0f];
411 *(--rp
) = palette
[data
>> 4];
416 p
= (unsigned char*)bmpbuf
+ width
;
417 while (p
> (unsigned char*)bmpbuf
)
418 *(--rp
) = palette
[*(--p
)];
423 p2
= (uint16_t *)bmpbuf
+ width
;
424 while (p2
> (uint16_t *)bmpbuf
) {
425 unsigned component
, rgb
;
427 data
= letoh16(*(--p2
));
429 component
= (data
<< 3) & 0xf8;
430 #ifdef ROCKBOX_BIG_ENDIAN
431 rgb
= (component
| (component
>> 5)) << 8;
435 component
= data
& 0xf8;
436 rgb
|= component
| (component
>> 5);
439 component
= data
& 0xfc;
440 rgb
|= component
| (component
>> 6);
444 component
= data
& 0xf8;
445 rgb
= (rgb
<< 8) | component
| (component
>> 5);
447 #else /* little endian */
448 rgb
= component
| (component
>> 5);
452 component
= data
& 0xf8;
453 rgb
|= (component
| (component
>> 5)) << 8;
456 component
= data
& 0xfc;
457 rgb
|= (component
| (component
>> 6)) << 8;
461 component
= data
& 0xf8;
462 rgb
|= (component
| (component
>> 5)) << 16;
469 p
= (unsigned char*)bmpbuf
+ 3 * width
;
470 while (p
> (unsigned char*)bmpbuf
) {
472 data
= (data
<< 8) | *(--p
);
473 data
= (data
<< 8) | *(--p
);
474 *(--rp
) = htole32(data
);
478 case 32: /* already in desired format */
482 /* Convert to destination format */
483 qp
= (union rgb_union
*)bmpbuf
;
484 #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
485 if (format
== FORMAT_NATIVE
) {
486 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
488 #if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)
489 /* iAudio X5/M5 remote */
490 fb_remote_data
*dest
= (fb_remote_data
*)bitmap
491 + dst_width
* (row
>> 3);
496 for (col
= 0; col
< width
; col
++) {
498 delta
= dither_matrix
[row
& 0xf][col
& 0xf];
499 bright
= brightness(*qp
++);
500 bright
= (3 * bright
+ (bright
>> 6) + delta
) >> 8;
501 *dest
++ |= vi_pattern
[bright
] << shift
;
503 #endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */
505 #endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */
508 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
509 /* greyscale iPods */
510 fb_data
*dest
= (fb_data
*)bitmap
+ dst_width
* row
;
516 for (col
= 0; col
< width
; col
++) {
518 delta
= dither_matrix
[row
& 0xf][col
& 0xf];
519 bright
= brightness(*qp
++);
520 bright
= (3 * bright
+ (bright
>> 6) + delta
) >> 8;
521 data
|= (~bright
& 3) << shift
;
531 #elif LCD_PIXELFORMAT == VERTICAL_PACKING
533 fb_data
*dest
= (fb_data
*)bitmap
+ dst_width
* (row
>> 2);
534 int shift
= 2 * (row
& 3);
538 for (col
= 0; col
< width
; col
++) {
540 delta
= dither_matrix
[row
& 0xf][col
& 0xf];
541 bright
= brightness(*qp
++);
542 bright
= (3 * bright
+ (bright
>> 6) + delta
) >> 8;
543 *dest
++ |= (~bright
& 3) << shift
;
545 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
547 fb_data
*dest
= (fb_data
*)bitmap
+ dst_width
* (row
>> 3);
552 for (col
= 0; col
< width
; col
++) {
554 delta
= dither_matrix
[row
& 0xf][col
& 0xf];
555 bright
= brightness(*qp
++);
556 bright
= (3 * bright
+ (bright
>> 6) + delta
) >> 8;
557 *dest
++ |= vi_pattern
[bright
] << shift
;
559 #endif /* LCD_PIXELFORMAT */
560 #elif LCD_DEPTH == 16
561 /* iriver h300, colour iPods, X5 */
562 fb_data
*dest
= (fb_data
*)bitmap
+ dst_width
* row
;
566 for (col
= 0; col
< width
; col
++) {
568 delta
= dither_matrix
[row
& 0xf][col
& 0xf];
570 r
= (31 * q0
.red
+ (q0
.red
>> 3) + delta
) >> 8;
571 g
= (63 * q0
.green
+ (q0
.green
>> 2) + delta
) >> 8;
572 b
= (31 * q0
.blue
+ (q0
.blue
>> 3) + delta
) >> 8;
573 *dest
++ = LCD_RGBPACK_LCD(r
, g
, b
);
575 #endif /* LCD_DEPTH */
578 #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
580 p
= bitmap
+ dst_width
* (row
>> 3);
581 mask
= 1 << (row
& 7);
583 for (col
= 0; col
< width
; col
++, p
++)
584 if (brightness(*qp
++) < 128)
589 return totalsize
; /* return the used buffer size. */