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 ****************************************************************************/
21 2005-04-16 Tomas Salfischberger:
22 - New BMP loader function, based on the old one (borrowed a lot of
23 calculations and checks there.)
24 - Conversion part needs some optimization, doing unneeded calulations now.
25 2006-11-18 Jens Arnold: complete rework
26 - All canonical formats supported now (1, 4, 8, 15/16, 24 and 32 bit)
27 - better protection against malformed / non-standard BMPs
28 - code heavily optimised for both size and speed
29 - dithering for 2 bit targets
39 #ifdef HAVE_REMOTE_LCD
40 #include "lcd-remote.h"
53 #define STRUCT_PACKED __attribute__((packed))
56 #pragma pack (push, 2)
59 /* BMP header structure */
61 uint16_t type
; /* signature - 'BM' */
62 uint32_t size
; /* file size in bytes */
63 uint16_t reserved1
; /* 0 */
64 uint16_t reserved2
; /* 0 */
65 uint32_t off_bits
; /* offset to bitmap */
66 uint32_t struct_size
; /* size of this struct (40) */
67 int32_t width
; /* bmap width in pixels */
68 int32_t height
; /* bmap height in pixels */
69 uint16_t planes
; /* num planes - always 1 */
70 uint16_t bit_count
; /* bits per pixel */
71 uint32_t compression
; /* compression flag */
72 uint32_t size_image
; /* image size in bytes */
73 int32_t x_pels_per_meter
; /* horz resolution */
74 int32_t y_pels_per_meter
; /* vert resolution */
75 uint32_t clr_used
; /* 0 -> color table size */
76 uint32_t clr_important
; /* important color count */
80 struct { /* Little endian */
84 unsigned char reserved
;
89 /* masks for supported BI_BITFIELDS encodings (16/32 bit), little endian */
90 static const unsigned char bitfields
[3][12] = {
91 { 0x00,0x7c,0x00,0, 0xe0,0x03,0x00,0, 0x1f,0x00,0x00,0 }, /* 15 bit */
92 { 0x00,0xf8,0x00,0, 0xe0,0x07,0x00,0, 0x1f,0x00,0x00,0 }, /* 16 bit */
93 { 0x00,0x00,0xff,0, 0x00,0xff,0x00,0, 0xff,0x00,0x00,0 }, /* 32 bit */
96 #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
97 /* canonical ordered dither matrix */
98 static const unsigned char dither_matrix
[16][16] = {
99 { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 },
100 { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 },
101 { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 },
102 { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 },
103 { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 },
104 { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 },
105 { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 },
106 { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 },
107 { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 },
108 { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 },
109 { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 },
110 { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 },
111 { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 },
112 { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 },
113 { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 },
114 { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 }
118 #if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \
119 || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH == 2) \
120 && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED))
121 static const unsigned short vi_pattern
[4] = {
122 0x0101, 0x0100, 0x0001, 0x0000
126 /* little endian functions */
127 static inline unsigned readshort(uint16_t *value
)
129 unsigned char* bytes
= (unsigned char*) value
;
130 return (unsigned)bytes
[0] | ((unsigned)bytes
[1] << 8);
133 static inline uint32_t readlong(uint32_t *value
)
135 unsigned char* bytes
= (unsigned char*) value
;
136 return (uint32_t)bytes
[0] | ((uint32_t)bytes
[1] << 8) |
137 ((uint32_t)bytes
[2] << 16) | ((uint32_t)bytes
[3] << 24);
140 static inline unsigned brightness(union rgb_union color
)
142 return (3 * (unsigned)color
.red
+ 6 * (unsigned)color
.green
143 + (unsigned)color
.blue
) / 10;
146 /******************************************************************************
149 * Reads a BMP file and puts the data in rockbox format in *bitmap.
151 *****************************************************************************/
152 int read_bmp_file(const char* filename
,
158 fd
= open(filename
, O_RDONLY
);
160 /* Exit if file opening failed */
162 DEBUGF("read_bmp_file: can't open '%s', rc: %d\n", filename
, fd
);
166 ret
= read_bmp_fd(fd
, bm
, maxsize
, format
);
171 /******************************************************************************
174 * Reads a BMP file in an open file descriptor and puts the data in rockbox
177 *****************************************************************************/
178 int read_bmp_fd(int fd
,
183 struct bmp_header bmph
;
184 int width
, height
, padded_width
;
185 int dst_height
, dst_width
;
186 int depth
, numcolors
, compression
, totalsize
;
188 int rowstart
, rowstop
, rowstep
;
190 unsigned char *bitmap
= bm
->data
;
191 uint32_t bmpbuf
[LCD_WIDTH
]; /* Buffer for one line */
192 uint32_t palette
[256];
193 #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
194 bool transparent
= false;
196 #ifdef HAVE_REMOTE_LCD
199 if (format
& FORMAT_REMOTE
) {
201 #if LCD_REMOTE_DEPTH == 1
202 format
= FORMAT_MONO
;
204 format
&= ~FORMAT_REMOTE
;
207 #endif /* HAVE_REMOTE_LCD */
208 if (format
& FORMAT_TRANSPARENT
) {
210 format
&= ~FORMAT_TRANSPARENT
;
212 if (format
& FORMAT_DITHER
) {
214 format
&= ~FORMAT_DITHER
;
219 #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
221 /* read fileheader */
222 ret
= read(fd
, &bmph
, sizeof(struct bmp_header
));
227 if (ret
!= sizeof(struct bmp_header
)) {
228 DEBUGF("read_bmp_fd: can't read BMP header.");
232 width
= readlong(&bmph
.width
);
233 if (width
> LCD_WIDTH
) {
234 DEBUGF("read_bmp_fd: Bitmap too wide (%d pixels, max is %d)\n",
239 height
= readlong(&bmph
.height
);
240 if (height
< 0) { /* Top-down BMP file */
245 } else { /* normal BMP */
246 rowstart
= height
- 1;
251 depth
= readshort(&bmph
.bit_count
);
252 padded_width
= ((width
* depth
+ 31) >> 3) & ~3; /* 4-byte boundary aligned */
254 #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
255 if (format
== FORMAT_ANY
) {
257 format
= FORMAT_MONO
;
259 format
= FORMAT_NATIVE
;
262 #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
263 /* returning image size */
267 #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
268 if (format
== FORMAT_NATIVE
) {
269 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
271 #if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)
273 dst_height
= (height
+ 7) >> 3;
274 #endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */
275 totalsize
= dst_width
* dst_height
* sizeof(fb_remote_data
);
277 #endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */
280 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
281 dst_width
= (width
+ 3) >> 2;
283 #elif LCD_PIXELFORMAT == VERTICAL_PACKING
285 dst_height
= (height
+ 3) >> 2;
286 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
288 dst_height
= (height
+ 7) >> 3;
289 #endif /* LCD_PIXELFORMAT */
290 #elif LCD_DEPTH == 16
293 #endif /* LCD_DEPTH */
294 totalsize
= dst_width
* dst_height
* sizeof(fb_data
);
297 #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
300 dst_height
= (height
+ 7) >> 3;
301 totalsize
= dst_width
* dst_height
;
304 /* Check if this fits the buffer */
305 if (totalsize
> maxsize
) {
306 DEBUGF("read_bmp_fd: Bitmap too large for buffer: "
307 "%d bytes.\n", totalsize
);
311 compression
= readlong(&bmph
.compression
);
313 numcolors
= readlong(&bmph
.clr_used
);
315 numcolors
= 1 << depth
;
317 numcolors
= (compression
== 3) ? 3 : 0;
319 if (numcolors
> 0 && numcolors
<= 256) {
320 if (read(fd
, palette
, numcolors
* sizeof(uint32_t))
321 != numcolors
* (int)sizeof(uint32_t))
323 DEBUGF("read_bmp_fd: Can't read color palette\n");
331 /* don't dither 16 bit BMP to LCD with same or larger depth */
332 #ifdef HAVE_REMOTE_LCD
337 if (compression
== 0) { /* BI_RGB, i.e. 15 bit */
340 } /* else fall through */
343 if (compression
== 3) { /* BI_BITFIELDS */
344 if (!memcmp(palette
, bitfields
[0], 12)) { /* 15 bit */
348 if (!memcmp(palette
, bitfields
[1], 12) /* 16 bit */
349 || !memcmp(palette
, bitfields
[2], 12)) /* 32 bit */
353 } /* else fall through */
356 if (compression
!= 0) { /* not BI_RGB */
357 DEBUGF("read_bmp_fd: Unsupported compression (type %d)\n",
364 /* Search to the beginning of the image data */
365 lseek(fd
, (off_t
)readlong(&bmph
.off_bits
), SEEK_SET
);
367 memset(bitmap
, 0, totalsize
);
369 /* loop to read rows and put them to buffer */
370 for (row
= rowstart
; row
!= rowstop
; row
+= rowstep
) {
376 union rgb_union q0
, q1
;
379 ret
= read(fd
, bmpbuf
, padded_width
);
380 if (ret
!= padded_width
) {
381 DEBUGF("read_bmp_fd: error reading image, read returned: %d "
382 "expected: %d\n", ret
, padded_width
);
386 /* convert whole line in-place to XRGB8888 (little endian) */
392 p
= (unsigned char*)bmpbuf
+ ((width
+ 7) >> 3);
393 mask
= 0x80 >> ((width
+ 7) & 7);
394 while (p
> (unsigned char*)bmpbuf
) {
396 for (; mask
<= 0x80; mask
<<= 1)
397 *(--rp
) = (data
& mask
) ? q1
.raw
: q0
.raw
;
405 p
= (unsigned char*)bmpbuf
+ ((width
+ 1) >> 1);
406 while (p
> (unsigned char*)bmpbuf
) {
408 *(--rp
) = palette
[data
& 0x0f];
409 *(--rp
) = palette
[data
>> 4];
414 p
= (unsigned char*)bmpbuf
+ width
;
415 while (p
> (unsigned char*)bmpbuf
)
416 *(--rp
) = palette
[*(--p
)];
421 p2
= (uint16_t *)bmpbuf
+ width
;
422 while (p2
> (uint16_t *)bmpbuf
) {
423 unsigned component
, rgb
;
425 data
= letoh16(*(--p2
));
427 component
= (data
<< 3) & 0xf8;
428 #ifdef ROCKBOX_BIG_ENDIAN
429 rgb
= (component
| (component
>> 5)) << 8;
433 component
= data
& 0xf8;
434 rgb
|= component
| (component
>> 5);
437 component
= data
& 0xfc;
438 rgb
|= component
| (component
>> 6);
442 component
= data
& 0xf8;
443 rgb
= (rgb
<< 8) | component
| (component
>> 5);
445 #else /* little endian */
446 rgb
= component
| (component
>> 5);
450 component
= data
& 0xf8;
451 rgb
|= (component
| (component
>> 5)) << 8;
454 component
= data
& 0xfc;
455 rgb
|= (component
| (component
>> 6)) << 8;
459 component
= data
& 0xf8;
460 rgb
|= (component
| (component
>> 5)) << 16;
467 p
= (unsigned char*)bmpbuf
+ 3 * width
;
468 while (p
> (unsigned char*)bmpbuf
) {
470 data
= (data
<< 8) | *(--p
);
471 data
= (data
<< 8) | *(--p
);
472 *(--rp
) = htole32(data
);
476 case 32: /* already in desired format */
480 /* Convert to destination format */
481 qp
= (union rgb_union
*)bmpbuf
;
482 #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
483 if (format
== FORMAT_NATIVE
) {
484 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
486 #if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)
487 /* iAudio X5/M5 remote */
488 fb_remote_data
*dest
= (fb_remote_data
*)bitmap
489 + dst_width
* (row
>> 3);
494 for (col
= 0; col
< width
; col
++) {
496 delta
= dither_matrix
[row
& 0xf][col
& 0xf];
497 bright
= brightness(*qp
++);
498 bright
= (3 * bright
+ (bright
>> 6) + delta
) >> 8;
499 *dest
++ |= vi_pattern
[bright
] << shift
;
501 #endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */
503 #endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */
506 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
507 /* greyscale iPods */
508 fb_data
*dest
= (fb_data
*)bitmap
+ dst_width
* row
;
514 for (col
= 0; col
< width
; col
++) {
516 delta
= dither_matrix
[row
& 0xf][col
& 0xf];
517 bright
= brightness(*qp
++);
518 bright
= (3 * bright
+ (bright
>> 6) + delta
) >> 8;
519 data
|= (~bright
& 3) << shift
;
529 #elif LCD_PIXELFORMAT == VERTICAL_PACKING
531 fb_data
*dest
= (fb_data
*)bitmap
+ dst_width
* (row
>> 2);
532 int shift
= 2 * (row
& 3);
536 for (col
= 0; col
< width
; col
++) {
538 delta
= dither_matrix
[row
& 0xf][col
& 0xf];
539 bright
= brightness(*qp
++);
540 bright
= (3 * bright
+ (bright
>> 6) + delta
) >> 8;
541 *dest
++ |= (~bright
& 3) << shift
;
543 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
545 fb_data
*dest
= (fb_data
*)bitmap
+ dst_width
* (row
>> 3);
550 for (col
= 0; col
< width
; col
++) {
552 delta
= dither_matrix
[row
& 0xf][col
& 0xf];
553 bright
= brightness(*qp
++);
554 bright
= (3 * bright
+ (bright
>> 6) + delta
) >> 8;
555 *dest
++ |= vi_pattern
[bright
] << shift
;
557 #endif /* LCD_PIXELFORMAT */
558 #elif LCD_DEPTH == 16
559 /* iriver h300, colour iPods, X5 */
560 fb_data
*dest
= (fb_data
*)bitmap
+ dst_width
* row
;
564 for (col
= 0; col
< width
; col
++) {
566 delta
= dither_matrix
[row
& 0xf][col
& 0xf];
568 r
= (31 * q0
.red
+ (q0
.red
>> 3) + delta
) >> 8;
569 g
= (63 * q0
.green
+ (q0
.green
>> 2) + delta
) >> 8;
570 b
= (31 * q0
.blue
+ (q0
.blue
>> 3) + delta
) >> 8;
571 *dest
++ = LCD_RGBPACK_LCD(r
, g
, b
);
573 #endif /* LCD_DEPTH */
576 #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
578 p
= bitmap
+ dst_width
* (row
>> 3);
579 mask
= 1 << (row
& 7);
581 for (col
= 0; col
< width
; col
++, p
++)
582 if (brightness(*qp
++) < 128)
587 return totalsize
; /* return the used buffer size. */