fix FS#9120 by actually quiting random folder advance config after choosing "ignore...
[Rockbox.git] / apps / recorder / bmp.c
blob9327ac5ec4763a2120c1de13e99caf7dd22a3187
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 ****************************************************************************/
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
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include "inttypes.h"
38 #include "debug.h"
39 #include "lcd.h"
40 #include "file.h"
41 #ifdef HAVE_REMOTE_LCD
42 #include "lcd-remote.h"
43 #endif
44 #ifndef __PCTOOL__
45 #include "config.h"
46 #include "system.h"
47 #include "bmp.h"
48 #include "debug.h"
49 #else
50 #undef DEBUGF
51 #define DEBUGF(...)
52 #endif
54 #ifdef __GNUC__
55 #define STRUCT_PACKED __attribute__((packed))
56 #else
57 #define STRUCT_PACKED
58 #pragma pack (push, 2)
59 #endif
61 /* BMP header structure */
62 struct bmp_header {
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 */
79 } STRUCT_PACKED;
81 union rgb_union {
82 struct { /* Little endian */
83 unsigned char blue;
84 unsigned char green;
85 unsigned char red;
86 unsigned char reserved;
88 uint32_t raw;
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 }
118 #endif
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
126 #endif
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 /******************************************************************************
149 * read_bmp_file()
151 * Reads a BMP file and puts the data in rockbox format in *bitmap.
153 *****************************************************************************/
154 int read_bmp_file(const char* filename,
155 struct bitmap *bm,
156 int maxsize,
157 int format)
159 int fd, ret;
160 fd = open(filename, O_RDONLY);
162 /* Exit if file opening failed */
163 if (fd < 0) {
164 DEBUGF("read_bmp_file: can't open '%s', rc: %d\n", filename, fd);
165 return fd * 10 - 1;
168 ret = read_bmp_fd(fd, bm, maxsize, format);
169 close(fd);
170 return ret;
173 /******************************************************************************
174 * read_bmp_fd()
176 * Reads a BMP file in an open file descriptor and puts the data in rockbox
177 * format in *bitmap.
179 *****************************************************************************/
180 int read_bmp_fd(int fd,
181 struct bitmap *bm,
182 int maxsize,
183 int format)
185 struct bmp_header bmph;
186 int width, height, padded_width;
187 int dst_height, dst_width;
188 int depth, numcolors, compression, totalsize;
189 int row, col, ret;
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;
197 bool dither = false;
198 #ifdef HAVE_REMOTE_LCD
199 bool remote = false;
201 if (format & FORMAT_REMOTE) {
202 remote = true;
203 #if LCD_REMOTE_DEPTH == 1
204 format = FORMAT_MONO;
205 #else
206 format &= ~FORMAT_REMOTE;
207 #endif
209 #endif /* HAVE_REMOTE_LCD */
210 if (format & FORMAT_TRANSPARENT) {
211 transparent = true;
212 format &= ~FORMAT_TRANSPARENT;
214 if (format & FORMAT_DITHER) {
215 dither = true;
216 format &= ~FORMAT_DITHER;
218 #else
220 (void)format;
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));
225 if (ret < 0) {
226 return ret * 10 - 2;
229 if (ret != sizeof(struct bmp_header)) {
230 DEBUGF("read_bmp_fd: can't read BMP header.");
231 return -3;
234 width = readlong(&bmph.width);
235 if (width > LCD_WIDTH) {
236 DEBUGF("read_bmp_fd: Bitmap too wide (%d pixels, max is %d)\n",
237 width, LCD_WIDTH);
238 return -4;
241 height = readlong(&bmph.height);
242 if (height < 0) { /* Top-down BMP file */
243 height = -height;
244 rowstart = 0;
245 rowstop = height;
246 rowstep = 1;
247 } else { /* normal BMP */
248 rowstart = height - 1;
249 rowstop = -1;
250 rowstep = -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) {
258 if (depth == 1)
259 format = FORMAT_MONO;
260 else
261 format = FORMAT_NATIVE;
263 bm->format = format;
264 #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
265 /* returning image size */
266 bm->width = width;
267 bm->height = height;
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
272 if (remote) {
273 #if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)
274 dst_width = width;
275 dst_height = (height + 7) >> 3;
276 #endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */
277 totalsize = dst_width * dst_height * sizeof(fb_remote_data);
278 } else
279 #endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */
281 #if LCD_DEPTH == 2
282 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
283 dst_width = (width + 3) >> 2;
284 dst_height = height;
285 #elif LCD_PIXELFORMAT == VERTICAL_PACKING
286 dst_width = width;
287 dst_height = (height + 3) >> 2;
288 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
289 dst_width = width;
290 dst_height = (height + 7) >> 3;
291 #endif /* LCD_PIXELFORMAT */
292 #elif LCD_DEPTH == 16
293 dst_width = width;
294 dst_height = height;
295 #endif /* LCD_DEPTH */
296 totalsize = dst_width * dst_height * sizeof(fb_data);
298 } else
299 #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
301 dst_width = width;
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);
310 return -6;
313 compression = readlong(&bmph.compression);
314 if (depth <= 8) {
315 numcolors = readlong(&bmph.clr_used);
316 if (numcolors == 0)
317 numcolors = 1 << depth;
318 } else
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");
326 return -7;
330 switch (depth) {
331 case 16:
332 #if LCD_DEPTH >= 16
333 /* don't dither 16 bit BMP to LCD with same or larger depth */
334 #ifdef HAVE_REMOTE_LCD
335 if (!remote)
336 #endif
337 dither = false;
338 #endif
339 if (compression == 0) { /* BI_RGB, i.e. 15 bit */
340 depth = 15;
341 break;
342 } /* else fall through */
344 case 32:
345 if (compression == 3) { /* BI_BITFIELDS */
346 if (!memcmp(palette, bitfields[0], 12)) { /* 15 bit */
347 depth = 15;
348 break;
350 if (!memcmp(palette, bitfields[1], 12) /* 16 bit */
351 || !memcmp(palette, bitfields[2], 12)) /* 32 bit */
353 break;
355 } /* else fall through */
357 default:
358 if (compression != 0) { /* not BI_RGB */
359 DEBUGF("read_bmp_fd: Unsupported compression (type %d)\n",
360 compression);
361 return -8;
363 break;
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) {
373 unsigned data, mask;
374 unsigned char *p;
375 uint16_t *p2;
376 uint32_t *rp;
377 union rgb_union *qp;
378 union rgb_union q0, q1;
380 /* read one row */
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);
385 return -9;
388 /* convert whole line in-place to XRGB8888 (little endian) */
389 rp = bmpbuf + width;
390 switch (depth) {
391 case 1:
392 q0.raw = palette[0];
393 q1.raw = palette[1];
394 p = (unsigned char*)bmpbuf + ((width + 7) >> 3);
395 mask = 0x80 >> ((width + 7) & 7);
396 while (p > (unsigned char*)bmpbuf) {
397 data = *(--p);
398 for (; mask <= 0x80; mask <<= 1)
399 *(--rp) = (data & mask) ? q1.raw : q0.raw;
400 mask = 0x01;
402 break;
404 case 4:
405 if (width & 1)
406 rp++;
407 p = (unsigned char*)bmpbuf + ((width + 1) >> 1);
408 while (p > (unsigned char*)bmpbuf) {
409 data = *(--p);
410 *(--rp) = palette[data & 0x0f];
411 *(--rp) = palette[data >> 4];
413 break;
415 case 8:
416 p = (unsigned char*)bmpbuf + width;
417 while (p > (unsigned char*)bmpbuf)
418 *(--rp) = palette[*(--p)];
419 break;
421 case 15:
422 case 16:
423 p2 = (uint16_t *)bmpbuf + width;
424 while (p2 > (uint16_t *)bmpbuf) {
425 unsigned component, rgb;
427 data = letoh16(*(--p2));
428 /* blue */
429 component = (data << 3) & 0xf8;
430 #ifdef ROCKBOX_BIG_ENDIAN
431 rgb = (component | (component >> 5)) << 8;
432 /* green */
433 data >>= 2;
434 if (depth == 15) {
435 component = data & 0xf8;
436 rgb |= component | (component >> 5);
437 } else {
438 data >>= 1;
439 component = data & 0xfc;
440 rgb |= component | (component >> 6);
442 /* red */
443 data >>= 5;
444 component = data & 0xf8;
445 rgb = (rgb << 8) | component | (component >> 5);
446 *(--rp) = rgb << 8;
447 #else /* little endian */
448 rgb = component | (component >> 5);
449 /* green */
450 data >>= 2;
451 if (depth == 15) {
452 component = data & 0xf8;
453 rgb |= (component | (component >> 5)) << 8;
454 } else {
455 data >>= 1;
456 component = data & 0xfc;
457 rgb |= (component | (component >> 6)) << 8;
459 /* red */
460 data >>= 5;
461 component = data & 0xf8;
462 rgb |= (component | (component >> 5)) << 16;
463 *(--rp) = rgb;
464 #endif
466 break;
468 case 24:
469 p = (unsigned char*)bmpbuf + 3 * width;
470 while (p > (unsigned char*)bmpbuf) {
471 data = *(--p);
472 data = (data << 8) | *(--p);
473 data = (data << 8) | *(--p);
474 *(--rp) = htole32(data);
476 break;
478 case 32: /* already in desired format */
479 break;
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
487 if (remote) {
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);
492 int shift = row & 7;
493 int delta = 127;
494 unsigned bright;
496 for (col = 0; col < width; col++) {
497 if (dither)
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 */
504 } else
505 #endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */
507 #if LCD_DEPTH == 2
508 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
509 /* greyscale iPods */
510 fb_data *dest = (fb_data *)bitmap + dst_width * row;
511 int shift = 6;
512 int delta = 127;
513 unsigned bright;
514 unsigned data = 0;
516 for (col = 0; col < width; col++) {
517 if (dither)
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;
522 shift -= 2;
523 if (shift < 0) {
524 *dest++ = data;
525 data = 0;
526 shift = 6;
529 if (shift < 6)
530 *dest++ = data;
531 #elif LCD_PIXELFORMAT == VERTICAL_PACKING
532 /* iriver H1x0 */
533 fb_data *dest = (fb_data *)bitmap + dst_width * (row >> 2);
534 int shift = 2 * (row & 3);
535 int delta = 127;
536 unsigned bright;
538 for (col = 0; col < width; col++) {
539 if (dither)
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
546 /* iAudio M3 */
547 fb_data *dest = (fb_data *)bitmap + dst_width * (row >> 3);
548 int shift = row & 7;
549 int delta = 127;
550 unsigned bright;
552 for (col = 0; col < width; col++) {
553 if (dither)
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;
563 int delta = 127;
564 unsigned r, g, b;
566 for (col = 0; col < width; col++) {
567 if (dither)
568 delta = dither_matrix[row & 0xf][col & 0xf];
569 q0 = *qp++;
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 */
577 } else
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)
585 *p |= mask;
589 return totalsize; /* return the used buffer size. */