Move the "warning suppression" down, so it comes after the last write to "remote...
[maemo-rb.git] / apps / recorder / bmp.c
blobbc3b754e4db710d00c595f33405d2ed048a840cf
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
32 2008-11-02 Akio Idehara: refactor for scaler frontend
33 2008-12-08 Andrew Mahone: partial-line reading, scaler frontend
34 - read_part_line does the actual source BMP reading, return columns read
35 and updates fields in a struct bmp_args with the new data and current
36 reader state
37 - skip_lines_bmp and store_part_bmp implement the scaler callbacks to skip
38 ahead by whole lines, or read the next chunk of the current line
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include "inttypes.h"
45 #include "system.h"
46 #ifndef PLUGIN
47 #include "debug.h"
48 #endif
49 #include "lcd.h"
50 #include "file.h"
51 #include "bmp.h"
52 #ifdef HAVE_REMOTE_LCD
53 #include "lcd-remote.h"
54 #endif
55 #ifdef ROCKBOX_DEBUG_BMP_LOADER
56 #define BDEBUGF DEBUGF
57 #else
58 #define BDEBUGF(...)
59 #endif
60 #ifndef __PCTOOL__
61 #include "config.h"
62 #include "resize.h"
63 #else
64 #undef DEBUGF
65 #define DEBUGF(...)
66 #endif
68 #ifdef __GNUC__
69 #define STRUCT_PACKED __attribute__((packed))
70 #else
71 #define STRUCT_PACKED
72 #pragma pack (push, 2)
73 #endif
75 /* BMP header structure */
76 struct bmp_header {
77 uint16_t type; /* signature - 'BM' */
78 uint32_t size; /* file size in bytes */
79 uint16_t reserved1; /* 0 */
80 uint16_t reserved2; /* 0 */
81 uint32_t off_bits; /* offset to bitmap */
82 uint32_t struct_size; /* size of this struct (40) */
83 int32_t width; /* bmap width in pixels */
84 int32_t height; /* bmap height in pixels */
85 uint16_t planes; /* num planes - always 1 */
86 uint16_t bit_count; /* bits per pixel */
87 uint32_t compression; /* compression flag */
88 uint32_t size_image; /* image size in bytes */
89 int32_t x_pels_per_meter; /* horz resolution */
90 int32_t y_pels_per_meter; /* vert resolution */
91 uint32_t clr_used; /* 0 -> color table size */
92 uint32_t clr_important; /* important color count */
93 } STRUCT_PACKED;
95 union rgb_union {
96 struct { /* Little endian */
97 unsigned char blue;
98 unsigned char green;
99 unsigned char red;
100 unsigned char reserved;
102 uint32_t raw;
105 /* masks for supported BI_BITFIELDS encodings (16/32 bit) */
106 static const struct uint8_rgb bitfields[3][3] = {
107 /* 15bit */
109 { .blue = 0x00, .green = 0x7c, .red = 0x00 },
110 { .blue = 0xe0, .green = 0x03, .red = 0x00 },
111 { .blue = 0x1f, .green = 0x00, .red = 0x00 },
113 /* 16bit */
115 { .blue = 0x00, .green = 0xf8, .red = 0x00 },
116 { .blue = 0xe0, .green = 0x07, .red = 0x00 },
117 { .blue = 0x1f, .green = 0x00, .red = 0x00 },
119 /* 32bit */
121 { .blue = 0x00, .green = 0x00, .red = 0xff },
122 { .blue = 0x00, .green = 0xff, .red = 0x00 },
123 { .blue = 0xff, .green = 0x00, .red = 0x00 },
127 #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
128 /* the full 16x16 Bayer dither matrix may be calculated quickly with this table
130 const unsigned char dither_table[16] =
131 { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 };
132 #endif
134 #if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \
135 || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH == 2) \
136 && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED))
137 const unsigned short vi_pattern[4] = {
138 0x0101, 0x0100, 0x0001, 0x0000
140 #endif
142 /******************************************************************************
143 * read_bmp_file()
145 * Reads a BMP file and puts the data in rockbox format in *bitmap.
147 *****************************************************************************/
148 int read_bmp_file(const char* filename,
149 struct bitmap *bm,
150 int maxsize,
151 int format,
152 const struct custom_format *cformat)
154 int fd, ret;
155 fd = open(filename, O_RDONLY);
157 /* Exit if file opening failed */
158 if (fd < 0) {
159 DEBUGF("read_bmp_file: can't open '%s', rc: %d\n", filename, fd);
160 return fd * 10 - 1;
163 BDEBUGF("read_bmp_file: '%s' remote: %d resize: %d keep_aspect: %d\n",
164 filename, !!(format & FORMAT_REMOTE), !!(format & FORMAT_RESIZE),
165 !!(format & FORMAT_KEEP_ASPECT));
166 ret = read_bmp_fd(fd, bm, maxsize, format, cformat);
167 close(fd);
168 return ret;
171 static inline void set_rgb_union(struct uint8_rgb *dst, union rgb_union src)
173 dst->red = src.red;
174 dst->green = src.green;
175 dst->blue = src.blue;
178 struct bmp_args {
179 int fd;
180 short padded_width;
181 short read_width;
182 short width;
183 short depth;
184 unsigned char buf[BM_MAX_WIDTH * 4];
185 struct uint8_rgb *palette;
186 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
187 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
188 int cur_row;
189 int cur_col;
190 struct img_part part;
191 #endif
194 static unsigned int read_part_line(struct bmp_args *ba)
196 const int padded_width = ba->padded_width;
197 const int read_width = ba->read_width;
198 const int width = ba->width;
199 const int depth = ba->depth;
200 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
201 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
202 int cur_row = ba->cur_row;
203 int cur_col = ba->cur_col;
204 #endif
205 const int fd = ba->fd;
206 uint8_t *ibuf;
207 struct uint8_rgb *buf = (struct uint8_rgb *)(ba->buf);
208 const struct uint8_rgb *palette = ba->palette;
209 uint32_t component, data;
210 int ret;
211 int i, cols, len;
213 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
214 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
215 cols = MIN(width - cur_col,(int)BM_MAX_WIDTH);
216 BDEBUGF("reading %d cols (width: %d, max: %d)\n",cols,width,BM_MAX_WIDTH);
217 len = (cols * (depth == 15 ? 16 : depth) + 7) >> 3;
218 #else
219 cols = width;
220 len = read_width;
221 #endif
222 ibuf = ((unsigned char *)buf) + (BM_MAX_WIDTH << 2) - len;
223 BDEBUGF("read_part_line: cols=%d len=%d\n",cols,len);
224 ret = read(fd, ibuf, len);
225 if (ret != len)
227 DEBUGF("read_part_line: error reading image, read returned %d "
228 "expected %d\n", ret, len);
229 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
230 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
231 BDEBUGF("cur_row: %d cur_col: %d cols: %d len: %d\n", cur_row, cur_col,
232 cols, len);
233 #endif
234 return 0;
236 while (ibuf < ba->buf + (BM_MAX_WIDTH << 2))
238 switch (depth)
240 case 1:
241 data = *ibuf++;
242 for (i = 0; i < 8; i++)
244 *buf++ = palette[data & 0x80 ? 1 : 0];
245 data <<= 1;
247 break;
248 case 4:
249 data = *ibuf++;
250 *buf++ = palette[data >> 4];
251 *buf++ = palette[data & 0xf];
252 break;
253 case 8:
254 *buf++ = palette[*ibuf++];
255 break;
256 case 15:
257 case 16:
258 data = letoh16(*(uint16_t*)ibuf);
259 component = (data << 3) & 0xf8;
260 component |= component >> 5;
261 buf->blue = component;
262 if (depth == 15)
264 data >>= 2;
265 component = data & 0xf8;
266 component |= component >> 5;
267 } else {
268 data >>= 3;
269 component = data & 0xfc;
270 component |= component >> 6;
272 buf->green = component;
273 data >>= 5;
274 component = data & 0xf8;
275 component |= component >> 5;
276 buf->red = component;
277 buf++;
278 ibuf += 2;
279 break;
280 case 32:
281 case 24:
282 buf->blue = *ibuf++;
283 buf->green = *ibuf++;
284 buf->red = *ibuf++;
285 if (depth == 32)
286 ibuf++;
287 buf++;
288 break;
292 #if !defined(HAVE_LCD_COLOR) && \
293 ((LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \
294 defined(PLUGIN))
295 ibuf = ba->buf;
296 buf = (struct uint8_rgb*)ba->buf;
297 while (ibuf < ba->buf + cols)
298 *ibuf++ = brightness(*buf++);
299 #endif
301 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
302 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
303 cur_col += cols;
304 if (cur_col == width)
306 #endif
307 int pad = padded_width - read_width;
308 if (pad > 0)
310 BDEBUGF("seeking %d bytes to next line\n",pad);
311 lseek(fd, pad, SEEK_CUR);
313 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
314 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
315 cur_col = 0;
316 BDEBUGF("read_part_line: completed row %d\n", cur_row);
317 cur_row += 1;
320 ba->cur_row = cur_row;
321 ba->cur_col = cur_col;
322 #endif
323 return cols;
326 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
327 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
328 static struct img_part *store_part_bmp(void *args)
330 struct bmp_args *ba = (struct bmp_args *)args;
332 ba->part.len = read_part_line(ba);
333 #ifdef HAVE_LCD_COLOR
334 ba->part.buf = (struct uint8_rgb *)ba->buf;
335 #else
336 ba->part.buf = (uint8_t *)ba->buf;
337 #endif
338 if (ba->part.len)
339 return &(ba->part);
340 else
341 return NULL;
343 #endif
345 static inline int rgbcmp(struct uint8_rgb rgb1, struct uint8_rgb rgb2)
347 if ((rgb1.red == rgb2.red) && (rgb1.green == rgb2.green) &&
348 (rgb1.blue == rgb2.blue))
349 return 0;
350 else
351 return 1;
353 #if LCD_DEPTH > 1
354 #if !defined(PLUGIN) && !defined(HAVE_JPEG) && !defined(HAVE_BMP_SCALING)
355 static inline
356 #endif
357 void output_row_8_native(uint32_t row, void * row_in,
358 struct scaler_context *ctx)
360 int col;
361 int fb_width = BM_WIDTH(ctx->bm->width,FORMAT_NATIVE,0);
362 uint8_t dy = DITHERY(row);
363 #ifdef HAVE_LCD_COLOR
364 struct uint8_rgb *qp = (struct uint8_rgb*)row_in;
365 #else
366 uint8_t *qp = (uint8_t*)row_in;
367 #endif
368 BDEBUGF("output_row: y: %lu in: %p\n",row, row_in);
369 #if LCD_DEPTH == 2
370 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
371 /* greyscale iPods */
372 fb_data *dest = (fb_data *)ctx->bm->data + fb_width * row;
373 int shift = 6;
374 int delta = 127;
375 unsigned bright;
376 unsigned data = 0;
378 for (col = 0; col < ctx->bm->width; col++) {
379 if (ctx->dither)
380 delta = DITHERXDY(col,dy);
381 bright = *qp++;
382 bright = (3 * bright + (bright >> 6) + delta) >> 8;
383 data |= (~bright & 3) << shift;
384 shift -= 2;
385 if (shift < 0) {
386 *dest++ = data;
387 data = 0;
388 shift = 6;
391 if (shift < 6)
392 *dest++ = data;
393 #elif LCD_PIXELFORMAT == VERTICAL_PACKING
394 /* iriver H1x0 */
395 fb_data *dest = (fb_data *)ctx->bm->data + fb_width *
396 (row >> 2);
397 int shift = 2 * (row & 3);
398 int delta = 127;
399 unsigned bright;
401 for (col = 0; col < ctx->bm->width; col++) {
402 if (ctx->dither)
403 delta = DITHERXDY(col,dy);
404 bright = *qp++;
405 bright = (3 * bright + (bright >> 6) + delta) >> 8;
406 *dest++ |= (~bright & 3) << shift;
408 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
409 /* iAudio M3 */
410 fb_data *dest = (fb_data *)ctx->bm->data + fb_width *
411 (row >> 3);
412 int shift = row & 7;
413 int delta = 127;
414 unsigned bright;
416 for (col = 0; col < ctx->bm->width; col++) {
417 if (ctx->dither)
418 delta = DITHERXDY(col,dy);
419 bright = *qp++;
420 bright = (3 * bright + (bright >> 6) + delta) >> 8;
421 *dest++ |= vi_pattern[bright] << shift;
423 #endif /* LCD_PIXELFORMAT */
424 #elif LCD_DEPTH == 16
425 #if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE
426 /* M:Robe 500 */
427 (void) fb_width;
428 fb_data *dest = (fb_data *)ctx->bm->data + row;
429 int delta = 127;
430 unsigned r, g, b;
431 for (col = 0; col < ctx->bm->width; col++) {
432 if (ctx->dither)
433 delta = DITHERXDY(col,dy);
434 r = qp->red;
435 g = qp->green;
436 b = (qp++)->blue;
437 r = (31 * r + (r >> 3) + delta) >> 8;
438 g = (63 * g + (g >> 2) + delta) >> 8;
439 b = (31 * b + (b >> 3) + delta) >> 8;
440 *dest = LCD_RGBPACK_LCD(r, g, b);
441 dest += ctx->bm->height;
443 #else
444 /* iriver h300, colour iPods, X5 */
445 fb_data *dest = (fb_data *)ctx->bm->data + fb_width * row;
446 int delta = 127;
447 unsigned r, g, b;
448 for (col = 0; col < ctx->bm->width; col++) {
449 if (ctx->dither)
450 delta = DITHERXDY(col,dy);
451 r = qp->red;
452 g = qp->green;
453 b = (qp++)->blue;
454 r = (31 * r + (r >> 3) + delta) >> 8;
455 g = (63 * g + (g >> 2) + delta) >> 8;
456 b = (31 * b + (b >> 3) + delta) >> 8;
457 *dest++ = LCD_RGBPACK_LCD(r, g, b);
459 #endif
460 #endif /* LCD_DEPTH */
462 #endif
464 /******************************************************************************
465 * read_bmp_fd()
467 * Reads a BMP file in an open file descriptor and puts the data in rockbox
468 * format in *bitmap.
470 *****************************************************************************/
471 int read_bmp_fd(int fd,
472 struct bitmap *bm,
473 int maxsize,
474 int format,
475 const struct custom_format *cformat)
477 struct bmp_header bmph;
478 int padded_width;
479 int read_width;
480 int depth, numcolors, compression, totalsize;
481 int ret;
482 bool return_size = format & FORMAT_RETURN_SIZE;
484 unsigned char *bitmap = bm->data;
485 struct uint8_rgb palette[256];
486 struct rowset rset;
487 struct dim src_dim;
488 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \
489 defined(PLUGIN)
490 bool dither = false;
491 #endif
492 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
493 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
494 unsigned int resize = IMG_NORESIZE;
496 #ifdef HAVE_REMOTE_LCD
497 bool remote = false;
498 if (format & FORMAT_REMOTE) {
499 remote = true;
500 #if LCD_REMOTE_DEPTH == 1
501 format = FORMAT_MONO;
502 #endif
504 #endif /* HAVE_REMOTE_LCD */
506 if (format & FORMAT_RESIZE) {
507 resize = IMG_RESIZE;
510 #else
512 (void)format;
513 #endif /*(LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)*/
514 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \
515 defined(PLUGIN)
516 if (format & FORMAT_DITHER) {
517 dither = true;
519 #endif
520 /* read fileheader */
521 ret = read(fd, &bmph, sizeof(struct bmp_header));
522 if (ret < 0) {
523 return ret * 10 - 2;
526 if (ret != sizeof(struct bmp_header)) {
527 DEBUGF("read_bmp_fd: can't read BMP header.");
528 return -3;
531 src_dim.width = letoh32(bmph.width);
532 src_dim.height = letoh32(bmph.height);
533 if (src_dim.height < 0) { /* Top-down BMP file */
534 src_dim.height = -src_dim.height;
535 rset.rowstep = 1;
536 } else { /* normal BMP */
537 rset.rowstep = -1;
540 depth = letoh16(bmph.bit_count);
541 /* 4-byte boundary aligned */
542 read_width = ((src_dim.width * (depth == 15 ? 16 : depth) + 7) >> 3);
543 padded_width = (read_width + 3) & ~3;
545 BDEBUGF("width: %d height: %d depth: %d padded_width: %d\n", src_dim.width,
546 src_dim.height, depth, padded_width);
548 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
549 if ((format & 3) == FORMAT_ANY) {
550 if (depth == 1)
551 format = (format & ~3);
552 else
553 format = (format & ~3) | FORMAT_NATIVE;
555 bm->format = format & 1;
556 if ((format & 1) == FORMAT_MONO)
558 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
559 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
560 resize &= ~IMG_RESIZE;
561 resize |= IMG_NORESIZE;
562 #endif
563 #ifdef HAVE_REMOTE_LCD
564 remote = false;
565 #endif
567 #elif !defined(PLUGIN)
568 if (src_dim.width > BM_MAX_WIDTH)
569 return -6;
570 #endif /*(LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)*/
572 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
573 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
574 if (resize & IMG_RESIZE) {
575 if(format & FORMAT_KEEP_ASPECT) {
576 /* keep aspect ratio.. */
577 struct dim resize_dim = {
578 .width = bm->width,
579 .height = bm->height,
581 if (recalc_dimension(&resize_dim, &src_dim))
582 resize = IMG_NORESIZE;
583 bm->width = resize_dim.width;
584 bm->height = resize_dim.height;
588 if (!(resize & IMG_RESIZE)) {
589 #endif
590 /* returning image size */
591 bm->width = src_dim.width;
592 bm->height = src_dim.height;
594 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
595 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
597 #endif
598 #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
599 format &= 1;
600 #endif
601 if (rset.rowstep > 0) { /* Top-down BMP file */
602 rset.rowstart = 0;
603 rset.rowstop = bm->height;
604 } else { /* normal BMP */
605 rset.rowstart = bm->height - 1;
606 rset.rowstop = -1;
609 if (cformat)
610 totalsize = cformat->get_size(bm);
611 else
612 totalsize = BM_SIZE(bm->width,bm->height,format,remote);
614 if(return_size)
616 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
617 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
618 if(resize)
619 totalsize += BM_SCALED_SIZE(bm->width, 0, 0, 0);
620 else if (bm->width > BM_MAX_WIDTH)
621 totalsize += bm->width*4;
622 #endif
623 return totalsize;
626 /* Check if this fits the buffer */
627 if (totalsize > maxsize) {
628 DEBUGF("read_bmp_fd: Bitmap too large for buffer: "
629 "%d bytes.\n", totalsize);
630 return -6;
633 compression = letoh32(bmph.compression);
634 if (depth <= 8) {
635 numcolors = letoh32(bmph.clr_used);
636 if (numcolors == 0)
637 numcolors = BIT_N(depth);
638 } else
639 numcolors = (compression == 3) ? 3 : 0;
641 if (numcolors > 0 && numcolors <= 256) {
642 int i;
643 union rgb_union pal;
644 for (i = 0; i < numcolors; i++) {
645 if (read(fd, &pal, sizeof(pal)) != (int)sizeof(pal))
647 DEBUGF("read_bmp_fd: Can't read color palette\n");
648 return -7;
650 set_rgb_union(&palette[i], pal);
654 switch (depth) {
655 case 16:
656 #if LCD_DEPTH >= 16
657 /* don't dither 16 bit BMP to LCD with same or larger depth */
658 #ifdef HAVE_REMOTE_LCD
659 if (!remote)
660 #endif
661 dither = false;
662 #endif
663 if (compression == 0) { /* BI_RGB, i.e. 15 bit */
664 depth = 15;
665 break;
666 } /* else fall through */
668 case 32:
669 if (compression == 3) { /* BI_BITFIELDS */
670 bool found;
671 int i, j;
673 /* (i == 0) is 15bit, (i == 1) is 16bit, (i == 2) is 32bit */
674 for (i = 0; i < ARRAY_SIZE(bitfields); i++) {
675 for (j = 0; j < ARRAY_SIZE(bitfields[0]); j++) {
676 if (!rgbcmp(palette[j], bitfields[i][j])) {
677 found = true;
678 } else {
679 found = false;
680 break;
683 if (found) {
684 if (i == 0) /* 15bit */
685 depth = 15;
686 break;
689 if (found)
690 break;
691 } /* else fall through */
693 default:
694 if (compression != 0) { /* not BI_RGB */
695 DEBUGF("read_bmp_fd: Unsupported compression (type %d)\n",
696 compression);
697 return -8;
699 break;
702 /* Search to the beginning of the image data */
703 lseek(fd, (off_t)letoh32(bmph.off_bits), SEEK_SET);
705 memset(bitmap, 0, totalsize);
707 struct bmp_args ba = {
708 .fd = fd, .padded_width = padded_width, .read_width = read_width,
709 .width = src_dim.width, .depth = depth, .palette = palette,
710 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
711 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
712 .cur_row = 0, .cur_col = 0, .part = {0,0}
713 #endif
716 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
717 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
718 if (resize)
720 if (resize_on_load(bm, dither, &src_dim, &rset,
721 bitmap + totalsize, maxsize - totalsize,
722 cformat, IF_PIX_FMT(0,) store_part_bmp, &ba))
723 return totalsize;
724 else
725 return 0;
727 #endif /* LCD_DEPTH */
729 #if LCD_DEPTH > 1 || defined(PLUGIN)
730 struct scaler_context ctx = {
731 .bm = bm,
732 .dither = dither,
734 #endif
735 #if defined(PLUGIN) || defined(HAVE_JPEG) || defined(HAVE_BMP_SCALING)
736 #if LCD_DEPTH > 1
737 void (*output_row_8)(uint32_t, void*, struct scaler_context*) =
738 output_row_8_native;
739 #elif defined(PLUGIN)
740 void (*output_row_8)(uint32_t, void*, struct scaler_context*) = NULL;
741 #endif
742 #if LCD_DEPTH > 1 || defined(PLUGIN)
743 if (cformat)
744 output_row_8 = cformat->output_row_8;
745 #endif
746 #endif
748 unsigned char *buf = ba.buf;
749 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \
750 defined(PLUGIN)
751 if (bm->width > BM_MAX_WIDTH)
753 #if defined(HAVE_BMP_SCALING) || defined(PLUGIN)
754 unsigned int len = maxsize - totalsize;
755 buf = bitmap + totalsize;
756 ALIGN_BUFFER(buf, len, sizeof(uint32_t));
757 if (bm->width*4 > (int)len)
758 #endif
759 return -6;
761 #endif
763 int row;
764 /* loop to read rows and put them to buffer */
765 for (row = rset.rowstart; row != rset.rowstop; row += rset.rowstep) {
766 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
767 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
768 if (bm->width > BM_MAX_WIDTH)
770 #if defined(HAVE_LCD_COLOR)
771 struct uint8_rgb *p = (struct uint8_rgb *)buf;
772 #else
773 uint8_t* p = buf;
774 #endif
775 do {
776 int len = read_part_line(&ba);
777 if (!len)
778 return -9;
779 memcpy(p, ba.buf, len*sizeof(*p));
780 p += len;
781 } while (ba.cur_col);
783 else
784 #endif
785 if (!read_part_line(&ba))
786 return -9;
787 #ifndef PLUGIN
788 #if !defined(HAVE_LCD_COLOR) && \
789 (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
790 uint8_t* qp = buf;
791 #else
792 struct uint8_rgb *qp = (struct uint8_rgb *)buf;
793 #endif
794 #endif
795 /* Convert to destination format */
796 #if ((LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) && \
797 !defined(PLUGIN)
798 if (format == FORMAT_NATIVE) {
799 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
800 if (remote) {
801 unsigned char dy = DITHERY(row);
802 #if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)
803 /* iAudio X5/M5 remote */
804 fb_remote_data *dest = (fb_remote_data *)bitmap
805 + bm->width * (row >> 3);
806 int shift = row & 7;
807 int delta = 127;
808 unsigned bright;
810 int col;
811 for (col = 0; col < bm->width; col++) {
812 if (dither)
813 delta = DITHERXDY(col,dy);
814 #if !defined(HAVE_LCD_COLOR) && \
815 (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
816 bright = *qp++;
817 #else
818 bright = brightness(*qp++);
819 #endif
820 bright = (3 * bright + (bright >> 6) + delta) >> 8;
821 *dest++ |= vi_pattern[bright] << shift;
823 #endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */
824 } else
825 #endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */
826 #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) &&
827 (LCD_REMOTE_DEPTH > 1) */
828 #if LCD_DEPTH > 1 || defined(PLUGIN)
830 #if !defined(PLUGIN) && !defined(HAVE_JPEG) && !defined(HAVE_BMP_SCALING)
831 output_row_8_native(row, buf, &ctx);
832 #else
833 output_row_8(row, buf, &ctx);
834 #endif
836 #endif
837 #if ((LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) && \
838 !defined(PLUGIN)
840 #ifndef PLUGIN
841 else
842 #endif
843 #endif
844 #ifndef PLUGIN
846 unsigned char *p = bitmap + bm->width * (row >> 3);
847 unsigned char mask = BIT_N(row & 7);
848 int col;
849 for (col = 0; col < bm->width; col++, p++)
850 #if !defined(HAVE_LCD_COLOR) && \
851 (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
852 if (*qp++ < 128)
853 *p |= mask;
854 #else
855 if (brightness(*qp++) < 128)
856 *p |= mask;
857 #endif
859 #endif
861 #ifdef HAVE_REMOTE_LCD
862 /* Thanks to the mass of #ifdefs in this function, there are cases where
863 * remote is never read, so we need to suppress the resulting warnings
864 * (or rewrite the lot)*/
865 (void)remote;
866 #endif
867 return totalsize; /* return the used buffer size. */