Update Beast installation instructions to use beastpatcher and remove instructions...
[kugel-rb.git] / apps / recorder / bmp.c
blob3fb8a4d6c1c4d924ab3690c9cae0a61615613d60
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(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(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(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(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(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(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(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;
355 /******************************************************************************
356 * read_bmp_fd()
358 * Reads a BMP file in an open file descriptor and puts the data in rockbox
359 * format in *bitmap.
361 *****************************************************************************/
362 int read_bmp_fd(int fd,
363 struct bitmap *bm,
364 int maxsize,
365 int format,
366 const struct custom_format *cformat)
368 struct bmp_header bmph;
369 int padded_width;
370 int read_width;
371 int depth, numcolors, compression, totalsize;
372 int ret;
374 unsigned char *bitmap = bm->data;
375 struct uint8_rgb palette[256];
376 struct rowset rset;
377 struct dim src_dim;
378 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) \
379 || defined(PLUGIN)
380 unsigned int resize = IMG_NORESIZE;
381 bool dither = false;
382 bool transparent = false;
384 #ifdef HAVE_REMOTE_LCD
385 bool remote = false;
386 if (format & FORMAT_REMOTE) {
387 remote = true;
388 #if LCD_REMOTE_DEPTH == 1
389 format = FORMAT_MONO;
390 #endif
392 #endif /* HAVE_REMOTE_LCD */
394 if (format & FORMAT_RESIZE) {
395 resize = IMG_RESIZE;
398 if (format & FORMAT_TRANSPARENT) {
399 transparent = true;
401 if (format & FORMAT_DITHER) {
402 dither = true;
404 #else
406 (void)format;
407 #endif /*(LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)*/
409 /* read fileheader */
410 ret = read(fd, &bmph, sizeof(struct bmp_header));
411 if (ret < 0) {
412 return ret * 10 - 2;
415 if (ret != sizeof(struct bmp_header)) {
416 DEBUGF("read_bmp_fd: can't read BMP header.");
417 return -3;
420 src_dim.width = letoh32(bmph.width);
421 src_dim.height = letoh32(bmph.height);
422 if (src_dim.height < 0) { /* Top-down BMP file */
423 src_dim.height = -src_dim.height;
424 rset.rowstep = 1;
425 } else { /* normal BMP */
426 rset.rowstep = -1;
429 depth = letoh16(bmph.bit_count);
430 /* 4-byte boundary aligned */
431 read_width = ((src_dim.width * (depth == 15 ? 16 : depth) + 7) >> 3);
432 padded_width = (read_width + 3) & ~3;
434 BDEBUGF("width: %d height: %d depth: %d padded_width: %d\n", src_dim.width,
435 src_dim.height, depth, padded_width);
437 #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
438 if ((format & 3) == FORMAT_ANY) {
439 if (depth == 1)
440 format = (format & ~3);
441 else
442 format = (format & ~3) | FORMAT_NATIVE;
444 bm->format = format & 1;
445 if ((format & 1) == FORMAT_MONO)
447 resize &= ~IMG_RESIZE;
448 resize |= IMG_NORESIZE;
449 #ifdef HAVE_REMOTE_LCD
450 remote = 0;
451 #endif
453 #elif !defined(PLUGIN)
454 if (src_dim.width > BM_MAX_WIDTH)
455 return -6;
456 #endif /*(LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)*/
458 #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) || \
459 defined(PLUGIN)
460 if (resize & IMG_RESIZE) {
461 if(format & FORMAT_KEEP_ASPECT) {
462 /* keep aspect ratio.. */
463 struct dim resize_dim = {
464 .width = bm->width,
465 .height = bm->height,
467 if (recalc_dimension(&resize_dim, &src_dim))
468 resize = IMG_NORESIZE;
469 bm->width = resize_dim.width;
470 bm->height = resize_dim.height;
474 format &= 1;
476 if (!(resize & IMG_RESIZE)) {
477 #endif
478 /* returning image size */
479 bm->width = src_dim.width;
480 bm->height = src_dim.height;
482 #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) || \
483 defined(PLUGIN)
485 #endif
487 if (rset.rowstep > 0) { /* Top-down BMP file */
488 rset.rowstart = 0;
489 rset.rowstop = bm->height;
490 } else { /* normal BMP */
491 rset.rowstart = bm->height - 1;
492 rset.rowstop = -1;
495 if (cformat)
496 totalsize = cformat->get_size(bm);
497 else
498 totalsize = BM_SIZE(bm->width,bm->height,format,remote);
500 /* Check if this fits the buffer */
501 if (totalsize > maxsize) {
502 DEBUGF("read_bmp_fd: Bitmap too large for buffer: "
503 "%d bytes.\n", totalsize);
504 return -6;
507 compression = letoh32(bmph.compression);
508 if (depth <= 8) {
509 numcolors = letoh32(bmph.clr_used);
510 if (numcolors == 0)
511 numcolors = 1 << depth;
512 } else
513 numcolors = (compression == 3) ? 3 : 0;
515 if (numcolors > 0 && numcolors <= 256) {
516 int i;
517 union rgb_union pal;
518 for (i = 0; i < numcolors; i++) {
519 if (read(fd, &pal, sizeof(pal)) != (int)sizeof(pal))
521 DEBUGF("read_bmp_fd: Can't read color palette\n");
522 return -7;
524 set_rgb_union(&palette[i], pal);
528 switch (depth) {
529 case 16:
530 #if LCD_DEPTH >= 16
531 /* don't dither 16 bit BMP to LCD with same or larger depth */
532 #ifdef HAVE_REMOTE_LCD
533 if (!remote)
534 #endif
535 dither = false;
536 #endif
537 if (compression == 0) { /* BI_RGB, i.e. 15 bit */
538 depth = 15;
539 break;
540 } /* else fall through */
542 case 32:
543 if (compression == 3) { /* BI_BITFIELDS */
544 bool found;
545 int i, j;
547 /* (i == 0) is 15bit, (i == 1) is 16bit, (i == 2) is 32bit */
548 for (i = 0; i < ARRAY_SIZE(bitfields); i++) {
549 for (j = 0; j < ARRAY_SIZE(bitfields[0]); j++) {
550 if (!rgbcmp(palette[j], bitfields[i][j])) {
551 found = true;
552 } else {
553 found = false;
554 break;
557 if (found) {
558 if (i == 0) /* 15bit */
559 depth = 15;
560 break;
563 if (found)
564 break;
565 } /* else fall through */
567 default:
568 if (compression != 0) { /* not BI_RGB */
569 DEBUGF("read_bmp_fd: Unsupported compression (type %d)\n",
570 compression);
571 return -8;
573 break;
576 /* Search to the beginning of the image data */
577 lseek(fd, (off_t)letoh32(bmph.off_bits), SEEK_SET);
579 memset(bitmap, 0, totalsize);
581 struct bmp_args ba = {
582 .fd = fd, .padded_width = padded_width, .read_width = read_width,
583 .width = src_dim.width, .depth = depth, .palette = palette,
584 #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) || \
585 defined(PLUGIN)
586 .cur_row = 0, .cur_col = 0, .part = {0,0}
587 #endif
590 #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) || \
591 defined(PLUGIN)
592 #if LCD_DEPTH > 1
593 if (resize || cformat)
594 #endif
596 if (resize_on_load(bm, dither, &src_dim, &rset,
597 bitmap + totalsize, maxsize - totalsize,
598 cformat, store_part_bmp, &ba))
599 return totalsize;
600 else
601 return 0;
603 #ifndef PLUGIN
604 int fb_width = BM_WIDTH(bm->width,bm->format,remote);
605 #endif
606 #endif /* LCD_DEPTH */
608 #ifndef PLUGIN
609 int col, row;
611 /* loop to read rows and put them to buffer */
612 for (row = rset.rowstart; row != rset.rowstop; row += rset.rowstep) {
613 #if !defined(HAVE_LCD_COLOR) && \
614 (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
615 uint8_t* qp = ba.buf;
616 #else
617 struct uint8_rgb *qp = (struct uint8_rgb *)ba.buf;
618 #endif
619 unsigned mask;
620 unsigned char *p;
621 if (!read_part_line(&ba))
622 return -9;
624 /* Convert to destination format */
625 #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
626 unsigned char dy = DITHERY(row);
627 if (format == FORMAT_NATIVE) {
628 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
629 if (remote) {
630 #if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)
631 /* iAudio X5/M5 remote */
632 fb_remote_data *dest = (fb_remote_data *)bitmap
633 + bm->width * (row >> 3);
634 int shift = row & 7;
635 int delta = 127;
636 unsigned bright;
638 for (col = 0; col < bm->width; col++) {
639 if (dither)
640 delta = DITHERXDY(col,dy);
641 #if !defined(HAVE_LCD_COLOR) && \
642 (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
643 bright = *qp++;
644 #else
645 bright = brightness(*qp++);
646 #endif
647 bright = (3 * bright + (bright >> 6) + delta) >> 8;
648 *dest++ |= vi_pattern[bright] << shift;
650 #endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */
651 } else
652 #endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */
654 #if LCD_DEPTH == 2
655 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
656 /* greyscale iPods */
657 fb_data *dest = (fb_data *)bitmap + fb_width * row;
658 int shift = 6;
659 int delta = 127;
660 unsigned bright;
661 unsigned data = 0;
663 for (col = 0; col < bm->width; col++) {
664 if (dither)
665 delta = DITHERXDY(col,dy);
666 bright = *qp++;
667 bright = (3 * bright + (bright >> 6) + delta) >> 8;
668 data |= (~bright & 3) << shift;
669 shift -= 2;
670 if (shift < 0) {
671 *dest++ = data;
672 data = 0;
673 shift = 6;
676 if (shift < 6)
677 *dest++ = data;
678 #elif LCD_PIXELFORMAT == VERTICAL_PACKING
679 /* iriver H1x0 */
680 fb_data *dest = (fb_data *)bitmap + fb_width * (row >> 2);
681 int shift = 2 * (row & 3);
682 int delta = 127;
683 unsigned bright;
685 for (col = 0; col < bm->width; col++) {
686 if (dither)
687 delta = DITHERXDY(col,dy);
688 bright = *qp++;
689 bright = (3 * bright + (bright >> 6) + delta) >> 8;
690 *dest++ |= (~bright & 3) << shift;
692 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
693 /* iAudio M3 */
694 fb_data *dest = (fb_data *)bitmap + fb_width * (row >> 3);
695 int shift = row & 7;
696 int delta = 127;
697 unsigned bright;
699 for (col = 0; col < bm->width; col++) {
700 if (dither)
701 delta = DITHERXDY(col,dy);
702 bright = *qp++;
703 bright = (3 * bright + (bright >> 6) + delta) >> 8;
704 *dest++ |= vi_pattern[bright] << shift;
706 #endif /* LCD_PIXELFORMAT */
707 #elif LCD_DEPTH == 16
708 /* iriver h300, colour iPods, X5 */
709 fb_data *dest = (fb_data *)bitmap + fb_width * row;
710 int delta = 127;
711 unsigned r, g, b;
712 struct uint8_rgb q0;
714 for (col = 0; col < bm->width; col++) {
715 if (dither)
716 delta = DITHERXDY(col,dy);
717 q0 = *qp++;
718 r = (31 * q0.red + (q0.red >> 3) + delta) >> 8;
719 g = (63 * q0.green + (q0.green >> 2) + delta) >> 8;
720 b = (31 * q0.blue + (q0.blue >> 3) + delta) >> 8;
721 *dest++ = LCD_RGBPACK_LCD(r, g, b);
723 #endif /* LCD_DEPTH */
725 } else
726 #endif /* (LCD_DEPTH > 1) ||
727 defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
729 p = bitmap + bm->width * (row >> 3);
730 mask = 1 << (row & 7);
732 for (col = 0; col < bm->width; col++, p++)
733 #if !defined(HAVE_LCD_COLOR) && \
734 (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
735 if (*qp++ < 128)
736 *p |= mask;
737 #else
738 if (brightness(*qp++) < 128)
739 *p |= mask;
740 #endif
743 return totalsize; /* return the used buffer size. */
744 #endif