Update Swedish translation.
[maemo-rb.git] / apps / recorder / bmp.c
blobb67615b840da2f35a43315608e0bf971e5276635
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 #ifndef PLUGIN
46 #include "debug.h"
47 #endif
48 #include "lcd.h"
49 #include "file.h"
50 #include "bmp.h"
51 #ifdef HAVE_REMOTE_LCD
52 #include "lcd-remote.h"
53 #endif
54 #ifdef ROCKBOX_DEBUG_BMP_LOADER
55 #define BDEBUGF DEBUGF
56 #else
57 #define BDEBUGF(...)
58 #endif
59 #ifndef __PCTOOL__
60 #include "config.h"
61 #include "system.h"
62 #include "resize.h"
63 #else
64 #include "checkwps.h"
65 #undef DEBUGF
66 #define DEBUGF(...)
67 #endif
69 #ifdef __GNUC__
70 #define STRUCT_PACKED __attribute__((packed))
71 #else
72 #define STRUCT_PACKED
73 #pragma pack (push, 2)
74 #endif
76 /* BMP header structure */
77 struct bmp_header {
78 uint16_t type; /* signature - 'BM' */
79 uint32_t size; /* file size in bytes */
80 uint16_t reserved1; /* 0 */
81 uint16_t reserved2; /* 0 */
82 uint32_t off_bits; /* offset to bitmap */
83 uint32_t struct_size; /* size of this struct (40) */
84 int32_t width; /* bmap width in pixels */
85 int32_t height; /* bmap height in pixels */
86 uint16_t planes; /* num planes - always 1 */
87 uint16_t bit_count; /* bits per pixel */
88 uint32_t compression; /* compression flag */
89 uint32_t size_image; /* image size in bytes */
90 int32_t x_pels_per_meter; /* horz resolution */
91 int32_t y_pels_per_meter; /* vert resolution */
92 uint32_t clr_used; /* 0 -> color table size */
93 uint32_t clr_important; /* important color count */
94 } STRUCT_PACKED;
96 union rgb_union {
97 struct { /* Little endian */
98 unsigned char blue;
99 unsigned char green;
100 unsigned char red;
101 unsigned char reserved;
103 uint32_t raw;
106 /* masks for supported BI_BITFIELDS encodings (16/32 bit) */
107 static const struct uint8_rgb bitfields[3][3] = {
108 /* 15bit */
110 { .blue = 0x00, .green = 0x7c, .red = 0x00 },
111 { .blue = 0xe0, .green = 0x03, .red = 0x00 },
112 { .blue = 0x1f, .green = 0x00, .red = 0x00 },
114 /* 16bit */
116 { .blue = 0x00, .green = 0xf8, .red = 0x00 },
117 { .blue = 0xe0, .green = 0x07, .red = 0x00 },
118 { .blue = 0x1f, .green = 0x00, .red = 0x00 },
120 /* 32bit */
122 { .blue = 0x00, .green = 0x00, .red = 0xff },
123 { .blue = 0x00, .green = 0xff, .red = 0x00 },
124 { .blue = 0xff, .green = 0x00, .red = 0x00 },
128 #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
129 /* the full 16x16 Bayer dither matrix may be calculated quickly with this table
131 const unsigned char dither_table[16] =
132 { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 };
133 #endif
135 #if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \
136 || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH == 2) \
137 && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED))
138 const unsigned short vi_pattern[4] = {
139 0x0101, 0x0100, 0x0001, 0x0000
141 #endif
143 /******************************************************************************
144 * read_bmp_file()
146 * Reads a BMP file and puts the data in rockbox format in *bitmap.
148 *****************************************************************************/
149 int read_bmp_file(const char* filename,
150 struct bitmap *bm,
151 int maxsize,
152 int format,
153 const struct custom_format *cformat)
155 int fd, ret;
156 fd = open(filename, O_RDONLY);
158 /* Exit if file opening failed */
159 if (fd < 0) {
160 DEBUGF("read_bmp_file: can't open '%s', rc: %d\n", filename, fd);
161 return fd * 10 - 1;
164 BDEBUGF("read_bmp_file: '%s' remote: %d resize: %d keep_aspect: %d\n",
165 filename, !!(format & FORMAT_REMOTE), !!(format & FORMAT_RESIZE),
166 !!(format & FORMAT_KEEP_ASPECT));
167 ret = read_bmp_fd(fd, bm, maxsize, format, cformat);
168 close(fd);
169 return ret;
172 static inline void set_rgb_union(struct uint8_rgb *dst, union rgb_union src)
174 dst->red = src.red;
175 dst->green = src.green;
176 dst->blue = src.blue;
179 struct bmp_args {
180 int fd;
181 short padded_width;
182 short read_width;
183 short width;
184 short depth;
185 unsigned char buf[BM_MAX_WIDTH * 4];
186 struct uint8_rgb *palette;
187 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
188 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
189 int cur_row;
190 int cur_col;
191 struct img_part part;
192 #endif
195 static unsigned int read_part_line(struct bmp_args *ba)
197 const int padded_width = ba->padded_width;
198 const int read_width = ba->read_width;
199 const int width = ba->width;
200 const int depth = ba->depth;
201 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
202 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
203 int cur_row = ba->cur_row;
204 int cur_col = ba->cur_col;
205 #endif
206 const int fd = ba->fd;
207 uint8_t *ibuf;
208 struct uint8_rgb *buf = (struct uint8_rgb *)(ba->buf);
209 const struct uint8_rgb *palette = ba->palette;
210 uint32_t component, data = data;
211 int ret;
212 int i, cols, len;
214 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
215 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
216 cols = MIN(width - cur_col,(int)BM_MAX_WIDTH);
217 BDEBUGF("reading %d cols (width: %d, max: %d)\n",cols,width,BM_MAX_WIDTH);
218 len = (cols * (depth == 15 ? 16 : depth) + 7) >> 3;
219 #else
220 cols = width;
221 len = read_width;
222 #endif
223 ibuf = ((unsigned char *)buf) + (BM_MAX_WIDTH << 2) - len;
224 BDEBUGF("read_part_line: cols=%d len=%d\n",cols,len);
225 ret = read(fd, ibuf, len);
226 if (ret != len)
228 DEBUGF("read_part_line: error reading image, read returned %d "
229 "expected %d\n", ret, len);
230 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
231 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
232 BDEBUGF("cur_row: %d cur_col: %d cols: %d len: %d\n", cur_row, cur_col,
233 cols, len);
234 #endif
235 return 0;
237 while (ibuf < ba->buf + (BM_MAX_WIDTH << 2))
239 switch (depth)
241 case 1:
242 data = *ibuf++;
243 for (i = 0; i < 8; i++)
245 *buf++ = palette[data & 0x80 ? 1 : 0];
246 data <<= 1;
248 break;
249 case 4:
250 data = *ibuf++;
251 *buf++ = palette[data >> 4];
252 *buf++ = palette[data & 0xf];
253 break;
254 case 8:
255 *buf++ = palette[*ibuf++];
256 break;
257 case 15:
258 case 16:
259 data = letoh16(*(uint16_t*)ibuf);
260 component = (data << 3) & 0xf8;
261 component |= component >> 5;
262 buf->blue = component;
263 if (depth == 15)
265 data >>= 2;
266 component = data & 0xf8;
267 component |= component >> 5;
268 } else {
269 data >>= 3;
270 component = data & 0xfc;
271 component |= component >> 6;
273 buf->green = component;
274 data >>= 5;
275 component = data & 0xf8;
276 component |= component >> 5;
277 buf->red = component;
278 buf++;
279 ibuf += 2;
280 break;
281 case 32:
282 case 24:
283 buf->blue = *ibuf++;
284 buf->green = *ibuf++;
285 buf->red = *ibuf++;
286 if (depth == 32)
287 ibuf++;
288 buf++;
289 break;
293 #if !defined(HAVE_LCD_COLOR) && \
294 ((LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \
295 defined(PLUGIN))
296 ibuf = ba->buf;
297 buf = (struct uint8_rgb*)ba->buf;
298 while (ibuf < ba->buf + cols)
299 *ibuf++ = brightness(*buf++);
300 #endif
302 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
303 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
304 cur_col += cols;
305 if (cur_col == width)
307 #endif
308 int pad = padded_width - read_width;
309 if (pad > 0)
311 BDEBUGF("seeking %d bytes to next line\n",pad);
312 lseek(fd, pad, SEEK_CUR);
314 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
315 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
316 cur_col = 0;
317 BDEBUGF("read_part_line: completed row %d\n", cur_row);
318 cur_row += 1;
321 ba->cur_row = cur_row;
322 ba->cur_col = cur_col;
323 #endif
324 return cols;
327 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
328 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
329 static struct img_part *store_part_bmp(void *args)
331 struct bmp_args *ba = (struct bmp_args *)args;
333 ba->part.len = read_part_line(ba);
334 #ifdef HAVE_LCD_COLOR
335 ba->part.buf = (struct uint8_rgb *)ba->buf;
336 #else
337 ba->part.buf = (uint8_t *)ba->buf;
338 #endif
339 if (ba->part.len)
340 return &(ba->part);
341 else
342 return NULL;
344 #endif
346 static inline int rgbcmp(struct uint8_rgb rgb1, struct uint8_rgb rgb2)
348 if ((rgb1.red == rgb2.red) && (rgb1.green == rgb2.green) &&
349 (rgb1.blue == rgb2.blue))
350 return 0;
351 else
352 return 1;
354 #if LCD_DEPTH > 1
355 #if !defined(PLUGIN) && !defined(HAVE_JPEG) && !defined(HAVE_BMP_SCALING)
356 static inline
357 #endif
358 void output_row_8_native(uint32_t row, void * row_in,
359 struct scaler_context *ctx)
361 int col;
362 int fb_width = BM_WIDTH(ctx->bm->width,FORMAT_NATIVE,0);
363 uint8_t dy = DITHERY(row);
364 #ifdef HAVE_LCD_COLOR
365 struct uint8_rgb *qp = (struct uint8_rgb*)row_in;
366 #else
367 uint8_t *qp = (uint8_t*)row_in;
368 #endif
369 BDEBUGF("output_row: y: %lu in: %p\n",row, row_in);
370 #if LCD_DEPTH == 2
371 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
372 /* greyscale iPods */
373 fb_data *dest = (fb_data *)ctx->bm->data + fb_width * row;
374 int shift = 6;
375 int delta = 127;
376 unsigned bright;
377 unsigned data = 0;
379 for (col = 0; col < ctx->bm->width; col++) {
380 if (ctx->dither)
381 delta = DITHERXDY(col,dy);
382 bright = *qp++;
383 bright = (3 * bright + (bright >> 6) + delta) >> 8;
384 data |= (~bright & 3) << shift;
385 shift -= 2;
386 if (shift < 0) {
387 *dest++ = data;
388 data = 0;
389 shift = 6;
392 if (shift < 6)
393 *dest++ = data;
394 #elif LCD_PIXELFORMAT == VERTICAL_PACKING
395 /* iriver H1x0 */
396 fb_data *dest = (fb_data *)ctx->bm->data + fb_width *
397 (row >> 2);
398 int shift = 2 * (row & 3);
399 int delta = 127;
400 unsigned bright;
402 for (col = 0; col < ctx->bm->width; col++) {
403 if (ctx->dither)
404 delta = DITHERXDY(col,dy);
405 bright = *qp++;
406 bright = (3 * bright + (bright >> 6) + delta) >> 8;
407 *dest++ |= (~bright & 3) << shift;
409 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
410 /* iAudio M3 */
411 fb_data *dest = (fb_data *)ctx->bm->data + fb_width *
412 (row >> 3);
413 int shift = row & 7;
414 int delta = 127;
415 unsigned bright;
417 for (col = 0; col < ctx->bm->width; col++) {
418 if (ctx->dither)
419 delta = DITHERXDY(col,dy);
420 bright = *qp++;
421 bright = (3 * bright + (bright >> 6) + delta) >> 8;
422 *dest++ |= vi_pattern[bright] << shift;
424 #endif /* LCD_PIXELFORMAT */
425 #elif LCD_DEPTH == 16
426 #if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE
427 /* M:Robe 500 */
428 (void) fb_width;
429 fb_data *dest = (fb_data *)ctx->bm->data + row;
430 int delta = 127;
431 unsigned r, g, b;
432 for (col = 0; col < ctx->bm->width; col++) {
433 if (ctx->dither)
434 delta = DITHERXDY(col,dy);
435 r = qp->red;
436 g = qp->green;
437 b = (qp++)->blue;
438 r = (31 * r + (r >> 3) + delta) >> 8;
439 g = (63 * g + (g >> 2) + delta) >> 8;
440 b = (31 * b + (b >> 3) + delta) >> 8;
441 *dest = LCD_RGBPACK_LCD(r, g, b);
442 dest += ctx->bm->height;
444 #else
445 /* iriver h300, colour iPods, X5 */
446 fb_data *dest = (fb_data *)ctx->bm->data + fb_width * row;
447 int delta = 127;
448 unsigned r, g, b;
449 for (col = 0; col < ctx->bm->width; col++) {
450 if (ctx->dither)
451 delta = DITHERXDY(col,dy);
452 r = qp->red;
453 g = qp->green;
454 b = (qp++)->blue;
455 r = (31 * r + (r >> 3) + delta) >> 8;
456 g = (63 * g + (g >> 2) + delta) >> 8;
457 b = (31 * b + (b >> 3) + delta) >> 8;
458 *dest++ = LCD_RGBPACK_LCD(r, g, b);
460 #endif
461 #endif /* LCD_DEPTH */
463 #endif
465 /******************************************************************************
466 * read_bmp_fd()
468 * Reads a BMP file in an open file descriptor and puts the data in rockbox
469 * format in *bitmap.
471 *****************************************************************************/
472 int read_bmp_fd(int fd,
473 struct bitmap *bm,
474 int maxsize,
475 int format,
476 const struct custom_format *cformat)
478 struct bmp_header bmph;
479 int padded_width;
480 int read_width;
481 int depth, numcolors, compression, totalsize;
482 int ret;
483 bool return_size = format & FORMAT_RETURN_SIZE;
485 unsigned char *bitmap = bm->data;
486 struct uint8_rgb palette[256];
487 struct rowset rset;
488 struct dim src_dim;
489 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \
490 defined(PLUGIN)
491 bool dither = false;
492 #endif
493 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
494 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
495 unsigned int resize = IMG_NORESIZE;
496 bool transparent = false;
498 #ifdef HAVE_REMOTE_LCD
499 bool remote = false;
500 if (format & FORMAT_REMOTE) {
501 remote = true;
502 #if LCD_REMOTE_DEPTH == 1
503 format = FORMAT_MONO;
504 #endif
506 #endif /* HAVE_REMOTE_LCD */
508 if (format & FORMAT_RESIZE) {
509 resize = IMG_RESIZE;
512 if (format & FORMAT_TRANSPARENT) {
513 transparent = true;
515 #else
517 (void)format;
518 #endif /*(LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)*/
519 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \
520 defined(PLUGIN)
521 if (format & FORMAT_DITHER) {
522 dither = true;
524 #endif
525 /* read fileheader */
526 ret = read(fd, &bmph, sizeof(struct bmp_header));
527 if (ret < 0) {
528 return ret * 10 - 2;
531 if (ret != sizeof(struct bmp_header)) {
532 DEBUGF("read_bmp_fd: can't read BMP header.");
533 return -3;
536 src_dim.width = letoh32(bmph.width);
537 src_dim.height = letoh32(bmph.height);
538 if (src_dim.height < 0) { /* Top-down BMP file */
539 src_dim.height = -src_dim.height;
540 rset.rowstep = 1;
541 } else { /* normal BMP */
542 rset.rowstep = -1;
545 depth = letoh16(bmph.bit_count);
546 /* 4-byte boundary aligned */
547 read_width = ((src_dim.width * (depth == 15 ? 16 : depth) + 7) >> 3);
548 padded_width = (read_width + 3) & ~3;
550 BDEBUGF("width: %d height: %d depth: %d padded_width: %d\n", src_dim.width,
551 src_dim.height, depth, padded_width);
553 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
554 if ((format & 3) == FORMAT_ANY) {
555 if (depth == 1)
556 format = (format & ~3);
557 else
558 format = (format & ~3) | FORMAT_NATIVE;
560 bm->format = format & 1;
561 if ((format & 1) == FORMAT_MONO)
563 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
564 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
565 resize &= ~IMG_RESIZE;
566 resize |= IMG_NORESIZE;
567 #endif
568 #ifdef HAVE_REMOTE_LCD
569 remote = 0;
570 #endif
572 #elif !defined(PLUGIN)
573 if (src_dim.width > BM_MAX_WIDTH)
574 return -6;
575 #endif /*(LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)*/
577 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
578 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
579 if (resize & IMG_RESIZE) {
580 if(format & FORMAT_KEEP_ASPECT) {
581 /* keep aspect ratio.. */
582 struct dim resize_dim = {
583 .width = bm->width,
584 .height = bm->height,
586 if (recalc_dimension(&resize_dim, &src_dim))
587 resize = IMG_NORESIZE;
588 bm->width = resize_dim.width;
589 bm->height = resize_dim.height;
593 if (!(resize & IMG_RESIZE)) {
594 #endif
595 /* returning image size */
596 bm->width = src_dim.width;
597 bm->height = src_dim.height;
599 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
600 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
602 #endif
603 #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
604 format &= 1;
605 #endif
606 if (rset.rowstep > 0) { /* Top-down BMP file */
607 rset.rowstart = 0;
608 rset.rowstop = bm->height;
609 } else { /* normal BMP */
610 rset.rowstart = bm->height - 1;
611 rset.rowstop = -1;
614 if (cformat)
615 totalsize = cformat->get_size(bm);
616 else
617 totalsize = BM_SIZE(bm->width,bm->height,format,remote);
619 if(return_size)
621 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
622 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
623 if(resize)
624 totalsize += BM_SCALED_SIZE(bm->width, 0, 0, 0);
625 #endif
626 return totalsize;
629 /* Check if this fits the buffer */
630 if (totalsize > maxsize) {
631 DEBUGF("read_bmp_fd: Bitmap too large for buffer: "
632 "%d bytes.\n", totalsize);
633 return -6;
636 compression = letoh32(bmph.compression);
637 if (depth <= 8) {
638 numcolors = letoh32(bmph.clr_used);
639 if (numcolors == 0)
640 numcolors = BIT_N(depth);
641 } else
642 numcolors = (compression == 3) ? 3 : 0;
644 if (numcolors > 0 && numcolors <= 256) {
645 int i;
646 union rgb_union pal;
647 for (i = 0; i < numcolors; i++) {
648 if (read(fd, &pal, sizeof(pal)) != (int)sizeof(pal))
650 DEBUGF("read_bmp_fd: Can't read color palette\n");
651 return -7;
653 set_rgb_union(&palette[i], pal);
657 switch (depth) {
658 case 16:
659 #if LCD_DEPTH >= 16
660 /* don't dither 16 bit BMP to LCD with same or larger depth */
661 #ifdef HAVE_REMOTE_LCD
662 if (!remote)
663 #endif
664 dither = false;
665 #endif
666 if (compression == 0) { /* BI_RGB, i.e. 15 bit */
667 depth = 15;
668 break;
669 } /* else fall through */
671 case 32:
672 if (compression == 3) { /* BI_BITFIELDS */
673 bool found;
674 int i, j;
676 /* (i == 0) is 15bit, (i == 1) is 16bit, (i == 2) is 32bit */
677 for (i = 0; i < ARRAY_SIZE(bitfields); i++) {
678 for (j = 0; j < ARRAY_SIZE(bitfields[0]); j++) {
679 if (!rgbcmp(palette[j], bitfields[i][j])) {
680 found = true;
681 } else {
682 found = false;
683 break;
686 if (found) {
687 if (i == 0) /* 15bit */
688 depth = 15;
689 break;
692 if (found)
693 break;
694 } /* else fall through */
696 default:
697 if (compression != 0) { /* not BI_RGB */
698 DEBUGF("read_bmp_fd: Unsupported compression (type %d)\n",
699 compression);
700 return -8;
702 break;
705 /* Search to the beginning of the image data */
706 lseek(fd, (off_t)letoh32(bmph.off_bits), SEEK_SET);
708 memset(bitmap, 0, totalsize);
710 struct bmp_args ba = {
711 .fd = fd, .padded_width = padded_width, .read_width = read_width,
712 .width = src_dim.width, .depth = depth, .palette = palette,
713 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
714 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
715 .cur_row = 0, .cur_col = 0, .part = {0,0}
716 #endif
719 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
720 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
721 #if LCD_DEPTH > 1 && defined(HAVE_BMP_SCALING)
722 if (resize)
723 #endif
725 if (resize_on_load(bm, dither, &src_dim, &rset,
726 bitmap + totalsize, maxsize - totalsize,
727 cformat, IF_PIX_FMT(0,) store_part_bmp, &ba))
728 return totalsize;
729 else
730 return 0;
732 #endif /* LCD_DEPTH */
734 #if LCD_DEPTH > 1 || defined(PLUGIN)
735 struct scaler_context ctx = {
736 .bm = bm,
737 .dither = dither,
739 #endif
740 #if defined(PLUGIN) || defined(HAVE_JPEG) || defined(HAVE_BMP_SCALING)
741 #if LCD_DEPTH > 1
742 void (*output_row_8)(uint32_t, void*, struct scaler_context*) =
743 output_row_8_native;
744 #elif defined(PLUGIN)
745 void (*output_row_8)(uint32_t, void*, struct scaler_context*) = NULL;
746 #endif
747 #if LCD_DEPTH > 1 || defined(PLUGIN)
748 if (cformat)
749 output_row_8 = cformat->output_row_8;
750 #endif
751 #endif
753 int row;
754 /* loop to read rows and put them to buffer */
755 for (row = rset.rowstart; row != rset.rowstop; row += rset.rowstep) {
756 if (!read_part_line(&ba))
757 return -9;
758 #ifndef PLUGIN
759 #if !defined(HAVE_LCD_COLOR) && \
760 (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
761 uint8_t* qp = ba.buf;
762 #else
763 struct uint8_rgb *qp = (struct uint8_rgb *)ba.buf;
764 #endif
765 #endif
766 /* Convert to destination format */
767 #if ((LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) && \
768 !defined(PLUGIN)
769 if (format == FORMAT_NATIVE) {
770 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
771 if (remote) {
772 unsigned char dy = DITHERY(row);
773 #if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)
774 /* iAudio X5/M5 remote */
775 fb_remote_data *dest = (fb_remote_data *)bitmap
776 + bm->width * (row >> 3);
777 int shift = row & 7;
778 int delta = 127;
779 unsigned bright;
781 int col;
782 for (col = 0; col < bm->width; col++) {
783 if (dither)
784 delta = DITHERXDY(col,dy);
785 #if !defined(HAVE_LCD_COLOR) && \
786 (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
787 bright = *qp++;
788 #else
789 bright = brightness(*qp++);
790 #endif
791 bright = (3 * bright + (bright >> 6) + delta) >> 8;
792 *dest++ |= vi_pattern[bright] << shift;
794 #endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */
795 } else
796 #endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */
797 #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) &&
798 (LCD_REMOTE_DEPTH > 1) */
799 #if LCD_DEPTH > 1 || defined(PLUGIN)
801 #if !defined(PLUGIN) && !defined(HAVE_JPEG) && !defined(HAVE_BMP_SCALING)
802 output_row_8_native(row, ba.buf, &ctx);
803 #else
804 output_row_8(row, ba.buf, &ctx);
805 #endif
807 #endif
808 #if ((LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) && \
809 !defined(PLUGIN)
811 #ifndef PLUGIN
812 else
813 #endif
814 #endif
815 #ifndef PLUGIN
817 unsigned char *p = bitmap + bm->width * (row >> 3);
818 unsigned char mask = BIT_N(row & 7);
819 int col;
820 for (col = 0; col < bm->width; col++, p++)
821 #if !defined(HAVE_LCD_COLOR) && \
822 (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
823 if (*qp++ < 128)
824 *p |= mask;
825 #else
826 if (brightness(*qp++) < 128)
827 *p |= mask;
828 #endif
830 #endif
832 return totalsize; /* return the used buffer size. */