1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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
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
52 #ifdef HAVE_REMOTE_LCD
53 #include "lcd-remote.h"
55 #ifdef ROCKBOX_DEBUG_BMP_LOADER
56 #define BDEBUGF DEBUGF
69 #define STRUCT_PACKED __attribute__((packed))
72 #pragma pack (push, 2)
75 /* BMP header structure */
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 */
96 struct { /* Little endian */
100 unsigned char reserved
;
105 /* masks for supported BI_BITFIELDS encodings (16/32 bit) */
106 static const struct uint8_rgb bitfields
[3][3] = {
109 { .blue
= 0x00, .green
= 0x7c, .red
= 0x00 },
110 { .blue
= 0xe0, .green
= 0x03, .red
= 0x00 },
111 { .blue
= 0x1f, .green
= 0x00, .red
= 0x00 },
115 { .blue
= 0x00, .green
= 0xf8, .red
= 0x00 },
116 { .blue
= 0xe0, .green
= 0x07, .red
= 0x00 },
117 { .blue
= 0x1f, .green
= 0x00, .red
= 0x00 },
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 };
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
142 /******************************************************************************
145 * Reads a BMP file and puts the data in rockbox format in *bitmap.
147 *****************************************************************************/
148 int read_bmp_file(const char* filename
,
152 const struct custom_format
*cformat
)
155 fd
= open(filename
, O_RDONLY
);
157 /* Exit if file opening failed */
159 DEBUGF("read_bmp_file: can't open '%s', rc: %d\n", filename
, fd
);
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
);
171 static inline void set_rgb_union(struct uint8_rgb
*dst
, union rgb_union src
)
174 dst
->green
= src
.green
;
175 dst
->blue
= src
.blue
;
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)
191 struct img_part part
;
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 */
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
;
212 const int fd
= ba
->fd
;
214 struct uint8_rgb
*buf
= (struct uint8_rgb
*)(ba
->buf
);
215 const struct uint8_rgb
*palette
= ba
->palette
;
216 uint32_t component
, data
;
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;
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
);
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
,
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))
259 for (i
= 0; i
< 8; i
++)
261 *buf
++ = palette
[data
& 0x80 ? 1 : 0];
267 *buf
++ = palette
[data
>> 4];
268 *buf
++ = palette
[data
& 0xf];
271 *buf
++ = palette
[*ibuf
++];
275 data
= letoh16(*(uint16_t*)ibuf
);
276 component
= (data
<< 3) & 0xf8;
277 component
|= component
>> 5;
278 buf
->blue
= component
;
282 component
= data
& 0xf8;
283 component
|= component
>> 5;
286 component
= data
& 0xfc;
287 component
|= component
>> 6;
289 buf
->green
= component
;
291 component
= data
& 0xf8;
292 component
|= component
>> 5;
293 buf
->red
= component
;
300 buf
->green
= *ibuf
++;
307 buf
->green
= *ibuf
++;
309 buf
->alpha
= *ibuf
++;
310 ba
->alpha_detected
|= (buf
->alpha
!= ba
->first_alpha_byte
);
315 #if !defined(HAVE_LCD_COLOR) && \
316 ((LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \
319 buf
= (struct uint8_rgb
*)ba
->buf
;
320 while (ibuf
< ba
->buf
+ cols
)
321 *ibuf
++ = brightness(*buf
++);
324 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
325 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
327 if (cur_col
== width
)
330 int pad
= padded_width
- read_width
;
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)
339 BDEBUGF("read_part_line: completed row %d\n", cur_row
);
343 ba
->cur_row
= cur_row
;
344 ba
->cur_col
= cur_col
;
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
;
359 ba
->part
.buf
= (uint8_t *)ba
->buf
;
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
))
377 #if !defined(PLUGIN) && !defined(HAVE_JPEG) && !defined(HAVE_BMP_SCALING)
380 void output_row_8_native(uint32_t row
, void * row_in
,
381 struct scaler_context
*ctx
)
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
;
389 uint8_t *qp
= (uint8_t*)row_in
;
391 BDEBUGF("output_row: y: %lu in: %p\n",row
, row_in
);
393 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
394 /* greyscale iPods */
395 fb_data
*dest
= (fb_data
*)ctx
->bm
->data
+ fb_width
* row
;
401 for (col
= 0; col
< ctx
->bm
->width
; col
++) {
403 delta
= DITHERXDY(col
,dy
);
405 bright
= (3 * bright
+ (bright
>> 6) + delta
) >> 8;
406 data
|= (~bright
& 3) << shift
;
416 #elif LCD_PIXELFORMAT == VERTICAL_PACKING
418 fb_data
*dest
= (fb_data
*)ctx
->bm
->data
+ fb_width
*
420 int shift
= 2 * (row
& 3);
424 for (col
= 0; col
< ctx
->bm
->width
; col
++) {
426 delta
= DITHERXDY(col
,dy
);
428 bright
= (3 * bright
+ (bright
>> 6) + delta
) >> 8;
429 *dest
++ |= (~bright
& 3) << shift
;
431 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
433 fb_data
*dest
= (fb_data
*)ctx
->bm
->data
+ fb_width
*
439 for (col
= 0; col
< ctx
->bm
->width
; col
++) {
441 delta
= DITHERXDY(col
,dy
);
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 */
450 fb_data
*dest
= STRIDE_MAIN((fb_data
*)ctx
->bm
->data
+ fb_width
* row
,
451 (fb_data
*)ctx
->bm
->data
+ row
);
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
;
459 bm_alpha
+= ALIGN_UP(ctx
->bm
->width
, 2) * row
/2;
461 for (col
= 0; col
< ctx
->bm
->width
; col
++) {
463 delta
= DITHERXDY(col
,dy
);
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
);
473 /* pack alpha channel for 2 pixels into 1 byte */
474 unsigned alpha
= qp
->alpha
;
476 *bm_alpha
++ |= alpha
&0xf0;
478 *bm_alpha
= alpha
>>4;
482 #endif /* LCD_DEPTH */
486 /******************************************************************************
489 * Reads a BMP file in an open file descriptor and puts the data in rockbox
492 *****************************************************************************/
493 int read_bmp_fd(int fd
,
497 const struct custom_format
*cformat
)
499 struct bmp_header bmph
;
502 int depth
, numcolors
, compression
, totalsize
;
504 bool return_size
= format
& FORMAT_RETURN_SIZE
;
505 bool read_alpha
= format
& FORMAT_TRANSPARENT
;
507 unsigned char *bitmap
= bm
->data
;
508 struct uint8_rgb palette
[256];
511 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \
516 #ifdef HAVE_REMOTE_LCD
518 if (format
& FORMAT_REMOTE
) {
520 #if LCD_REMOTE_DEPTH == 1
521 format
= FORMAT_MONO
;
524 #endif /* HAVE_REMOTE_LCD */
526 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
527 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
528 unsigned int resize
= IMG_NORESIZE
;
530 if (format
& FORMAT_RESIZE
) {
537 #endif /*(LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)*/
538 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \
540 if (format
& FORMAT_DITHER
) {
544 /* read fileheader */
545 ret
= read(fd
, &bmph
, sizeof(struct bmp_header
));
550 if (ret
!= sizeof(struct bmp_header
)) {
551 DEBUGF("read_bmp_fd: can't read BMP header.");
555 src_dim
.width
= letoh32(bmph
.width
);
556 src_dim
.height
= letoh32(bmph
.height
);
557 if (src_dim
.height
< 0) { /* Top-down BMP file */
558 src_dim
.height
= -src_dim
.height
;
560 } else { /* normal BMP */
564 depth
= letoh16(bmph
.bit_count
);
565 /* 4-byte boundary aligned */
566 read_width
= ((src_dim
.width
* (depth
== 15 ? 16 : depth
) + 7) >> 3);
567 padded_width
= (read_width
+ 3) & ~3;
569 BDEBUGF("width: %d height: %d depth: %d padded_width: %d\n", src_dim
.width
,
570 src_dim
.height
, depth
, padded_width
);
572 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
573 if ((format
& 3) == FORMAT_ANY
) {
575 format
= (format
& ~3);
577 format
= (format
& ~3) | FORMAT_NATIVE
;
579 bm
->format
= format
& 1;
580 if ((format
& 1) == FORMAT_MONO
)
582 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
583 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
584 resize
&= ~IMG_RESIZE
;
585 resize
|= IMG_NORESIZE
;
587 #ifdef HAVE_REMOTE_LCD
591 #elif !defined(PLUGIN)
592 if (src_dim
.width
> BM_MAX_WIDTH
)
594 #endif /*(LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)*/
596 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
597 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
598 if (resize
& IMG_RESIZE
) {
599 if(format
& FORMAT_KEEP_ASPECT
) {
600 /* keep aspect ratio.. */
601 struct dim resize_dim
= {
603 .height
= bm
->height
,
605 if (recalc_dimension(&resize_dim
, &src_dim
))
606 resize
= IMG_NORESIZE
;
607 bm
->width
= resize_dim
.width
;
608 bm
->height
= resize_dim
.height
;
612 if (!(resize
& IMG_RESIZE
)) {
614 /* returning image size */
615 bm
->width
= src_dim
.width
;
616 bm
->height
= src_dim
.height
;
618 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
619 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
622 #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
625 if (rset
.rowstep
> 0) { /* Top-down BMP file */
627 rset
.rowstop
= bm
->height
;
628 } else { /* normal BMP */
629 rset
.rowstart
= bm
->height
- 1;
633 /* need even rows (see lcd-16bit-common.c for details) */
634 int alphasize
= ALIGN_UP(bm
->width
, 2) * bm
->height
/ 2;
636 totalsize
= cformat
->get_size(bm
);
638 totalsize
= BM_SIZE(bm
->width
,bm
->height
,format
,remote
);
639 #ifdef HAVE_REMOTE_LCD
642 if (depth
== 32 && read_alpha
) /* account for possible 4bit alpha per pixel */
643 totalsize
+= alphasize
;
648 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
649 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
651 totalsize
+= BM_SCALED_SIZE(bm
->width
, 0, 0, 0);
652 else if (bm
->width
> BM_MAX_WIDTH
)
653 totalsize
+= bm
->width
*4;
658 /* Check if this fits the buffer */
659 if (totalsize
> maxsize
) {
660 DEBUGF("read_bmp_fd: Bitmap too large for buffer: "
661 "%d bytes.\n", totalsize
);
665 compression
= letoh32(bmph
.compression
);
667 numcolors
= letoh32(bmph
.clr_used
);
669 numcolors
= BIT_N(depth
);
671 numcolors
= (compression
== 3) ? 3 : 0;
673 if (numcolors
> 0 && numcolors
<= 256) {
676 for (i
= 0; i
< numcolors
; i
++) {
677 if (read(fd
, &pal
, sizeof(pal
)) != (int)sizeof(pal
))
679 DEBUGF("read_bmp_fd: Can't read color palette\n");
682 set_rgb_union(&palette
[i
], pal
);
689 /* don't dither 16 bit BMP to LCD with same or larger depth */
690 #ifdef HAVE_REMOTE_LCD
695 if (compression
== 0) { /* BI_RGB, i.e. 15 bit */
698 } /* else fall through */
701 if (compression
== 3) { /* BI_BITFIELDS */
705 /* (i == 0) is 15bit, (i == 1) is 16bit, (i == 2) is 32bit */
706 for (i
= 0; i
< ARRAY_SIZE(bitfields
); i
++) {
707 for (j
= 0; j
< ARRAY_SIZE(bitfields
[0]); j
++) {
708 if (!rgbcmp(palette
[j
], bitfields
[i
][j
])) {
716 if (i
== 0) /* 15bit */
723 } /* else fall through */
726 if (compression
!= 0) { /* not BI_RGB */
727 DEBUGF("read_bmp_fd: Unsupported compression (type %d)\n",
734 /* Search to the beginning of the image data */
735 lseek(fd
, (off_t
)letoh32(bmph
.off_bits
), SEEK_SET
);
737 memset(bitmap
, 0, totalsize
);
739 #ifdef HAVE_LCD_COLOR
740 if (read_alpha
&& depth
== 32)
741 bm
->alpha_offset
= totalsize
- alphasize
;
743 bm
->alpha_offset
= 0;
746 struct bmp_args ba
= {
747 .fd
= fd
, .padded_width
= padded_width
, .read_width
= read_width
,
748 .width
= src_dim
.width
, .depth
= depth
, .palette
= palette
,
749 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
750 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
751 .cur_row
= 0, .cur_col
= 0, .part
= {0,0},
753 .alpha_detected
= false, .first_alpha_byte
= 0x80,
756 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
757 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
760 if (resize_on_load(bm
, dither
, &src_dim
, &rset
,
761 bitmap
+ totalsize
, maxsize
- totalsize
,
762 cformat
, IF_PIX_FMT(0,) store_part_bmp
, &ba
))
767 #endif /* LCD_DEPTH */
769 #if LCD_DEPTH > 1 || defined(PLUGIN)
770 struct scaler_context ctx
= {
775 #if defined(PLUGIN) || defined(HAVE_JPEG) || defined(HAVE_BMP_SCALING)
777 void (*output_row_8
)(uint32_t, void*, struct scaler_context
*) =
779 #elif defined(PLUGIN)
780 void (*output_row_8
)(uint32_t, void*, struct scaler_context
*) = NULL
;
782 #if LCD_DEPTH > 1 || defined(PLUGIN)
784 output_row_8
= cformat
->output_row_8
;
788 unsigned char *buf
= ba
.buf
;
789 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \
791 if (bm
->width
> BM_MAX_WIDTH
)
793 #if defined(HAVE_BMP_SCALING) || defined(PLUGIN)
794 unsigned int len
= maxsize
- totalsize
;
795 buf
= bitmap
+ totalsize
;
796 ALIGN_BUFFER(buf
, len
, sizeof(uint32_t));
797 if (bm
->width
*4 > (int)len
)
803 /* loop to read rows and put them to buffer */
804 for (row
= rset
.rowstart
; row
!= rset
.rowstop
; row
+= rset
.rowstep
) {
805 #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \
806 defined(HAVE_BMP_SCALING) || defined(PLUGIN)
807 if (bm
->width
> BM_MAX_WIDTH
)
809 #if defined(HAVE_LCD_COLOR)
810 struct uint8_rgb
*p
= (struct uint8_rgb
*)buf
;
815 int len
= read_part_line(&ba
);
818 memcpy(p
, ba
.buf
, len
*sizeof(*p
));
820 } while (ba
.cur_col
);
824 if (!read_part_line(&ba
))
827 #if !defined(HAVE_LCD_COLOR) && \
828 (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
831 struct uint8_rgb
*qp
= (struct uint8_rgb
*)buf
;
834 /* Convert to destination format */
835 #if ((LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) && \
837 if (format
== FORMAT_NATIVE
) {
838 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
840 unsigned char dy
= DITHERY(row
);
841 #if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)
842 /* iAudio X5/M5 remote */
843 fb_remote_data
*dest
= (fb_remote_data
*)bitmap
844 + bm
->width
* (row
>> 3);
850 for (col
= 0; col
< bm
->width
; col
++) {
852 delta
= DITHERXDY(col
,dy
);
853 #if !defined(HAVE_LCD_COLOR) && \
854 (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
857 bright
= brightness(*qp
++);
859 bright
= (3 * bright
+ (bright
>> 6) + delta
) >> 8;
860 *dest
++ |= vi_pattern
[bright
] << shift
;
862 #endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */
864 #endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */
865 #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) &&
866 (LCD_REMOTE_DEPTH > 1) */
867 #if LCD_DEPTH > 1 || defined(PLUGIN)
869 #if !defined(PLUGIN) && !defined(HAVE_JPEG) && !defined(HAVE_BMP_SCALING)
870 output_row_8_native(row
, buf
, &ctx
);
872 output_row_8(row
, buf
, &ctx
);
876 #if ((LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) && \
885 unsigned char *p
= bitmap
+ bm
->width
* (row
>> 3);
886 unsigned char mask
= BIT_N(row
& 7);
888 for (col
= 0; col
< bm
->width
; col
++, p
++)
889 #if !defined(HAVE_LCD_COLOR) && \
890 (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
894 if (brightness(*qp
++) < 128)
900 #ifdef HAVE_LCD_COLOR
901 if (!ba
.alpha_detected
)
902 { /* if this has an alpha channel, totalsize accounts for it as well
903 * subtract if no actual alpha information was found */
904 if (bm
->alpha_offset
> 0)
905 totalsize
-= alphasize
;
906 bm
->alpha_offset
= 0;
909 return totalsize
; /* return the used buffer size. */