Bump version numbers for 3.13
[maemo-rb.git] / apps / recorder / bmp.c
blob011a4d60fef0bec6585c174a82f2a41d6d2b2d55
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;
176 dst->alpha = 0xff;
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
193 /* as read_part_line() goes through the rows it'll set this to true
194 * if it finds transparency. Initialize to 0 before calling */
195 int alpha_detected;
196 /* for checking transparency it checks the against the very first byte
197 * of the bitmap. Initalize to 0x80 before calling */
198 unsigned char first_alpha_byte;
201 static unsigned int read_part_line(struct bmp_args *ba)
203 const int padded_width = ba->padded_width;
204 const int read_width = ba->read_width;
205 const int width = ba->width;
206 const int depth = ba->depth;
207 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
208 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
209 int cur_row = ba->cur_row;
210 int cur_col = ba->cur_col;
211 #endif
212 const int fd = ba->fd;
213 uint8_t *ibuf;
214 struct uint8_rgb *buf = (struct uint8_rgb *)(ba->buf);
215 const struct uint8_rgb *palette = ba->palette;
216 uint32_t component, data;
217 int ret;
218 int i, cols, len;
220 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
221 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
222 cols = MIN(width - cur_col,(int)BM_MAX_WIDTH);
223 BDEBUGF("reading %d cols (width: %d, max: %d)\n",cols,width,BM_MAX_WIDTH);
224 len = (cols * (depth == 15 ? 16 : depth) + 7) >> 3;
225 #else
226 cols = width;
227 len = read_width;
228 #endif
229 ibuf = ((unsigned char *)buf) + (BM_MAX_WIDTH << 2) - len;
230 BDEBUGF("read_part_line: cols=%d len=%d\n",cols,len);
231 ret = read(fd, ibuf, len);
232 if (ret != len)
234 DEBUGF("read_part_line: error reading image, read returned %d "
235 "expected %d\n", ret, len);
236 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
237 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
238 BDEBUGF("cur_row: %d cur_col: %d cols: %d len: %d\n", cur_row, cur_col,
239 cols, len);
240 #endif
241 return 0;
244 /* detect if the image has useful alpha information.
245 * if all alpha bits are 0xff or 0x00 discard the information.
246 * if it has other bits, or is mixed with 0x00 and 0xff then interpret
247 * as alpha. assume no alpha until the opposite is proven. as mixed
248 * is alpha, compare to the first byte instead of 0xff and 0x00 separately
250 if (depth == 32 && ba->first_alpha_byte == 0x80)
251 ba->first_alpha_byte = ibuf[3] ? 0xff : 0x0;
253 while (ibuf < ba->buf + (BM_MAX_WIDTH << 2))
255 switch (depth)
257 case 1:
258 data = *ibuf++;
259 for (i = 0; i < 8; i++)
261 *buf++ = palette[data & 0x80 ? 1 : 0];
262 data <<= 1;
264 break;
265 case 4:
266 data = *ibuf++;
267 *buf++ = palette[data >> 4];
268 *buf++ = palette[data & 0xf];
269 break;
270 case 8:
271 *buf++ = palette[*ibuf++];
272 break;
273 case 15:
274 case 16:
275 data = letoh16(*(uint16_t*)ibuf);
276 component = (data << 3) & 0xf8;
277 component |= component >> 5;
278 buf->blue = component;
279 if (depth == 15)
281 data >>= 2;
282 component = data & 0xf8;
283 component |= component >> 5;
284 } else {
285 data >>= 3;
286 component = data & 0xfc;
287 component |= component >> 6;
289 buf->green = component;
290 data >>= 5;
291 component = data & 0xf8;
292 component |= component >> 5;
293 buf->red = component;
294 buf->alpha = 0xff;
295 buf++;
296 ibuf += 2;
297 break;
298 case 24:
299 buf->blue = *ibuf++;
300 buf->green = *ibuf++;
301 buf->red = *ibuf++;
302 buf->alpha = 0xff;
303 buf++;
304 break;
305 case 32:
306 buf->blue = *ibuf++;
307 buf->green = *ibuf++;
308 buf->red = *ibuf++;
309 buf->alpha = *ibuf++;
310 ba->alpha_detected |= (buf->alpha != ba->first_alpha_byte);
311 buf++;
312 break;
315 #if !defined(HAVE_LCD_COLOR) && \
316 ((LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \
317 defined(PLUGIN))
318 ibuf = ba->buf;
319 buf = (struct uint8_rgb*)ba->buf;
320 while (ibuf < ba->buf + cols)
321 *ibuf++ = brightness(*buf++);
322 #endif
324 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
325 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
326 cur_col += cols;
327 if (cur_col == width)
329 #endif
330 int pad = padded_width - read_width;
331 if (pad > 0)
333 BDEBUGF("seeking %d bytes to next line\n",pad);
334 lseek(fd, pad, SEEK_CUR);
336 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
337 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
338 cur_col = 0;
339 BDEBUGF("read_part_line: completed row %d\n", cur_row);
340 cur_row += 1;
343 ba->cur_row = cur_row;
344 ba->cur_col = cur_col;
345 #endif
346 return cols;
349 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
350 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
351 static struct img_part *store_part_bmp(void *args)
353 struct bmp_args *ba = (struct bmp_args *)args;
355 ba->part.len = read_part_line(ba);
356 #ifdef HAVE_LCD_COLOR
357 ba->part.buf = (struct uint8_rgb *)ba->buf;
358 #else
359 ba->part.buf = (uint8_t *)ba->buf;
360 #endif
361 if (ba->part.len)
362 return &(ba->part);
363 else
364 return NULL;
366 #endif
368 static inline int rgbcmp(struct uint8_rgb rgb1, struct uint8_rgb rgb2)
370 if ((rgb1.red == rgb2.red) && (rgb1.green == rgb2.green) &&
371 (rgb1.blue == rgb2.blue))
372 return 0;
373 else
374 return 1;
376 #if LCD_DEPTH > 1
377 #if !defined(PLUGIN) && !defined(HAVE_JPEG) && !defined(HAVE_BMP_SCALING)
378 static inline
379 #endif
380 void output_row_8_native(uint32_t row, void * row_in,
381 struct scaler_context *ctx)
383 int col;
384 int fb_width = BM_WIDTH(ctx->bm->width,FORMAT_NATIVE,0);
385 uint8_t dy = DITHERY(row);
386 #ifdef HAVE_LCD_COLOR
387 struct uint8_rgb *qp = (struct uint8_rgb*)row_in;
388 #else
389 uint8_t *qp = (uint8_t*)row_in;
390 #endif
391 BDEBUGF("output_row: y: %lu in: %p\n",row, row_in);
392 #if LCD_DEPTH == 2
393 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
394 /* greyscale iPods */
395 fb_data *dest = (fb_data *)ctx->bm->data + fb_width * row;
396 int shift = 6;
397 int delta = 127;
398 unsigned bright;
399 unsigned data = 0;
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 data |= (~bright & 3) << shift;
407 shift -= 2;
408 if (shift < 0) {
409 *dest++ = data;
410 data = 0;
411 shift = 6;
414 if (shift < 6)
415 *dest++ = data;
416 #elif LCD_PIXELFORMAT == VERTICAL_PACKING
417 /* iriver H1x0 */
418 fb_data *dest = (fb_data *)ctx->bm->data + fb_width *
419 (row >> 2);
420 int shift = 2 * (row & 3);
421 int delta = 127;
422 unsigned bright;
424 for (col = 0; col < ctx->bm->width; col++) {
425 if (ctx->dither)
426 delta = DITHERXDY(col,dy);
427 bright = *qp++;
428 bright = (3 * bright + (bright >> 6) + delta) >> 8;
429 *dest++ |= (~bright & 3) << shift;
431 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
432 /* iAudio M3 */
433 fb_data *dest = (fb_data *)ctx->bm->data + fb_width *
434 (row >> 3);
435 int shift = row & 7;
436 int delta = 127;
437 unsigned bright;
439 for (col = 0; col < ctx->bm->width; col++) {
440 if (ctx->dither)
441 delta = DITHERXDY(col,dy);
442 bright = *qp++;
443 bright = (3 * bright + (bright >> 6) + delta) >> 8;
444 *dest++ |= vi_pattern[bright] << shift;
446 #endif /* LCD_PIXELFORMAT */
447 #elif LCD_DEPTH == 16
448 /* iriver h300, colour iPods, X5 */
449 (void)fb_width;
450 fb_data *dest = STRIDE_MAIN((fb_data *)ctx->bm->data + fb_width * row,
451 (fb_data *)ctx->bm->data + row);
452 int delta = 127;
453 unsigned r, g, b;
454 /* setup alpha channel buffer */
455 unsigned char *bm_alpha = NULL;
456 if (ctx->bm->alpha_offset > 0)
457 bm_alpha = ctx->bm->data + ctx->bm->alpha_offset;
458 if (bm_alpha)
459 bm_alpha += ALIGN_UP(ctx->bm->width, 2) * row/2;
461 for (col = 0; col < ctx->bm->width; col++) {
462 if (ctx->dither)
463 delta = DITHERXDY(col,dy);
464 r = qp->red;
465 g = qp->green;
466 b = qp->blue;
467 r = (31 * r + (r >> 3) + delta) >> 8;
468 g = (63 * g + (g >> 2) + delta) >> 8;
469 b = (31 * b + (b >> 3) + delta) >> 8;
470 *dest = LCD_RGBPACK_LCD(r, g, b);
471 dest += STRIDE_MAIN(1, ctx->bm->height);
472 if (bm_alpha) {
473 /* pack alpha channel for 2 pixels into 1 byte and negate
474 * according to the interal alpha channel format */
475 uint8_t alpha = ~qp->alpha;
476 if (col%2)
477 *bm_alpha++ |= alpha&0xf0;
478 else
479 *bm_alpha = alpha>>4;
481 qp++;
483 #endif /* LCD_DEPTH */
485 #endif
487 /******************************************************************************
488 * read_bmp_fd()
490 * Reads a BMP file in an open file descriptor and puts the data in rockbox
491 * format in *bitmap.
493 *****************************************************************************/
494 int read_bmp_fd(int fd,
495 struct bitmap *bm,
496 int maxsize,
497 int format,
498 const struct custom_format *cformat)
500 struct bmp_header bmph;
501 int padded_width;
502 int read_width;
503 int depth, numcolors, compression, totalsize;
504 int ret;
505 bool return_size = format & FORMAT_RETURN_SIZE;
506 bool read_alpha = format & FORMAT_TRANSPARENT;
508 unsigned char *bitmap = bm->data;
509 struct uint8_rgb palette[256];
510 struct rowset rset;
511 struct dim src_dim;
512 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \
513 defined(PLUGIN)
514 bool dither = false;
515 #endif
517 #ifdef HAVE_REMOTE_LCD
518 bool remote = false;
519 if (format & FORMAT_REMOTE) {
520 remote = true;
521 #if LCD_REMOTE_DEPTH == 1
522 format = FORMAT_MONO;
523 #endif
525 #endif /* HAVE_REMOTE_LCD */
527 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
528 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
529 unsigned int resize = IMG_NORESIZE;
531 if (format & FORMAT_RESIZE) {
532 resize = IMG_RESIZE;
535 #else
537 (void)format;
538 #endif /*(LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)*/
539 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \
540 defined(PLUGIN)
541 if (format & FORMAT_DITHER) {
542 dither = true;
544 #endif
545 /* read fileheader */
546 ret = read(fd, &bmph, sizeof(struct bmp_header));
547 if (ret < 0) {
548 return ret * 10 - 2;
551 if (ret != sizeof(struct bmp_header)) {
552 DEBUGF("read_bmp_fd: can't read BMP header.");
553 return -3;
556 src_dim.width = letoh32(bmph.width);
557 src_dim.height = letoh32(bmph.height);
558 if (src_dim.height < 0) { /* Top-down BMP file */
559 src_dim.height = -src_dim.height;
560 rset.rowstep = 1;
561 } else { /* normal BMP */
562 rset.rowstep = -1;
565 depth = letoh16(bmph.bit_count);
566 /* 4-byte boundary aligned */
567 read_width = ((src_dim.width * (depth == 15 ? 16 : depth) + 7) >> 3);
568 padded_width = (read_width + 3) & ~3;
570 BDEBUGF("width: %d height: %d depth: %d padded_width: %d\n", src_dim.width,
571 src_dim.height, depth, padded_width);
573 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
574 if ((format & 3) == FORMAT_ANY) {
575 if (depth == 1)
576 format = (format & ~3);
577 else
578 format = (format & ~3) | FORMAT_NATIVE;
580 bm->format = format & 1;
581 if ((format & 1) == FORMAT_MONO)
583 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
584 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
585 resize &= ~IMG_RESIZE;
586 resize |= IMG_NORESIZE;
587 #endif
588 #ifdef HAVE_REMOTE_LCD
589 remote = false;
590 #endif
592 #elif !defined(PLUGIN)
593 if (src_dim.width > BM_MAX_WIDTH)
594 return -6;
595 #endif /*(LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)*/
597 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
598 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
599 if (resize & IMG_RESIZE) {
600 if(format & FORMAT_KEEP_ASPECT) {
601 /* keep aspect ratio.. */
602 struct dim resize_dim = {
603 .width = bm->width,
604 .height = bm->height,
606 if (recalc_dimension(&resize_dim, &src_dim))
607 resize = IMG_NORESIZE;
608 bm->width = resize_dim.width;
609 bm->height = resize_dim.height;
613 if (!(resize & IMG_RESIZE)) {
614 #endif
615 /* returning image size */
616 bm->width = src_dim.width;
617 bm->height = src_dim.height;
619 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
620 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
622 #endif
623 #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
624 format &= 1;
625 #endif
626 if (rset.rowstep > 0) { /* Top-down BMP file */
627 rset.rowstart = 0;
628 rset.rowstop = bm->height;
629 } else { /* normal BMP */
630 rset.rowstart = bm->height - 1;
631 rset.rowstop = -1;
634 /* need even rows (see lcd-16bit-common.c for details) */
635 int alphasize = ALIGN_UP(bm->width, 2) * bm->height / 2;
636 if (cformat)
637 totalsize = cformat->get_size(bm);
638 else {
639 totalsize = BM_SIZE(bm->width,bm->height,format,remote);
640 #ifdef HAVE_REMOTE_LCD
641 if (!remote)
642 #endif
643 if (depth == 32 && read_alpha) /* account for possible 4bit alpha per pixel */
644 totalsize += alphasize;
647 if(return_size)
649 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
650 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
651 if(resize)
652 totalsize += BM_SCALED_SIZE(bm->width, 0, 0, 0);
653 else if (bm->width > BM_MAX_WIDTH)
654 totalsize += bm->width*4;
655 #endif
656 return totalsize;
659 /* Check if this fits the buffer */
660 if (totalsize > maxsize) {
661 DEBUGF("read_bmp_fd: Bitmap too large for buffer: "
662 "%d bytes.\n", totalsize);
663 return -6;
666 compression = letoh32(bmph.compression);
667 if (depth <= 8) {
668 numcolors = letoh32(bmph.clr_used);
669 if (numcolors == 0)
670 numcolors = BIT_N(depth);
671 } else
672 numcolors = (compression == 3) ? 3 : 0;
674 if (numcolors > 0 && numcolors <= 256) {
675 int i;
676 union rgb_union pal;
677 for (i = 0; i < numcolors; i++) {
678 if (read(fd, &pal, sizeof(pal)) != (int)sizeof(pal))
680 DEBUGF("read_bmp_fd: Can't read color palette\n");
681 return -7;
683 set_rgb_union(&palette[i], pal);
687 switch (depth) {
688 case 16:
689 #if LCD_DEPTH >= 16
690 /* don't dither 16 bit BMP to LCD with same or larger depth */
691 #ifdef HAVE_REMOTE_LCD
692 if (!remote)
693 #endif
694 dither = false;
695 #endif
696 if (compression == 0) { /* BI_RGB, i.e. 15 bit */
697 depth = 15;
698 break;
699 } /* else fall through */
701 case 32:
702 if (compression == 3) { /* BI_BITFIELDS */
703 bool found;
704 int i, j;
706 /* (i == 0) is 15bit, (i == 1) is 16bit, (i == 2) is 32bit */
707 for (i = 0; i < ARRAY_SIZE(bitfields); i++) {
708 for (j = 0; j < ARRAY_SIZE(bitfields[0]); j++) {
709 if (!rgbcmp(palette[j], bitfields[i][j])) {
710 found = true;
711 } else {
712 found = false;
713 break;
716 if (found) {
717 if (i == 0) /* 15bit */
718 depth = 15;
719 break;
722 if (found)
723 break;
724 } /* else fall through */
726 default:
727 if (compression != 0) { /* not BI_RGB */
728 DEBUGF("read_bmp_fd: Unsupported compression (type %d)\n",
729 compression);
730 return -8;
732 break;
735 /* Search to the beginning of the image data */
736 lseek(fd, (off_t)letoh32(bmph.off_bits), SEEK_SET);
738 memset(bitmap, 0, totalsize);
740 #ifdef HAVE_LCD_COLOR
741 if (read_alpha && depth == 32)
742 bm->alpha_offset = totalsize - alphasize;
743 else
744 bm->alpha_offset = 0;
745 #endif
747 struct bmp_args ba = {
748 .fd = fd, .padded_width = padded_width, .read_width = read_width,
749 .width = src_dim.width, .depth = depth, .palette = palette,
750 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
751 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
752 .cur_row = 0, .cur_col = 0, .part = {0,0},
753 #endif
754 .alpha_detected = false, .first_alpha_byte = 0x80,
757 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
758 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
759 if (resize)
761 if (resize_on_load(bm, dither, &src_dim, &rset,
762 bitmap + totalsize, maxsize - totalsize,
763 cformat, IF_PIX_FMT(0,) store_part_bmp, &ba))
764 return totalsize;
765 else
766 return 0;
768 #endif /* LCD_DEPTH */
770 #if LCD_DEPTH > 1 || defined(PLUGIN)
771 struct scaler_context ctx = {
772 .bm = bm,
773 .dither = dither,
775 #endif
776 #if defined(PLUGIN) || defined(HAVE_JPEG) || defined(HAVE_BMP_SCALING)
777 #if LCD_DEPTH > 1
778 void (*output_row_8)(uint32_t, void*, struct scaler_context*) =
779 output_row_8_native;
780 #elif defined(PLUGIN)
781 void (*output_row_8)(uint32_t, void*, struct scaler_context*) = NULL;
782 #endif
783 #if LCD_DEPTH > 1 || defined(PLUGIN)
784 if (cformat)
785 output_row_8 = cformat->output_row_8;
786 #endif
787 #endif
789 unsigned char *buf = ba.buf;
790 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \
791 defined(PLUGIN)
792 if (bm->width > BM_MAX_WIDTH)
794 #if defined(HAVE_BMP_SCALING) || defined(PLUGIN)
795 unsigned int len = maxsize - totalsize;
796 buf = bitmap + totalsize;
797 ALIGN_BUFFER(buf, len, sizeof(uint32_t));
798 if (bm->width*4 > (int)len)
799 #endif
800 return -6;
802 #endif
803 int row;
804 /* loop to read rows and put them to buffer */
805 for (row = rset.rowstart; row != rset.rowstop; row += rset.rowstep) {
806 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
807 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
808 if (bm->width > BM_MAX_WIDTH)
810 #if defined(HAVE_LCD_COLOR)
811 struct uint8_rgb *p = (struct uint8_rgb *)buf;
812 #else
813 uint8_t* p = buf;
814 #endif
815 do {
816 int len = read_part_line(&ba);
817 if (!len)
818 return -9;
819 memcpy(p, ba.buf, len*sizeof(*p));
820 p += len;
821 } while (ba.cur_col);
823 else
824 #endif
825 if (!read_part_line(&ba))
826 return -9;
827 #ifndef PLUGIN
828 #if !defined(HAVE_LCD_COLOR) && \
829 (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
830 uint8_t* qp = buf;
831 #else
832 struct uint8_rgb *qp = (struct uint8_rgb *)buf;
833 #endif
834 #endif
835 /* Convert to destination format */
836 #if ((LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) && \
837 !defined(PLUGIN)
838 if (format == FORMAT_NATIVE) {
839 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
840 if (remote) {
841 unsigned char dy = DITHERY(row);
842 #if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)
843 /* iAudio X5/M5 remote */
844 fb_remote_data *dest = (fb_remote_data *)bitmap
845 + bm->width * (row >> 3);
846 int shift = row & 7;
847 int delta = 127;
848 unsigned bright;
850 int col;
851 for (col = 0; col < bm->width; col++) {
852 if (dither)
853 delta = DITHERXDY(col,dy);
854 #if !defined(HAVE_LCD_COLOR) && \
855 (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
856 bright = *qp++;
857 #else
858 bright = brightness(*qp++);
859 #endif
860 bright = (3 * bright + (bright >> 6) + delta) >> 8;
861 *dest++ |= vi_pattern[bright] << shift;
863 #endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */
864 } else
865 #endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */
866 #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) &&
867 (LCD_REMOTE_DEPTH > 1) */
868 #if LCD_DEPTH > 1 || defined(PLUGIN)
870 #if !defined(PLUGIN) && !defined(HAVE_JPEG) && !defined(HAVE_BMP_SCALING)
871 output_row_8_native(row, buf, &ctx);
872 #else
873 output_row_8(row, buf, &ctx);
874 #endif
876 #endif
877 #if ((LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) && \
878 !defined(PLUGIN)
880 #ifndef PLUGIN
881 else
882 #endif
883 #endif
884 #ifndef PLUGIN
886 unsigned char *p = bitmap + bm->width * (row >> 3);
887 unsigned char mask = BIT_N(row & 7);
888 int col;
889 for (col = 0; col < bm->width; col++, p++)
890 #if !defined(HAVE_LCD_COLOR) && \
891 (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
892 if (*qp++ < 128)
893 *p |= mask;
894 #else
895 if (brightness(*qp++) < 128)
896 *p |= mask;
897 #endif
899 #endif
901 #ifdef HAVE_LCD_COLOR
902 if (!ba.alpha_detected)
903 { /* if this has an alpha channel, totalsize accounts for it as well
904 * subtract if no actual alpha information was found */
905 if (bm->alpha_offset > 0)
906 totalsize -= alphasize;
907 bm->alpha_offset = 0;
909 #endif
910 return totalsize; /* return the used buffer size. */