FS#8961 - Anti-Aliased Fonts.
[kugel-rb.git] / apps / recorder / bmp.c
blob8fcd8ca92ea6c9f0957df37965db59bba6dc796c
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 /* iriver h300, colour iPods, X5 */
427 fb_data *dest = (fb_data *)ctx->bm->data + fb_width * row;
428 int delta = 127;
429 unsigned r, g, b;
430 for (col = 0; col < ctx->bm->width; col++) {
431 if (ctx->dither)
432 delta = DITHERXDY(col,dy);
433 r = qp->red;
434 g = qp->green;
435 b = (qp++)->blue;
436 r = (31 * r + (r >> 3) + delta) >> 8;
437 g = (63 * g + (g >> 2) + delta) >> 8;
438 b = (31 * b + (b >> 3) + delta) >> 8;
439 *dest++ = LCD_RGBPACK_LCD(r, g, b);
441 #endif /* LCD_DEPTH */
443 #endif
445 /******************************************************************************
446 * read_bmp_fd()
448 * Reads a BMP file in an open file descriptor and puts the data in rockbox
449 * format in *bitmap.
451 *****************************************************************************/
452 int read_bmp_fd(int fd,
453 struct bitmap *bm,
454 int maxsize,
455 int format,
456 const struct custom_format *cformat)
458 struct bmp_header bmph;
459 int padded_width;
460 int read_width;
461 int depth, numcolors, compression, totalsize;
462 int ret;
463 bool return_size = format & FORMAT_RETURN_SIZE;
465 unsigned char *bitmap = bm->data;
466 struct uint8_rgb palette[256];
467 struct rowset rset;
468 struct dim src_dim;
469 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \
470 defined(PLUGIN)
471 bool dither = false;
472 #endif
473 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
474 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
475 unsigned int resize = IMG_NORESIZE;
476 bool transparent = false;
478 #ifdef HAVE_REMOTE_LCD
479 bool remote = false;
480 if (format & FORMAT_REMOTE) {
481 remote = true;
482 #if LCD_REMOTE_DEPTH == 1
483 format = FORMAT_MONO;
484 #endif
486 #endif /* HAVE_REMOTE_LCD */
488 if (format & FORMAT_RESIZE) {
489 resize = IMG_RESIZE;
492 if (format & FORMAT_TRANSPARENT) {
493 transparent = true;
495 #else
497 (void)format;
498 #endif /*(LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)*/
499 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \
500 defined(PLUGIN)
501 if (format & FORMAT_DITHER) {
502 dither = true;
504 #endif
505 /* read fileheader */
506 ret = read(fd, &bmph, sizeof(struct bmp_header));
507 if (ret < 0) {
508 return ret * 10 - 2;
511 if (ret != sizeof(struct bmp_header)) {
512 DEBUGF("read_bmp_fd: can't read BMP header.");
513 return -3;
516 src_dim.width = letoh32(bmph.width);
517 src_dim.height = letoh32(bmph.height);
518 if (src_dim.height < 0) { /* Top-down BMP file */
519 src_dim.height = -src_dim.height;
520 rset.rowstep = 1;
521 } else { /* normal BMP */
522 rset.rowstep = -1;
525 depth = letoh16(bmph.bit_count);
526 /* 4-byte boundary aligned */
527 read_width = ((src_dim.width * (depth == 15 ? 16 : depth) + 7) >> 3);
528 padded_width = (read_width + 3) & ~3;
530 BDEBUGF("width: %d height: %d depth: %d padded_width: %d\n", src_dim.width,
531 src_dim.height, depth, padded_width);
533 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
534 if ((format & 3) == FORMAT_ANY) {
535 if (depth == 1)
536 format = (format & ~3);
537 else
538 format = (format & ~3) | FORMAT_NATIVE;
540 bm->format = format & 1;
541 if ((format & 1) == FORMAT_MONO)
543 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
544 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
545 resize &= ~IMG_RESIZE;
546 resize |= IMG_NORESIZE;
547 #endif
548 #ifdef HAVE_REMOTE_LCD
549 remote = 0;
550 #endif
552 #elif !defined(PLUGIN)
553 if (src_dim.width > BM_MAX_WIDTH)
554 return -6;
555 #endif /*(LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)*/
557 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
558 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
559 if (resize & IMG_RESIZE) {
560 if(format & FORMAT_KEEP_ASPECT) {
561 /* keep aspect ratio.. */
562 struct dim resize_dim = {
563 .width = bm->width,
564 .height = bm->height,
566 if (recalc_dimension(&resize_dim, &src_dim))
567 resize = IMG_NORESIZE;
568 bm->width = resize_dim.width;
569 bm->height = resize_dim.height;
573 if (!(resize & IMG_RESIZE)) {
574 #endif
575 /* returning image size */
576 bm->width = src_dim.width;
577 bm->height = src_dim.height;
579 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
580 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
582 #endif
583 #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
584 format &= 1;
585 #endif
586 if (rset.rowstep > 0) { /* Top-down BMP file */
587 rset.rowstart = 0;
588 rset.rowstop = bm->height;
589 } else { /* normal BMP */
590 rset.rowstart = bm->height - 1;
591 rset.rowstop = -1;
594 if (cformat)
595 totalsize = cformat->get_size(bm);
596 else
597 totalsize = BM_SIZE(bm->width,bm->height,format,remote);
599 if(return_size)
601 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
602 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
603 if(resize)
604 totalsize += BM_SCALED_SIZE(bm->width, 0, 0, 0);
605 #endif
606 return totalsize;
609 /* Check if this fits the buffer */
610 if (totalsize > maxsize) {
611 DEBUGF("read_bmp_fd: Bitmap too large for buffer: "
612 "%d bytes.\n", totalsize);
613 return -6;
616 compression = letoh32(bmph.compression);
617 if (depth <= 8) {
618 numcolors = letoh32(bmph.clr_used);
619 if (numcolors == 0)
620 numcolors = BIT_N(depth);
621 } else
622 numcolors = (compression == 3) ? 3 : 0;
624 if (numcolors > 0 && numcolors <= 256) {
625 int i;
626 union rgb_union pal;
627 for (i = 0; i < numcolors; i++) {
628 if (read(fd, &pal, sizeof(pal)) != (int)sizeof(pal))
630 DEBUGF("read_bmp_fd: Can't read color palette\n");
631 return -7;
633 set_rgb_union(&palette[i], pal);
637 switch (depth) {
638 case 16:
639 #if LCD_DEPTH >= 16
640 /* don't dither 16 bit BMP to LCD with same or larger depth */
641 #ifdef HAVE_REMOTE_LCD
642 if (!remote)
643 #endif
644 dither = false;
645 #endif
646 if (compression == 0) { /* BI_RGB, i.e. 15 bit */
647 depth = 15;
648 break;
649 } /* else fall through */
651 case 32:
652 if (compression == 3) { /* BI_BITFIELDS */
653 bool found;
654 int i, j;
656 /* (i == 0) is 15bit, (i == 1) is 16bit, (i == 2) is 32bit */
657 for (i = 0; i < ARRAY_SIZE(bitfields); i++) {
658 for (j = 0; j < ARRAY_SIZE(bitfields[0]); j++) {
659 if (!rgbcmp(palette[j], bitfields[i][j])) {
660 found = true;
661 } else {
662 found = false;
663 break;
666 if (found) {
667 if (i == 0) /* 15bit */
668 depth = 15;
669 break;
672 if (found)
673 break;
674 } /* else fall through */
676 default:
677 if (compression != 0) { /* not BI_RGB */
678 DEBUGF("read_bmp_fd: Unsupported compression (type %d)\n",
679 compression);
680 return -8;
682 break;
685 /* Search to the beginning of the image data */
686 lseek(fd, (off_t)letoh32(bmph.off_bits), SEEK_SET);
688 memset(bitmap, 0, totalsize);
690 struct bmp_args ba = {
691 .fd = fd, .padded_width = padded_width, .read_width = read_width,
692 .width = src_dim.width, .depth = depth, .palette = palette,
693 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
694 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
695 .cur_row = 0, .cur_col = 0, .part = {0,0}
696 #endif
699 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
700 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
701 #if LCD_DEPTH > 1 && defined(HAVE_BMP_SCALING)
702 if (resize)
703 #endif
705 if (resize_on_load(bm, dither, &src_dim, &rset,
706 bitmap + totalsize, maxsize - totalsize,
707 cformat, IF_PIX_FMT(0,) store_part_bmp, &ba))
708 return totalsize;
709 else
710 return 0;
712 #endif /* LCD_DEPTH */
714 #if LCD_DEPTH > 1 || defined(PLUGIN)
715 struct scaler_context ctx = {
716 .bm = bm,
717 .dither = dither,
719 #endif
720 #if defined(PLUGIN) || defined(HAVE_JPEG) || defined(HAVE_BMP_SCALING)
721 #if LCD_DEPTH > 1
722 void (*output_row_8)(uint32_t, void*, struct scaler_context*) =
723 output_row_8_native;
724 #elif defined(PLUGIN)
725 void (*output_row_8)(uint32_t, void*, struct scaler_context*) = NULL;
726 #endif
727 #if LCD_DEPTH > 1 || defined(PLUGIN)
728 if (cformat)
729 output_row_8 = cformat->output_row_8;
730 #endif
731 #endif
733 int row;
734 /* loop to read rows and put them to buffer */
735 for (row = rset.rowstart; row != rset.rowstop; row += rset.rowstep) {
736 if (!read_part_line(&ba))
737 return -9;
738 #ifndef PLUGIN
739 #if !defined(HAVE_LCD_COLOR) && \
740 (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
741 uint8_t* qp = ba.buf;
742 #else
743 struct uint8_rgb *qp = (struct uint8_rgb *)ba.buf;
744 #endif
745 #endif
746 /* Convert to destination format */
747 #if ((LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) && \
748 !defined(PLUGIN)
749 if (format == FORMAT_NATIVE) {
750 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
751 if (remote) {
752 unsigned char dy = DITHERY(row);
753 #if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)
754 /* iAudio X5/M5 remote */
755 fb_remote_data *dest = (fb_remote_data *)bitmap
756 + bm->width * (row >> 3);
757 int shift = row & 7;
758 int delta = 127;
759 unsigned bright;
761 int col;
762 for (col = 0; col < bm->width; col++) {
763 if (dither)
764 delta = DITHERXDY(col,dy);
765 #if !defined(HAVE_LCD_COLOR) && \
766 (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
767 bright = *qp++;
768 #else
769 bright = brightness(*qp++);
770 #endif
771 bright = (3 * bright + (bright >> 6) + delta) >> 8;
772 *dest++ |= vi_pattern[bright] << shift;
774 #endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */
775 } else
776 #endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */
777 #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) &&
778 (LCD_REMOTE_DEPTH > 1) */
779 #if LCD_DEPTH > 1 || defined(PLUGIN)
781 #if !defined(PLUGIN) && !defined(HAVE_JPEG) && !defined(HAVE_BMP_SCALING)
782 output_row_8_native(row, ba.buf, &ctx);
783 #else
784 output_row_8(row, ba.buf, &ctx);
785 #endif
787 #endif
788 #if ((LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) && \
789 !defined(PLUGIN)
791 #ifndef PLUGIN
792 else
793 #endif
794 #endif
795 #ifndef PLUGIN
797 unsigned char *p = bitmap + bm->width * (row >> 3);
798 unsigned char mask = BIT_N(row & 7);
799 int col;
800 for (col = 0; col < bm->width; col++, p++)
801 #if !defined(HAVE_LCD_COLOR) && \
802 (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
803 if (*qp++ < 128)
804 *p |= mask;
805 #else
806 if (brightness(*qp++) < 128)
807 *p |= mask;
808 #endif
810 #endif
812 return totalsize; /* return the used buffer size. */