Daniel Stenberg | 1c0c861 | 2002-05-17 12:22:24 +0000 | [diff] [blame] | 1 | /*************************************************************************** |
| 2 | * __________ __ ___. |
| 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| 4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| 7 | * \/ \/ \/ \/ \/ |
| 8 | * $Id$ |
| 9 | * |
| 10 | * Copyright (C) 2002 by Linus Nielsen Feltzing |
| 11 | * |
Daniel Stenberg | 2acc0ac | 2008-06-28 18:10:04 +0000 | [diff] [blame] | 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. |
Daniel Stenberg | 1c0c861 | 2002-05-17 12:22:24 +0000 | [diff] [blame] | 16 | * |
| 17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| 18 | * KIND, either express or implied. |
| 19 | * |
| 20 | ****************************************************************************/ |
Linus Nielsen Feltzing | 250678b | 2005-04-25 07:42:10 +0000 | [diff] [blame] | 21 | |
| 22 | /* |
| 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. |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 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 |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 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 |
Linus Nielsen Feltzing | 250678b | 2005-04-25 07:42:10 +0000 | [diff] [blame] | 39 | */ |
Daniel Stenberg | 1c0c861 | 2002-05-17 12:22:24 +0000 | [diff] [blame] | 40 | |
| 41 | #include <stdio.h> |
| 42 | #include <stdlib.h> |
Linus Nielsen Feltzing | 745adad | 2006-01-28 12:12:42 +0000 | [diff] [blame] | 43 | #include <string.h> |
Jens Arnold | 83e18d9 | 2006-11-11 11:26:42 +0000 | [diff] [blame] | 44 | #include "inttypes.h" |
Andrew Mahone | 4eedc93 | 2009-01-04 21:22:05 +0000 | [diff] [blame] | 45 | #ifndef PLUGIN |
Felix Arends | 1f50b8b | 2002-05-29 14:36:09 +0000 | [diff] [blame] | 46 | #include "debug.h" |
Andrew Mahone | 4eedc93 | 2009-01-04 21:22:05 +0000 | [diff] [blame] | 47 | #endif |
Linus Nielsen Feltzing | 250678b | 2005-04-25 07:42:10 +0000 | [diff] [blame] | 48 | #include "lcd.h" |
Dave Chapman | 78d29f5 | 2008-03-26 23:35:34 +0000 | [diff] [blame] | 49 | #include "file.h" |
Maurus Cuelenaere | 36c71a6 | 2009-01-29 20:49:43 +0000 | [diff] [blame] | 50 | #include "bmp.h" |
Jens Arnold | 848e0b5 | 2006-11-20 00:20:09 +0000 | [diff] [blame] | 51 | #ifdef HAVE_REMOTE_LCD |
| 52 | #include "lcd-remote.h" |
| 53 | #endif |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 54 | #ifdef ROCKBOX_DEBUG_BMP_LOADER |
| 55 | #define BDEBUGF DEBUGF |
| 56 | #else |
| 57 | #define BDEBUGF(...) |
| 58 | #endif |
Dave Chapman | b9bb723 | 2008-03-26 18:18:22 +0000 | [diff] [blame] | 59 | #ifndef __PCTOOL__ |
Linus Nielsen Feltzing | 745adad | 2006-01-28 12:12:42 +0000 | [diff] [blame] | 60 | #include "config.h" |
Michael Sevakis | 756ce4a | 2006-10-11 01:43:53 +0000 | [diff] [blame] | 61 | #include "system.h" |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 62 | #include "resize.h" |
Dave Chapman | b9bb723 | 2008-03-26 18:18:22 +0000 | [diff] [blame] | 63 | #else |
Maurus Cuelenaere | 36c71a6 | 2009-01-29 20:49:43 +0000 | [diff] [blame] | 64 | #include "checkwps.h" |
Dave Chapman | b9bb723 | 2008-03-26 18:18:22 +0000 | [diff] [blame] | 65 | #undef DEBUGF |
| 66 | #define DEBUGF(...) |
| 67 | #endif |
Daniel Stenberg | 1c0c861 | 2002-05-17 12:22:24 +0000 | [diff] [blame] | 68 | |
| 69 | #ifdef __GNUC__ |
| 70 | #define STRUCT_PACKED __attribute__((packed)) |
Felix Arends | 1f50b8b | 2002-05-29 14:36:09 +0000 | [diff] [blame] | 71 | #else |
| 72 | #define STRUCT_PACKED |
| 73 | #pragma pack (push, 2) |
Daniel Stenberg | 1c0c861 | 2002-05-17 12:22:24 +0000 | [diff] [blame] | 74 | #endif |
| 75 | |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 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) */ |
Jens Arnold | 89bfb66 | 2007-11-30 08:51:18 +0000 | [diff] [blame] | 84 | int32_t width; /* bmap width in pixels */ |
| 85 | int32_t height; /* bmap height in pixels */ |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 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 */ |
Daniel Stenberg | 1c0c861 | 2002-05-17 12:22:24 +0000 | [diff] [blame] | 94 | } STRUCT_PACKED; |
| 95 | |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 96 | union rgb_union { |
| 97 | struct { /* Little endian */ |
| 98 | unsigned char blue; |
| 99 | unsigned char green; |
| 100 | unsigned char red; |
| 101 | unsigned char reserved; |
Michael Sevakis | 76a6aaa | 2006-10-11 01:26:09 +0000 | [diff] [blame] | 102 | }; |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 103 | uint32_t raw; |
| 104 | }; |
Michael Sevakis | 76a6aaa | 2006-10-11 01:26:09 +0000 | [diff] [blame] | 105 | |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 106 | /* masks for supported BI_BITFIELDS encodings (16/32 bit) */ |
| 107 | static const struct uint8_rgb bitfields[3][3] = { |
| 108 | /* 15bit */ |
| 109 | { |
| 110 | { .blue = 0x00, .green = 0x7c, .red = 0x00 }, |
| 111 | { .blue = 0xe0, .green = 0x03, .red = 0x00 }, |
| 112 | { .blue = 0x1f, .green = 0x00, .red = 0x00 }, |
| 113 | }, |
| 114 | /* 16bit */ |
| 115 | { |
| 116 | { .blue = 0x00, .green = 0xf8, .red = 0x00 }, |
| 117 | { .blue = 0xe0, .green = 0x07, .red = 0x00 }, |
| 118 | { .blue = 0x1f, .green = 0x00, .red = 0x00 }, |
| 119 | }, |
| 120 | /* 32bit */ |
| 121 | { |
| 122 | { .blue = 0x00, .green = 0x00, .red = 0xff }, |
| 123 | { .blue = 0x00, .green = 0xff, .red = 0x00 }, |
| 124 | { .blue = 0xff, .green = 0x00, .red = 0x00 }, |
| 125 | }, |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 126 | }; |
Michael Sevakis | 76a6aaa | 2006-10-11 01:26:09 +0000 | [diff] [blame] | 127 | |
Andrew Mahone | 07e982d | 2009-01-08 02:49:23 +0000 | [diff] [blame] | 128 | #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 129 | /* the full 16x16 Bayer dither matrix may be calculated quickly with this table |
| 130 | */ |
| 131 | const unsigned char dither_table[16] = |
| 132 | { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 }; |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 133 | #endif |
Michael Sevakis | bed0db2 | 2006-10-11 18:12:36 +0000 | [diff] [blame] | 134 | |
Jens Arnold | 8113717 | 2008-03-20 17:40:58 +0000 | [diff] [blame] | 135 | #if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \ |
| 136 | || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH == 2) \ |
| 137 | && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 138 | const unsigned short vi_pattern[4] = { |
Jens Arnold | 848e0b5 | 2006-11-20 00:20:09 +0000 | [diff] [blame] | 139 | 0x0101, 0x0100, 0x0001, 0x0000 |
| 140 | }; |
| 141 | #endif |
| 142 | |
Linus Nielsen Feltzing | 250678b | 2005-04-25 07:42:10 +0000 | [diff] [blame] | 143 | /****************************************************************************** |
| 144 | * read_bmp_file() |
| 145 | * |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 146 | * Reads a BMP file and puts the data in rockbox format in *bitmap. |
Linus Nielsen Feltzing | 250678b | 2005-04-25 07:42:10 +0000 | [diff] [blame] | 147 | * |
| 148 | *****************************************************************************/ |
Nicolas Pennequin | ec6569e | 2007-11-10 13:26:11 +0000 | [diff] [blame] | 149 | int read_bmp_file(const char* filename, |
Linus Nielsen Feltzing | 745adad | 2006-01-28 12:12:42 +0000 | [diff] [blame] | 150 | struct bitmap *bm, |
| 151 | int maxsize, |
Andrew Mahone | 9058620 | 2008-12-26 07:05:13 +0000 | [diff] [blame] | 152 | int format, |
| 153 | const struct custom_format *cformat) |
Linus Nielsen Feltzing | 250678b | 2005-04-25 07:42:10 +0000 | [diff] [blame] | 154 | { |
Nicolas Pennequin | ec6569e | 2007-11-10 13:26:11 +0000 | [diff] [blame] | 155 | int fd, ret; |
Andrew Mahone | 07e982d | 2009-01-08 02:49:23 +0000 | [diff] [blame] | 156 | fd = open(filename, O_RDONLY); |
Nicolas Pennequin | ec6569e | 2007-11-10 13:26:11 +0000 | [diff] [blame] | 157 | |
| 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; |
| 162 | } |
| 163 | |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 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)); |
Andrew Mahone | 9058620 | 2008-12-26 07:05:13 +0000 | [diff] [blame] | 167 | ret = read_bmp_fd(fd, bm, maxsize, format, cformat); |
Andrew Mahone | 07e982d | 2009-01-08 02:49:23 +0000 | [diff] [blame] | 168 | close(fd); |
Nicolas Pennequin | ec6569e | 2007-11-10 13:26:11 +0000 | [diff] [blame] | 169 | return ret; |
| 170 | } |
| 171 | |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 172 | static inline void set_rgb_union(struct uint8_rgb *dst, union rgb_union src) |
| 173 | { |
| 174 | dst->red = src.red; |
| 175 | dst->green = src.green; |
| 176 | dst->blue = src.blue; |
| 177 | } |
| 178 | |
| 179 | struct bmp_args { |
| 180 | int fd; |
| 181 | short padded_width; |
| 182 | short read_width; |
| 183 | short width; |
| 184 | short depth; |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 185 | unsigned char buf[BM_MAX_WIDTH * 4]; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 186 | struct uint8_rgb *palette; |
Andrew Mahone | 20f76d6 | 2009-05-04 15:46:41 +0000 | [diff] [blame] | 187 | #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \ |
| 188 | defined(HAVE_BMP_SCALING) || defined(PLUGIN) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 189 | int cur_row; |
| 190 | int cur_col; |
| 191 | struct img_part part; |
| 192 | #endif |
| 193 | }; |
| 194 | |
| 195 | static unsigned int read_part_line(struct bmp_args *ba) |
| 196 | { |
| 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; |
Andrew Mahone | 20f76d6 | 2009-05-04 15:46:41 +0000 | [diff] [blame] | 201 | #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \ |
| 202 | defined(HAVE_BMP_SCALING) || defined(PLUGIN) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 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; |
| 213 | |
Andrew Mahone | 20f76d6 | 2009-05-04 15:46:41 +0000 | [diff] [blame] | 214 | #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \ |
| 215 | defined(HAVE_BMP_SCALING) || defined(PLUGIN) |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 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); |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 218 | len = (cols * (depth == 15 ? 16 : depth) + 7) >> 3; |
| 219 | #else |
| 220 | cols = width; |
| 221 | len = read_width; |
| 222 | #endif |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 223 | ibuf = ((unsigned char *)buf) + (BM_MAX_WIDTH << 2) - len; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 224 | BDEBUGF("read_part_line: cols=%d len=%d\n",cols,len); |
Andrew Mahone | 07e982d | 2009-01-08 02:49:23 +0000 | [diff] [blame] | 225 | ret = read(fd, ibuf, len); |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 226 | if (ret != len) |
| 227 | { |
| 228 | DEBUGF("read_part_line: error reading image, read returned %d " |
| 229 | "expected %d\n", ret, len); |
Andrew Mahone | 20f76d6 | 2009-05-04 15:46:41 +0000 | [diff] [blame] | 230 | #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \ |
| 231 | defined(HAVE_BMP_SCALING) || defined(PLUGIN) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 232 | BDEBUGF("cur_row: %d cur_col: %d cols: %d len: %d\n", cur_row, cur_col, |
| 233 | cols, len); |
Andrew Mahone | 4eedc93 | 2009-01-04 21:22:05 +0000 | [diff] [blame] | 234 | #endif |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 235 | return 0; |
| 236 | } |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 237 | while (ibuf < ba->buf + (BM_MAX_WIDTH << 2)) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 238 | { |
| 239 | switch (depth) |
| 240 | { |
| 241 | case 1: |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 242 | data = *ibuf++; |
| 243 | for (i = 0; i < 8; i++) |
| 244 | { |
| 245 | *buf++ = palette[data & 0x80 ? 1 : 0]; |
| 246 | data <<= 1; |
| 247 | } |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 248 | break; |
| 249 | case 4: |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 250 | data = *ibuf++; |
| 251 | *buf++ = palette[data >> 4]; |
| 252 | *buf++ = palette[data & 0xf]; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 253 | break; |
| 254 | case 8: |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 255 | *buf++ = palette[*ibuf++]; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 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) |
| 264 | { |
| 265 | data >>= 2; |
| 266 | component = data & 0xf8; |
| 267 | component |= component >> 5; |
| 268 | } else { |
| 269 | data >>= 3; |
| 270 | component = data & 0xfc; |
| 271 | component |= component >> 6; |
| 272 | } |
| 273 | buf->green = component; |
| 274 | data >>= 5; |
| 275 | component = data & 0xf8; |
| 276 | component |= component >> 5; |
| 277 | buf->red = component; |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 278 | buf++; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 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++; |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 288 | buf++; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 289 | break; |
| 290 | } |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 291 | } |
| 292 | |
Andrew Mahone | 20f76d6 | 2009-05-04 15:46:41 +0000 | [diff] [blame] | 293 | #if !defined(HAVE_LCD_COLOR) && \ |
| 294 | ((LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \ |
| 295 | defined(PLUGIN)) |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 296 | ibuf = ba->buf; |
| 297 | buf = (struct uint8_rgb*)ba->buf; |
| 298 | while (ibuf < ba->buf + cols) |
| 299 | *ibuf++ = brightness(*buf++); |
| 300 | #endif |
| 301 | |
Andrew Mahone | 20f76d6 | 2009-05-04 15:46:41 +0000 | [diff] [blame] | 302 | #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \ |
| 303 | defined(HAVE_BMP_SCALING) || defined(PLUGIN) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 304 | cur_col += cols; |
| 305 | if (cur_col == width) |
| 306 | { |
| 307 | #endif |
| 308 | int pad = padded_width - read_width; |
| 309 | if (pad > 0) |
| 310 | { |
| 311 | BDEBUGF("seeking %d bytes to next line\n",pad); |
Andrew Mahone | 07e982d | 2009-01-08 02:49:23 +0000 | [diff] [blame] | 312 | lseek(fd, pad, SEEK_CUR); |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 313 | } |
Andrew Mahone | 20f76d6 | 2009-05-04 15:46:41 +0000 | [diff] [blame] | 314 | #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \ |
| 315 | defined(HAVE_BMP_SCALING) || defined(PLUGIN) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 316 | cur_col = 0; |
| 317 | BDEBUGF("read_part_line: completed row %d\n", cur_row); |
| 318 | cur_row += 1; |
| 319 | } |
| 320 | |
| 321 | ba->cur_row = cur_row; |
| 322 | ba->cur_col = cur_col; |
| 323 | #endif |
| 324 | return cols; |
| 325 | } |
| 326 | |
Andrew Mahone | 20f76d6 | 2009-05-04 15:46:41 +0000 | [diff] [blame] | 327 | #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \ |
| 328 | defined(HAVE_BMP_SCALING) || defined(PLUGIN) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 329 | static struct img_part *store_part_bmp(void *args) |
| 330 | { |
| 331 | struct bmp_args *ba = (struct bmp_args *)args; |
| 332 | |
| 333 | ba->part.len = read_part_line(ba); |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 334 | #ifdef HAVE_LCD_COLOR |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 335 | ba->part.buf = (struct uint8_rgb *)ba->buf; |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 336 | #else |
| 337 | ba->part.buf = (uint8_t *)ba->buf; |
| 338 | #endif |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 339 | if (ba->part.len) |
| 340 | return &(ba->part); |
| 341 | else |
| 342 | return NULL; |
| 343 | } |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 344 | #endif |
| 345 | |
| 346 | static inline int rgbcmp(struct uint8_rgb rgb1, struct uint8_rgb rgb2) |
| 347 | { |
| 348 | if ((rgb1.red == rgb2.red) && (rgb1.green == rgb2.green) && |
| 349 | (rgb1.blue == rgb2.blue)) |
| 350 | return 0; |
| 351 | else |
| 352 | return 1; |
| 353 | } |
Andrew Mahone | 91efc16 | 2009-05-09 07:31:27 +0000 | [diff] [blame] | 354 | #if LCD_DEPTH > 1 |
Andrew Mahone | 59e70b5 | 2009-05-09 10:32:07 +0000 | [diff] [blame] | 355 | #if !defined(PLUGIN) && !defined(HAVE_JPEG) && !defined(HAVE_BMP_SCALING) |
| 356 | static inline |
| 357 | #endif |
Andrew Mahone | 91efc16 | 2009-05-09 07:31:27 +0000 | [diff] [blame] | 358 | void output_row_8_native(uint32_t row, void * row_in, |
| 359 | struct scaler_context *ctx) |
| 360 | { |
| 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; |
| 378 | |
| 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; |
| 390 | } |
| 391 | } |
| 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; |
| 401 | |
| 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; |
| 408 | } |
| 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; |
| 416 | |
| 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; |
| 423 | } |
| 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); |
| 440 | } |
| 441 | #endif /* LCD_DEPTH */ |
| 442 | } |
| 443 | #endif |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 444 | |
Nicolas Pennequin | ec6569e | 2007-11-10 13:26:11 +0000 | [diff] [blame] | 445 | /****************************************************************************** |
| 446 | * read_bmp_fd() |
| 447 | * |
| 448 | * Reads a BMP file in an open file descriptor and puts the data in rockbox |
| 449 | * format in *bitmap. |
| 450 | * |
| 451 | *****************************************************************************/ |
| 452 | int read_bmp_fd(int fd, |
| 453 | struct bitmap *bm, |
| 454 | int maxsize, |
Andrew Mahone | 9058620 | 2008-12-26 07:05:13 +0000 | [diff] [blame] | 455 | int format, |
| 456 | const struct custom_format *cformat) |
Nicolas Pennequin | ec6569e | 2007-11-10 13:26:11 +0000 | [diff] [blame] | 457 | { |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 458 | struct bmp_header bmph; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 459 | int padded_width; |
| 460 | int read_width; |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 461 | int depth, numcolors, compression, totalsize; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 462 | int ret; |
Maurus Cuelenaere | aec37aa | 2009-05-25 11:12:27 +0000 | [diff] [blame] | 463 | bool return_size = format & FORMAT_RETURN_SIZE; |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 464 | |
| 465 | unsigned char *bitmap = bm->data; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 466 | struct uint8_rgb palette[256]; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 467 | struct rowset rset; |
| 468 | struct dim src_dim; |
Andrew Mahone | 20f76d6 | 2009-05-04 15:46:41 +0000 | [diff] [blame] | 469 | #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \ |
| 470 | defined(PLUGIN) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 471 | bool dither = false; |
Andrew Mahone | 20f76d6 | 2009-05-04 15:46:41 +0000 | [diff] [blame] | 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; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 476 | bool transparent = false; |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 477 | |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 478 | #ifdef HAVE_REMOTE_LCD |
Andrew Mahone | 4eedc93 | 2009-01-04 21:22:05 +0000 | [diff] [blame] | 479 | bool remote = false; |
Jens Arnold | 848e0b5 | 2006-11-20 00:20:09 +0000 | [diff] [blame] | 480 | if (format & FORMAT_REMOTE) { |
| 481 | remote = true; |
| 482 | #if LCD_REMOTE_DEPTH == 1 |
| 483 | format = FORMAT_MONO; |
Jens Arnold | 848e0b5 | 2006-11-20 00:20:09 +0000 | [diff] [blame] | 484 | #endif |
| 485 | } |
| 486 | #endif /* HAVE_REMOTE_LCD */ |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 487 | |
| 488 | if (format & FORMAT_RESIZE) { |
| 489 | resize = IMG_RESIZE; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 490 | } |
| 491 | |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 492 | if (format & FORMAT_TRANSPARENT) { |
Linus Nielsen Feltzing | 3722a99 | 2006-01-29 09:58:53 +0000 | [diff] [blame] | 493 | transparent = true; |
Linus Nielsen Feltzing | 3722a99 | 2006-01-29 09:58:53 +0000 | [diff] [blame] | 494 | } |
Michael Sevakis | 76a6aaa | 2006-10-11 01:26:09 +0000 | [diff] [blame] | 495 | #else |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 496 | |
| 497 | (void)format; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 498 | #endif /*(LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)*/ |
Andrew Mahone | 20f76d6 | 2009-05-04 15:46:41 +0000 | [diff] [blame] | 499 | #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) || \ |
| 500 | defined(PLUGIN) |
| 501 | if (format & FORMAT_DITHER) { |
| 502 | dither = true; |
| 503 | } |
| 504 | #endif |
Linus Nielsen Feltzing | 250678b | 2005-04-25 07:42:10 +0000 | [diff] [blame] | 505 | /* read fileheader */ |
Andrew Mahone | 07e982d | 2009-01-08 02:49:23 +0000 | [diff] [blame] | 506 | ret = read(fd, &bmph, sizeof(struct bmp_header)); |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 507 | if (ret < 0) { |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 508 | return ret * 10 - 2; |
Linus Nielsen Feltzing | 250678b | 2005-04-25 07:42:10 +0000 | [diff] [blame] | 509 | } |
Michael Sevakis | e0710b2 | 2006-10-15 17:51:00 +0000 | [diff] [blame] | 510 | |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 511 | if (ret != sizeof(struct bmp_header)) { |
Nicolas Pennequin | ec6569e | 2007-11-10 13:26:11 +0000 | [diff] [blame] | 512 | DEBUGF("read_bmp_fd: can't read BMP header."); |
Linus Nielsen Feltzing | 250678b | 2005-04-25 07:42:10 +0000 | [diff] [blame] | 513 | return -3; |
| 514 | } |
| 515 | |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 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; |
Jens Arnold | 89bfb66 | 2007-11-30 08:51:18 +0000 | [diff] [blame] | 521 | } else { /* normal BMP */ |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 522 | rset.rowstep = -1; |
Jens Arnold | 89bfb66 | 2007-11-30 08:51:18 +0000 | [diff] [blame] | 523 | } |
| 524 | |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 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; |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 529 | |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 530 | BDEBUGF("width: %d height: %d depth: %d padded_width: %d\n", src_dim.width, |
| 531 | src_dim.height, depth, padded_width); |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 532 | |
| 533 | #if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 534 | if ((format & 3) == FORMAT_ANY) { |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 535 | if (depth == 1) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 536 | format = (format & ~3); |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 537 | else |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 538 | format = (format & ~3) | FORMAT_NATIVE; |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 539 | } |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 540 | bm->format = format & 1; |
| 541 | if ((format & 1) == FORMAT_MONO) |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 542 | { |
Andrew Mahone | 20f76d6 | 2009-05-04 15:46:41 +0000 | [diff] [blame] | 543 | #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \ |
| 544 | defined(HAVE_BMP_SCALING) || defined(PLUGIN) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 545 | resize &= ~IMG_RESIZE; |
| 546 | resize |= IMG_NORESIZE; |
Andrew Mahone | 20f76d6 | 2009-05-04 15:46:41 +0000 | [diff] [blame] | 547 | #endif |
Andrew Mahone | 4eedc93 | 2009-01-04 21:22:05 +0000 | [diff] [blame] | 548 | #ifdef HAVE_REMOTE_LCD |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 549 | remote = 0; |
Andrew Mahone | 4eedc93 | 2009-01-04 21:22:05 +0000 | [diff] [blame] | 550 | #endif |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 551 | } |
Andrew Mahone | 4eedc93 | 2009-01-04 21:22:05 +0000 | [diff] [blame] | 552 | #elif !defined(PLUGIN) |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 553 | if (src_dim.width > BM_MAX_WIDTH) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 554 | return -6; |
| 555 | #endif /*(LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)*/ |
| 556 | |
Andrew Mahone | 20f76d6 | 2009-05-04 15:46:41 +0000 | [diff] [blame] | 557 | #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \ |
| 558 | defined(HAVE_BMP_SCALING) || defined(PLUGIN) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 559 | if (resize & IMG_RESIZE) { |
| 560 | if(format & FORMAT_KEEP_ASPECT) { |
| 561 | /* keep aspect ratio.. */ |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 562 | struct dim resize_dim = { |
| 563 | .width = bm->width, |
| 564 | .height = bm->height, |
| 565 | }; |
| 566 | if (recalc_dimension(&resize_dim, &src_dim)) |
| 567 | resize = IMG_NORESIZE; |
| 568 | bm->width = resize_dim.width; |
| 569 | bm->height = resize_dim.height; |
| 570 | } |
| 571 | } |
| 572 | |
| 573 | if (!(resize & IMG_RESIZE)) { |
| 574 | #endif |
| 575 | /* returning image size */ |
| 576 | bm->width = src_dim.width; |
| 577 | bm->height = src_dim.height; |
| 578 | |
Andrew Mahone | 20f76d6 | 2009-05-04 15:46:41 +0000 | [diff] [blame] | 579 | #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \ |
| 580 | defined(HAVE_BMP_SCALING) || defined(PLUGIN) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 581 | } |
| 582 | #endif |
Andrew Mahone | 20f76d6 | 2009-05-04 15:46:41 +0000 | [diff] [blame] | 583 | #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) |
| 584 | format &= 1; |
| 585 | #endif |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 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; |
| 592 | } |
| 593 | |
Andrew Mahone | 9058620 | 2008-12-26 07:05:13 +0000 | [diff] [blame] | 594 | if (cformat) |
| 595 | totalsize = cformat->get_size(bm); |
| 596 | else |
| 597 | totalsize = BM_SIZE(bm->width,bm->height,format,remote); |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 598 | |
Maurus Cuelenaere | aec37aa | 2009-05-25 11:12:27 +0000 | [diff] [blame] | 599 | if(return_size) |
Maurus Cuelenaere | 0bddb7e | 2009-05-25 15:19:34 +0000 | [diff] [blame] | 600 | { |
Maurus Cuelenaere | d2ea7db | 2009-05-25 20:15:02 +0000 | [diff] [blame] | 601 | #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \ |
| 602 | defined(HAVE_BMP_SCALING) || defined(PLUGIN) |
Maurus Cuelenaere | 0bddb7e | 2009-05-25 15:19:34 +0000 | [diff] [blame] | 603 | if(resize) |
| 604 | totalsize += BM_SCALED_SIZE(bm->width, 0, 0, 0); |
Maurus Cuelenaere | d2ea7db | 2009-05-25 20:15:02 +0000 | [diff] [blame] | 605 | #endif |
Maurus Cuelenaere | aec37aa | 2009-05-25 11:12:27 +0000 | [diff] [blame] | 606 | return totalsize; |
Maurus Cuelenaere | 0bddb7e | 2009-05-25 15:19:34 +0000 | [diff] [blame] | 607 | } |
Maurus Cuelenaere | aec37aa | 2009-05-25 11:12:27 +0000 | [diff] [blame] | 608 | |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 609 | /* Check if this fits the buffer */ |
| 610 | if (totalsize > maxsize) { |
Nicolas Pennequin | ec6569e | 2007-11-10 13:26:11 +0000 | [diff] [blame] | 611 | DEBUGF("read_bmp_fd: Bitmap too large for buffer: " |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 612 | "%d bytes.\n", totalsize); |
Linus Nielsen Feltzing | 250678b | 2005-04-25 07:42:10 +0000 | [diff] [blame] | 613 | return -6; |
| 614 | } |
| 615 | |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 616 | compression = letoh32(bmph.compression); |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 617 | if (depth <= 8) { |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 618 | numcolors = letoh32(bmph.clr_used); |
Linus Nielsen Feltzing | 745adad | 2006-01-28 12:12:42 +0000 | [diff] [blame] | 619 | if (numcolors == 0) |
Jens Arnold | 1d6df54 | 2009-06-07 21:27:05 +0000 | [diff] [blame] | 620 | numcolors = BIT_N(depth); |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 621 | } else |
| 622 | numcolors = (compression == 3) ? 3 : 0; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 623 | |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 624 | if (numcolors > 0 && numcolors <= 256) { |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 625 | int i; |
| 626 | union rgb_union pal; |
| 627 | for (i = 0; i < numcolors; i++) { |
Andrew Mahone | 07e982d | 2009-01-08 02:49:23 +0000 | [diff] [blame] | 628 | if (read(fd, &pal, sizeof(pal)) != (int)sizeof(pal)) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 629 | { |
| 630 | DEBUGF("read_bmp_fd: Can't read color palette\n"); |
| 631 | return -7; |
| 632 | } |
| 633 | set_rgb_union(&palette[i], pal); |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 634 | } |
| 635 | } |
| 636 | |
| 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 */ |
Jens Arnold | 848e0b5 | 2006-11-20 00:20:09 +0000 | [diff] [blame] | 641 | #ifdef HAVE_REMOTE_LCD |
| 642 | if (!remote) |
| 643 | #endif |
| 644 | dither = false; |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 645 | #endif |
| 646 | if (compression == 0) { /* BI_RGB, i.e. 15 bit */ |
| 647 | depth = 15; |
| 648 | break; |
| 649 | } /* else fall through */ |
| 650 | |
| 651 | case 32: |
| 652 | if (compression == 3) { /* BI_BITFIELDS */ |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 653 | bool found; |
| 654 | int i, j; |
| 655 | |
| 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; |
| 664 | } |
| 665 | } |
| 666 | if (found) { |
| 667 | if (i == 0) /* 15bit */ |
| 668 | depth = 15; |
| 669 | break; |
| 670 | } |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 671 | } |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 672 | if (found) |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 673 | break; |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 674 | } /* else fall through */ |
| 675 | |
| 676 | default: |
| 677 | if (compression != 0) { /* not BI_RGB */ |
Nicolas Pennequin | ec6569e | 2007-11-10 13:26:11 +0000 | [diff] [blame] | 678 | DEBUGF("read_bmp_fd: Unsupported compression (type %d)\n", |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 679 | compression); |
Linus Nielsen Feltzing | 745adad | 2006-01-28 12:12:42 +0000 | [diff] [blame] | 680 | return -8; |
| 681 | } |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 682 | break; |
Linus Nielsen Feltzing | 745adad | 2006-01-28 12:12:42 +0000 | [diff] [blame] | 683 | } |
Michael Sevakis | e0710b2 | 2006-10-15 17:51:00 +0000 | [diff] [blame] | 684 | |
Linus Nielsen Feltzing | 250678b | 2005-04-25 07:42:10 +0000 | [diff] [blame] | 685 | /* Search to the beginning of the image data */ |
Andrew Mahone | 07e982d | 2009-01-08 02:49:23 +0000 | [diff] [blame] | 686 | lseek(fd, (off_t)letoh32(bmph.off_bits), SEEK_SET); |
Linus Nielsen Feltzing | 250678b | 2005-04-25 07:42:10 +0000 | [diff] [blame] | 687 | |
Andrew Mahone | 07e982d | 2009-01-08 02:49:23 +0000 | [diff] [blame] | 688 | memset(bitmap, 0, totalsize); |
Michael Sevakis | e0710b2 | 2006-10-15 17:51:00 +0000 | [diff] [blame] | 689 | |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 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, |
Andrew Mahone | 20f76d6 | 2009-05-04 15:46:41 +0000 | [diff] [blame] | 693 | #if (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)) && \ |
| 694 | defined(HAVE_BMP_SCALING) || defined(PLUGIN) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 695 | .cur_row = 0, .cur_col = 0, .part = {0,0} |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 696 | #endif |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 697 | }; |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 698 | |
Andrew Mahone | 20f76d6 | 2009-05-04 15:46:41 +0000 | [diff] [blame] | 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) |
Andrew Mahone | 91efc16 | 2009-05-09 07:31:27 +0000 | [diff] [blame] | 702 | if (resize) |
Andrew Mahone | 4eedc93 | 2009-01-04 21:22:05 +0000 | [diff] [blame] | 703 | #endif |
Andrew Mahone | 9058620 | 2008-12-26 07:05:13 +0000 | [diff] [blame] | 704 | { |
| 705 | if (resize_on_load(bm, dither, &src_dim, &rset, |
| 706 | bitmap + totalsize, maxsize - totalsize, |
Andrew Mahone | eef7945 | 2009-05-06 04:53:56 +0000 | [diff] [blame] | 707 | cformat, IF_PIX_FMT(0,) store_part_bmp, &ba)) |
Andrew Mahone | 9058620 | 2008-12-26 07:05:13 +0000 | [diff] [blame] | 708 | return totalsize; |
| 709 | else |
| 710 | return 0; |
| 711 | } |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 712 | #endif /* LCD_DEPTH */ |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 713 | |
Andrew Mahone | 91efc16 | 2009-05-09 07:31:27 +0000 | [diff] [blame] | 714 | #if LCD_DEPTH > 1 || defined(PLUGIN) |
| 715 | struct scaler_context ctx = { |
| 716 | .bm = bm, |
| 717 | .dither = dither, |
| 718 | }; |
Andrew Mahone | 20f76d6 | 2009-05-04 15:46:41 +0000 | [diff] [blame] | 719 | #endif |
Andrew Mahone | 59e70b5 | 2009-05-09 10:32:07 +0000 | [diff] [blame] | 720 | #if defined(PLUGIN) || defined(HAVE_JPEG) || defined(HAVE_BMP_SCALING) |
Andrew Mahone | 91efc16 | 2009-05-09 07:31:27 +0000 | [diff] [blame] | 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 |
Andrew Mahone | 59e70b5 | 2009-05-09 10:32:07 +0000 | [diff] [blame] | 731 | #endif |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 732 | |
Andrew Mahone | 91efc16 | 2009-05-09 07:31:27 +0000 | [diff] [blame] | 733 | int row; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 734 | /* loop to read rows and put them to buffer */ |
| 735 | for (row = rset.rowstart; row != rset.rowstop; row += rset.rowstep) { |
Andrew Mahone | 91efc16 | 2009-05-09 07:31:27 +0000 | [diff] [blame] | 736 | if (!read_part_line(&ba)) |
| 737 | return -9; |
| 738 | #ifndef PLUGIN |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 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 |
Andrew Mahone | 91efc16 | 2009-05-09 07:31:27 +0000 | [diff] [blame] | 745 | #endif |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 746 | /* Convert to destination format */ |
Andrew Mahone | 91efc16 | 2009-05-09 07:31:27 +0000 | [diff] [blame] | 747 | #if ((LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) && \ |
| 748 | !defined(PLUGIN) |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 749 | if (format == FORMAT_NATIVE) { |
| 750 | #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 |
| 751 | if (remote) { |
Andrew Mahone | 91efc16 | 2009-05-09 07:31:27 +0000 | [diff] [blame] | 752 | unsigned char dy = DITHERY(row); |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 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; |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 760 | |
Andrew Mahone | 91efc16 | 2009-05-09 07:31:27 +0000 | [diff] [blame] | 761 | int col; |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 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++); |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 770 | #endif |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 771 | bright = (3 * bright + (bright >> 6) + delta) >> 8; |
| 772 | *dest++ |= vi_pattern[bright] << shift; |
| 773 | } |
| 774 | #endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */ |
| 775 | } else |
| 776 | #endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */ |
Andrew Mahone | 91efc16 | 2009-05-09 07:31:27 +0000 | [diff] [blame] | 777 | #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && |
| 778 | (LCD_REMOTE_DEPTH > 1) */ |
| 779 | #if LCD_DEPTH > 1 || defined(PLUGIN) |
Andrew Mahone | 781421a | 2008-12-09 23:07:59 +0000 | [diff] [blame] | 780 | { |
Andrew Mahone | 59e70b5 | 2009-05-09 10:32:07 +0000 | [diff] [blame] | 781 | #if !defined(PLUGIN) && !defined(HAVE_JPEG) && !defined(HAVE_BMP_SCALING) |
| 782 | output_row_8_native(row, ba.buf, &ctx); |
| 783 | #else |
Andrew Mahone | 91efc16 | 2009-05-09 07:31:27 +0000 | [diff] [blame] | 784 | output_row_8(row, ba.buf, &ctx); |
Andrew Mahone | 59e70b5 | 2009-05-09 10:32:07 +0000 | [diff] [blame] | 785 | #endif |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 786 | } |
Andrew Mahone | 91efc16 | 2009-05-09 07:31:27 +0000 | [diff] [blame] | 787 | #endif |
| 788 | #if ((LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)) && \ |
| 789 | !defined(PLUGIN) |
| 790 | } |
| 791 | #ifndef PLUGIN |
| 792 | else |
| 793 | #endif |
| 794 | #endif |
| 795 | #ifndef PLUGIN |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 796 | { |
Andrew Mahone | 91efc16 | 2009-05-09 07:31:27 +0000 | [diff] [blame] | 797 | unsigned char *p = bitmap + bm->width * (row >> 3); |
Jens Arnold | 1d6df54 | 2009-06-07 21:27:05 +0000 | [diff] [blame] | 798 | unsigned char mask = BIT_N(row & 7); |
Andrew Mahone | 91efc16 | 2009-05-09 07:31:27 +0000 | [diff] [blame] | 799 | int col; |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 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 |
Jens Arnold | adc4848 | 2006-11-18 14:29:51 +0000 | [diff] [blame] | 806 | if (brightness(*qp++) < 128) |
| 807 | *p |= mask; |
Andrew Mahone | f7fa7e5 | 2008-12-26 07:03:22 +0000 | [diff] [blame] | 808 | #endif |
Linus Nielsen Feltzing | 250678b | 2005-04-25 07:42:10 +0000 | [diff] [blame] | 809 | } |
Andrew Mahone | 91efc16 | 2009-05-09 07:31:27 +0000 | [diff] [blame] | 810 | #endif |
Linus Nielsen Feltzing | 250678b | 2005-04-25 07:42:10 +0000 | [diff] [blame] | 811 | } |
Linus Nielsen Feltzing | 745adad | 2006-01-28 12:12:42 +0000 | [diff] [blame] | 812 | return totalsize; /* return the used buffer size. */ |
Linus Nielsen Feltzing | 250678b | 2005-04-25 07:42:10 +0000 | [diff] [blame] | 813 | } |