Fix FS#10197 by setting the viewport before calculating the string size.
[kugel-rb.git] / apps / recorder / bmp.c
blobeef425fb25d7beb9c447094cefca443b81bdf0c1
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;
464 unsigned char *bitmap = bm->data;
465 struct uint8_rgb palette[256];
466 struct rowset rset;
467 struct dim src_dim;
468 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \
469 defined(PLUGIN)
470 bool dither = false;
471 #endif
472 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
473 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
474 unsigned int resize = IMG_NORESIZE;
475 bool transparent = false;
477 #ifdef HAVE_REMOTE_LCD
478 bool remote = false;
479 if (format & FORMAT_REMOTE) {
480 remote = true;
481 #if LCD_REMOTE_DEPTH == 1
482 format = FORMAT_MONO;
483 #endif
485 #endif /* HAVE_REMOTE_LCD */
487 if (format & FORMAT_RESIZE) {
488 resize = IMG_RESIZE;
491 if (format & FORMAT_TRANSPARENT) {
492 transparent = true;
494 #else
496 (void)format;
497 #endif /*(LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)*/
498 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \
499 defined(PLUGIN)
500 if (format & FORMAT_DITHER) {
501 dither = true;
503 #endif
504 /* read fileheader */
505 ret = read(fd, &bmph, sizeof(struct bmp_header));
506 if (ret < 0) {
507 return ret * 10 - 2;
510 if (ret != sizeof(struct bmp_header)) {
511 DEBUGF("read_bmp_fd: can't read BMP header.");
512 return -3;
515 src_dim.width = letoh32(bmph.width);
516 src_dim.height = letoh32(bmph.height);
517 if (src_dim.height < 0) { /* Top-down BMP file */
518 src_dim.height = -src_dim.height;
519 rset.rowstep = 1;
520 } else { /* normal BMP */
521 rset.rowstep = -1;
524 depth = letoh16(bmph.bit_count);
525 /* 4-byte boundary aligned */
526 read_width = ((src_dim.width * (depth == 15 ? 16 : depth) + 7) >> 3);
527 padded_width = (read_width + 3) & ~3;
529 BDEBUGF("width: %d height: %d depth: %d padded_width: %d\n", src_dim.width,
530 src_dim.height, depth, padded_width);
532 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
533 if ((format & 3) == FORMAT_ANY) {
534 if (depth == 1)
535 format = (format & ~3);
536 else
537 format = (format & ~3) | FORMAT_NATIVE;
539 bm->format = format & 1;
540 if ((format & 1) == FORMAT_MONO)
542 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
543 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
544 resize &= ~IMG_RESIZE;
545 resize |= IMG_NORESIZE;
546 #endif
547 #ifdef HAVE_REMOTE_LCD
548 remote = 0;
549 #endif
551 #elif !defined(PLUGIN)
552 if (src_dim.width > BM_MAX_WIDTH)
553 return -6;
554 #endif /*(LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)*/
556 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
557 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
558 if (resize & IMG_RESIZE) {
559 if(format & FORMAT_KEEP_ASPECT) {
560 /* keep aspect ratio.. */
561 struct dim resize_dim = {
562 .width = bm->width,
563 .height = bm->height,
565 if (recalc_dimension(&resize_dim, &src_dim))
566 resize = IMG_NORESIZE;
567 bm->width = resize_dim.width;
568 bm->height = resize_dim.height;
572 if (!(resize & IMG_RESIZE)) {
573 #endif
574 /* returning image size */
575 bm->width = src_dim.width;
576 bm->height = src_dim.height;
578 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
579 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
581 #endif
582 #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
583 format &= 1;
584 #endif
585 if (rset.rowstep > 0) { /* Top-down BMP file */
586 rset.rowstart = 0;
587 rset.rowstop = bm->height;
588 } else { /* normal BMP */
589 rset.rowstart = bm->height - 1;
590 rset.rowstop = -1;
593 if (cformat)
594 totalsize = cformat->get_size(bm);
595 else
596 totalsize = BM_SIZE(bm->width,bm->height,format,remote);
598 /* Check if this fits the buffer */
599 if (totalsize > maxsize) {
600 DEBUGF("read_bmp_fd: Bitmap too large for buffer: "
601 "%d bytes.\n", totalsize);
602 return -6;
605 compression = letoh32(bmph.compression);
606 if (depth <= 8) {
607 numcolors = letoh32(bmph.clr_used);
608 if (numcolors == 0)
609 numcolors = 1 << depth;
610 } else
611 numcolors = (compression == 3) ? 3 : 0;
613 if (numcolors > 0 && numcolors <= 256) {
614 int i;
615 union rgb_union pal;
616 for (i = 0; i < numcolors; i++) {
617 if (read(fd, &pal, sizeof(pal)) != (int)sizeof(pal))
619 DEBUGF("read_bmp_fd: Can't read color palette\n");
620 return -7;
622 set_rgb_union(&palette[i], pal);
626 switch (depth) {
627 case 16:
628 #if LCD_DEPTH >= 16
629 /* don't dither 16 bit BMP to LCD with same or larger depth */
630 #ifdef HAVE_REMOTE_LCD
631 if (!remote)
632 #endif
633 dither = false;
634 #endif
635 if (compression == 0) { /* BI_RGB, i.e. 15 bit */
636 depth = 15;
637 break;
638 } /* else fall through */
640 case 32:
641 if (compression == 3) { /* BI_BITFIELDS */
642 bool found;
643 int i, j;
645 /* (i == 0) is 15bit, (i == 1) is 16bit, (i == 2) is 32bit */
646 for (i = 0; i < ARRAY_SIZE(bitfields); i++) {
647 for (j = 0; j < ARRAY_SIZE(bitfields[0]); j++) {
648 if (!rgbcmp(palette[j], bitfields[i][j])) {
649 found = true;
650 } else {
651 found = false;
652 break;
655 if (found) {
656 if (i == 0) /* 15bit */
657 depth = 15;
658 break;
661 if (found)
662 break;
663 } /* else fall through */
665 default:
666 if (compression != 0) { /* not BI_RGB */
667 DEBUGF("read_bmp_fd: Unsupported compression (type %d)\n",
668 compression);
669 return -8;
671 break;
674 /* Search to the beginning of the image data */
675 lseek(fd, (off_t)letoh32(bmph.off_bits), SEEK_SET);
677 memset(bitmap, 0, totalsize);
679 struct bmp_args ba = {
680 .fd = fd, .padded_width = padded_width, .read_width = read_width,
681 .width = src_dim.width, .depth = depth, .palette = palette,
682 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
683 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
684 .cur_row = 0, .cur_col = 0, .part = {0,0}
685 #endif
688 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
689 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
690 #if LCD_DEPTH > 1 && defined(HAVE_BMP_SCALING)
691 if (resize)
692 #endif
694 if (resize_on_load(bm, dither, &src_dim, &rset,
695 bitmap + totalsize, maxsize - totalsize,
696 cformat, IF_PIX_FMT(0,) store_part_bmp, &ba))
697 return totalsize;
698 else
699 return 0;
701 #endif /* LCD_DEPTH */
703 #if LCD_DEPTH > 1 || defined(PLUGIN)
704 struct scaler_context ctx = {
705 .bm = bm,
706 .dither = dither,
708 #endif
709 #if defined(PLUGIN) || defined(HAVE_JPEG) || defined(HAVE_BMP_SCALING)
710 #if LCD_DEPTH > 1
711 void (*output_row_8)(uint32_t, void*, struct scaler_context*) =
712 output_row_8_native;
713 #elif defined(PLUGIN)
714 void (*output_row_8)(uint32_t, void*, struct scaler_context*) = NULL;
715 #endif
716 #if LCD_DEPTH > 1 || defined(PLUGIN)
717 if (cformat)
718 output_row_8 = cformat->output_row_8;
719 #endif
720 #endif
722 int row;
723 /* loop to read rows and put them to buffer */
724 for (row = rset.rowstart; row != rset.rowstop; row += rset.rowstep) {
725 if (!read_part_line(&ba))
726 return -9;
727 #ifndef PLUGIN
728 #if !defined(HAVE_LCD_COLOR) && \
729 (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
730 uint8_t* qp = ba.buf;
731 #else
732 struct uint8_rgb *qp = (struct uint8_rgb *)ba.buf;
733 #endif
734 #endif
735 /* Convert to destination format */
736 #if ((LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) && \
737 !defined(PLUGIN)
738 if (format == FORMAT_NATIVE) {
739 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
740 if (remote) {
741 unsigned char dy = DITHERY(row);
742 #if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)
743 /* iAudio X5/M5 remote */
744 fb_remote_data *dest = (fb_remote_data *)bitmap
745 + bm->width * (row >> 3);
746 int shift = row & 7;
747 int delta = 127;
748 unsigned bright;
750 int col;
751 for (col = 0; col < bm->width; col++) {
752 if (dither)
753 delta = DITHERXDY(col,dy);
754 #if !defined(HAVE_LCD_COLOR) && \
755 (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
756 bright = *qp++;
757 #else
758 bright = brightness(*qp++);
759 #endif
760 bright = (3 * bright + (bright >> 6) + delta) >> 8;
761 *dest++ |= vi_pattern[bright] << shift;
763 #endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */
764 } else
765 #endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */
766 #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) &&
767 (LCD_REMOTE_DEPTH > 1) */
768 #if LCD_DEPTH > 1 || defined(PLUGIN)
770 #if !defined(PLUGIN) && !defined(HAVE_JPEG) && !defined(HAVE_BMP_SCALING)
771 output_row_8_native(row, ba.buf, &ctx);
772 #else
773 output_row_8(row, ba.buf, &ctx);
774 #endif
776 #endif
777 #if ((LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) && \
778 !defined(PLUGIN)
780 #ifndef PLUGIN
781 else
782 #endif
783 #endif
784 #ifndef PLUGIN
786 unsigned char *p = bitmap + bm->width * (row >> 3);
787 unsigned char mask = 1 << (row & 7);
788 int col;
789 for (col = 0; col < bm->width; col++, p++)
790 #if !defined(HAVE_LCD_COLOR) && \
791 (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
792 if (*qp++ < 128)
793 *p |= mask;
794 #else
795 if (brightness(*qp++) < 128)
796 *p |= mask;
797 #endif
799 #endif
801 return totalsize; /* return the used buffer size. */