remove the 2nd last evil use of ata_disk_is_active() in apps/
[Rockbox.git] / apps / recorder / bmp.c
blobd977699fe4f1748603649f8ab44bc6ba3b427370
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 ****************************************************************************/
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
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include "inttypes.h"
36 #include "debug.h"
37 #include "lcd.h"
38 #include "file.h"
39 #ifdef HAVE_REMOTE_LCD
40 #include "lcd-remote.h"
41 #endif
42 #ifndef __PCTOOL__
43 #include "config.h"
44 #include "system.h"
45 #include "bmp.h"
46 #include "debug.h"
47 #else
48 #undef DEBUGF
49 #define DEBUGF(...)
50 #endif
52 #ifdef __GNUC__
53 #define STRUCT_PACKED __attribute__((packed))
54 #else
55 #define STRUCT_PACKED
56 #pragma pack (push, 2)
57 #endif
59 /* BMP header structure */
60 struct bmp_header {
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 */
77 } STRUCT_PACKED;
79 union rgb_union {
80 struct { /* Little endian */
81 unsigned char blue;
82 unsigned char green;
83 unsigned char red;
84 unsigned char reserved;
86 uint32_t raw;
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 }
116 #endif
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
124 #endif
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 /******************************************************************************
147 * read_bmp_file()
149 * Reads a BMP file and puts the data in rockbox format in *bitmap.
151 *****************************************************************************/
152 int read_bmp_file(const char* filename,
153 struct bitmap *bm,
154 int maxsize,
155 int format)
157 int fd, ret;
158 fd = open(filename, O_RDONLY);
160 /* Exit if file opening failed */
161 if (fd < 0) {
162 DEBUGF("read_bmp_file: can't open '%s', rc: %d\n", filename, fd);
163 return fd * 10 - 1;
166 ret = read_bmp_fd(fd, bm, maxsize, format);
167 close(fd);
168 return ret;
171 /******************************************************************************
172 * read_bmp_fd()
174 * Reads a BMP file in an open file descriptor and puts the data in rockbox
175 * format in *bitmap.
177 *****************************************************************************/
178 int read_bmp_fd(int fd,
179 struct bitmap *bm,
180 int maxsize,
181 int format)
183 struct bmp_header bmph;
184 int width, height, padded_width;
185 int dst_height, dst_width;
186 int depth, numcolors, compression, totalsize;
187 int row, col, ret;
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;
195 bool dither = false;
196 #ifdef HAVE_REMOTE_LCD
197 bool remote = false;
199 if (format & FORMAT_REMOTE) {
200 remote = true;
201 #if LCD_REMOTE_DEPTH == 1
202 format = FORMAT_MONO;
203 #else
204 format &= ~FORMAT_REMOTE;
205 #endif
207 #endif /* HAVE_REMOTE_LCD */
208 if (format & FORMAT_TRANSPARENT) {
209 transparent = true;
210 format &= ~FORMAT_TRANSPARENT;
212 if (format & FORMAT_DITHER) {
213 dither = true;
214 format &= ~FORMAT_DITHER;
216 #else
218 (void)format;
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));
223 if (ret < 0) {
224 return ret * 10 - 2;
227 if (ret != sizeof(struct bmp_header)) {
228 DEBUGF("read_bmp_fd: can't read BMP header.");
229 return -3;
232 width = readlong(&bmph.width);
233 if (width > LCD_WIDTH) {
234 DEBUGF("read_bmp_fd: Bitmap too wide (%d pixels, max is %d)\n",
235 width, LCD_WIDTH);
236 return -4;
239 height = readlong(&bmph.height);
240 if (height < 0) { /* Top-down BMP file */
241 height = -height;
242 rowstart = 0;
243 rowstop = height;
244 rowstep = 1;
245 } else { /* normal BMP */
246 rowstart = height - 1;
247 rowstop = -1;
248 rowstep = -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) {
256 if (depth == 1)
257 format = FORMAT_MONO;
258 else
259 format = FORMAT_NATIVE;
261 bm->format = format;
262 #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
263 /* returning image size */
264 bm->width = width;
265 bm->height = height;
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
270 if (remote) {
271 #if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)
272 dst_width = width;
273 dst_height = (height + 7) >> 3;
274 #endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */
275 totalsize = dst_width * dst_height * sizeof(fb_remote_data);
276 } else
277 #endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */
279 #if LCD_DEPTH == 2
280 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
281 dst_width = (width + 3) >> 2;
282 dst_height = height;
283 #elif LCD_PIXELFORMAT == VERTICAL_PACKING
284 dst_width = width;
285 dst_height = (height + 3) >> 2;
286 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
287 dst_width = width;
288 dst_height = (height + 7) >> 3;
289 #endif /* LCD_PIXELFORMAT */
290 #elif LCD_DEPTH == 16
291 dst_width = width;
292 dst_height = height;
293 #endif /* LCD_DEPTH */
294 totalsize = dst_width * dst_height * sizeof(fb_data);
296 } else
297 #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
299 dst_width = width;
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);
308 return -6;
311 compression = readlong(&bmph.compression);
312 if (depth <= 8) {
313 numcolors = readlong(&bmph.clr_used);
314 if (numcolors == 0)
315 numcolors = 1 << depth;
316 } else
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");
324 return -7;
328 switch (depth) {
329 case 16:
330 #if LCD_DEPTH >= 16
331 /* don't dither 16 bit BMP to LCD with same or larger depth */
332 #ifdef HAVE_REMOTE_LCD
333 if (!remote)
334 #endif
335 dither = false;
336 #endif
337 if (compression == 0) { /* BI_RGB, i.e. 15 bit */
338 depth = 15;
339 break;
340 } /* else fall through */
342 case 32:
343 if (compression == 3) { /* BI_BITFIELDS */
344 if (!memcmp(palette, bitfields[0], 12)) { /* 15 bit */
345 depth = 15;
346 break;
348 if (!memcmp(palette, bitfields[1], 12) /* 16 bit */
349 || !memcmp(palette, bitfields[2], 12)) /* 32 bit */
351 break;
353 } /* else fall through */
355 default:
356 if (compression != 0) { /* not BI_RGB */
357 DEBUGF("read_bmp_fd: Unsupported compression (type %d)\n",
358 compression);
359 return -8;
361 break;
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) {
371 unsigned data, mask;
372 unsigned char *p;
373 uint16_t *p2;
374 uint32_t *rp;
375 union rgb_union *qp;
376 union rgb_union q0, q1;
378 /* read one row */
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);
383 return -9;
386 /* convert whole line in-place to XRGB8888 (little endian) */
387 rp = bmpbuf + width;
388 switch (depth) {
389 case 1:
390 q0.raw = palette[0];
391 q1.raw = palette[1];
392 p = (unsigned char*)bmpbuf + ((width + 7) >> 3);
393 mask = 0x80 >> ((width + 7) & 7);
394 while (p > (unsigned char*)bmpbuf) {
395 data = *(--p);
396 for (; mask <= 0x80; mask <<= 1)
397 *(--rp) = (data & mask) ? q1.raw : q0.raw;
398 mask = 0x01;
400 break;
402 case 4:
403 if (width & 1)
404 rp++;
405 p = (unsigned char*)bmpbuf + ((width + 1) >> 1);
406 while (p > (unsigned char*)bmpbuf) {
407 data = *(--p);
408 *(--rp) = palette[data & 0x0f];
409 *(--rp) = palette[data >> 4];
411 break;
413 case 8:
414 p = (unsigned char*)bmpbuf + width;
415 while (p > (unsigned char*)bmpbuf)
416 *(--rp) = palette[*(--p)];
417 break;
419 case 15:
420 case 16:
421 p2 = (uint16_t *)bmpbuf + width;
422 while (p2 > (uint16_t *)bmpbuf) {
423 unsigned component, rgb;
425 data = letoh16(*(--p2));
426 /* blue */
427 component = (data << 3) & 0xf8;
428 #ifdef ROCKBOX_BIG_ENDIAN
429 rgb = (component | (component >> 5)) << 8;
430 /* green */
431 data >>= 2;
432 if (depth == 15) {
433 component = data & 0xf8;
434 rgb |= component | (component >> 5);
435 } else {
436 data >>= 1;
437 component = data & 0xfc;
438 rgb |= component | (component >> 6);
440 /* red */
441 data >>= 5;
442 component = data & 0xf8;
443 rgb = (rgb << 8) | component | (component >> 5);
444 *(--rp) = rgb << 8;
445 #else /* little endian */
446 rgb = component | (component >> 5);
447 /* green */
448 data >>= 2;
449 if (depth == 15) {
450 component = data & 0xf8;
451 rgb |= (component | (component >> 5)) << 8;
452 } else {
453 data >>= 1;
454 component = data & 0xfc;
455 rgb |= (component | (component >> 6)) << 8;
457 /* red */
458 data >>= 5;
459 component = data & 0xf8;
460 rgb |= (component | (component >> 5)) << 16;
461 *(--rp) = rgb;
462 #endif
464 break;
466 case 24:
467 p = (unsigned char*)bmpbuf + 3 * width;
468 while (p > (unsigned char*)bmpbuf) {
469 data = *(--p);
470 data = (data << 8) | *(--p);
471 data = (data << 8) | *(--p);
472 *(--rp) = htole32(data);
474 break;
476 case 32: /* already in desired format */
477 break;
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
485 if (remote) {
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);
490 int shift = row & 7;
491 int delta = 127;
492 unsigned bright;
494 for (col = 0; col < width; col++) {
495 if (dither)
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 */
502 } else
503 #endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */
505 #if LCD_DEPTH == 2
506 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
507 /* greyscale iPods */
508 fb_data *dest = (fb_data *)bitmap + dst_width * row;
509 int shift = 6;
510 int delta = 127;
511 unsigned bright;
512 unsigned data = 0;
514 for (col = 0; col < width; col++) {
515 if (dither)
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;
520 shift -= 2;
521 if (shift < 0) {
522 *dest++ = data;
523 data = 0;
524 shift = 6;
527 if (shift < 6)
528 *dest++ = data;
529 #elif LCD_PIXELFORMAT == VERTICAL_PACKING
530 /* iriver H1x0 */
531 fb_data *dest = (fb_data *)bitmap + dst_width * (row >> 2);
532 int shift = 2 * (row & 3);
533 int delta = 127;
534 unsigned bright;
536 for (col = 0; col < width; col++) {
537 if (dither)
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
544 /* iAudio M3 */
545 fb_data *dest = (fb_data *)bitmap + dst_width * (row >> 3);
546 int shift = row & 7;
547 int delta = 127;
548 unsigned bright;
550 for (col = 0; col < width; col++) {
551 if (dither)
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;
561 int delta = 127;
562 unsigned r, g, b;
564 for (col = 0; col < width; col++) {
565 if (dither)
566 delta = dither_matrix[row & 0xf][col & 0xf];
567 q0 = *qp++;
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 */
575 } else
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)
583 *p |= mask;
587 return totalsize; /* return the used buffer size. */