diff options
author | Andrew Mahone <andrew.mahone@gmail.com> | 2008-12-09 23:07:59 +0000 |
---|---|---|
committer | Andrew Mahone <andrew.mahone@gmail.com> | 2008-12-09 23:07:59 +0000 |
commit | 781421afa2085b841b52f876d80f484f565c0755 (patch) | |
tree | e952fe4857a1ee3edb91642bfbb96c93947748b4 /apps/recorder/bmp.c | |
parent | a2c71fde1bdb1a62cf66ae0e3b9a864824930dd0 (diff) | |
download | rockbox-781421afa2085b841b52f876d80f484f565c0755.tar.gz rockbox-781421afa2085b841b52f876d80f484f565c0755.zip |
resize-on-load for bitmap files on 2bpp and color targets
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19374 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/recorder/bmp.c')
-rw-r--r-- | apps/recorder/bmp.c | 752 |
1 files changed, 434 insertions, 318 deletions
diff --git a/apps/recorder/bmp.c b/apps/recorder/bmp.c index 9327ac5ec4..cdff8ccb07 100644 --- a/apps/recorder/bmp.c +++ b/apps/recorder/bmp.c | |||
@@ -29,6 +29,13 @@ | |||
29 | - better protection against malformed / non-standard BMPs | 29 | - better protection against malformed / non-standard BMPs |
30 | - code heavily optimised for both size and speed | 30 | - code heavily optimised for both size and speed |
31 | - dithering for 2 bit targets | 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 | ||
32 | */ | 39 | */ |
33 | 40 | ||
34 | #include <stdio.h> | 41 | #include <stdio.h> |
@@ -41,10 +48,16 @@ | |||
41 | #ifdef HAVE_REMOTE_LCD | 48 | #ifdef HAVE_REMOTE_LCD |
42 | #include "lcd-remote.h" | 49 | #include "lcd-remote.h" |
43 | #endif | 50 | #endif |
51 | #ifdef ROCKBOX_DEBUG_BMP_LOADER | ||
52 | #define BDEBUGF DEBUGF | ||
53 | #else | ||
54 | #define BDEBUGF(...) | ||
55 | #endif | ||
44 | #ifndef __PCTOOL__ | 56 | #ifndef __PCTOOL__ |
45 | #include "config.h" | 57 | #include "config.h" |
46 | #include "system.h" | 58 | #include "system.h" |
47 | #include "bmp.h" | 59 | #include "bmp.h" |
60 | #include "resize.h" | ||
48 | #include "debug.h" | 61 | #include "debug.h" |
49 | #else | 62 | #else |
50 | #undef DEBUGF | 63 | #undef DEBUGF |
@@ -88,16 +101,31 @@ union rgb_union { | |||
88 | uint32_t raw; | 101 | uint32_t raw; |
89 | }; | 102 | }; |
90 | 103 | ||
91 | /* masks for supported BI_BITFIELDS encodings (16/32 bit), little endian */ | 104 | /* masks for supported BI_BITFIELDS encodings (16/32 bit) */ |
92 | static const unsigned char bitfields[3][12] = { | 105 | static const struct uint8_rgb bitfields[3][3] = { |
93 | { 0x00,0x7c,0x00,0, 0xe0,0x03,0x00,0, 0x1f,0x00,0x00,0 }, /* 15 bit */ | 106 | /* 15bit */ |
94 | { 0x00,0xf8,0x00,0, 0xe0,0x07,0x00,0, 0x1f,0x00,0x00,0 }, /* 16 bit */ | 107 | { |
95 | { 0x00,0x00,0xff,0, 0x00,0xff,0x00,0, 0xff,0x00,0x00,0 }, /* 32 bit */ | 108 | { .blue = 0x00, .green = 0x7c, .red = 0x00 }, |
109 | { .blue = 0xe0, .green = 0x03, .red = 0x00 }, | ||
110 | { .blue = 0x1f, .green = 0x00, .red = 0x00 }, | ||
111 | }, | ||
112 | /* 16bit */ | ||
113 | { | ||
114 | { .blue = 0x00, .green = 0xf8, .red = 0x00 }, | ||
115 | { .blue = 0xe0, .green = 0x07, .red = 0x00 }, | ||
116 | { .blue = 0x1f, .green = 0x00, .red = 0x00 }, | ||
117 | }, | ||
118 | /* 32bit */ | ||
119 | { | ||
120 | { .blue = 0x00, .green = 0x00, .red = 0xff }, | ||
121 | { .blue = 0x00, .green = 0xff, .red = 0x00 }, | ||
122 | { .blue = 0xff, .green = 0x00, .red = 0x00 }, | ||
123 | }, | ||
96 | }; | 124 | }; |
97 | 125 | ||
98 | #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) | 126 | #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) |
99 | /* canonical ordered dither matrix */ | 127 | /* canonical ordered dither matrix */ |
100 | static const unsigned char dither_matrix[16][16] = { | 128 | const unsigned char dither_matrix[16][16] = { |
101 | { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 }, | 129 | { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 }, |
102 | { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 }, | 130 | { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 }, |
103 | { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 }, | 131 | { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 }, |
@@ -120,31 +148,11 @@ static const unsigned char dither_matrix[16][16] = { | |||
120 | #if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \ | 148 | #if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \ |
121 | || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH == 2) \ | 149 | || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH == 2) \ |
122 | && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)) | 150 | && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)) |
123 | static const unsigned short vi_pattern[4] = { | 151 | const unsigned short vi_pattern[4] = { |
124 | 0x0101, 0x0100, 0x0001, 0x0000 | 152 | 0x0101, 0x0100, 0x0001, 0x0000 |
125 | }; | 153 | }; |
126 | #endif | 154 | #endif |
127 | 155 | ||
128 | /* little endian functions */ | ||
129 | static inline unsigned readshort(uint16_t *value) | ||
130 | { | ||
131 | unsigned char* bytes = (unsigned char*) value; | ||
132 | return (unsigned)bytes[0] | ((unsigned)bytes[1] << 8); | ||
133 | } | ||
134 | |||
135 | static inline uint32_t readlong(uint32_t *value) | ||
136 | { | ||
137 | unsigned char* bytes = (unsigned char*) value; | ||
138 | return (uint32_t)bytes[0] | ((uint32_t)bytes[1] << 8) | | ||
139 | ((uint32_t)bytes[2] << 16) | ((uint32_t)bytes[3] << 24); | ||
140 | } | ||
141 | |||
142 | static inline unsigned brightness(union rgb_union color) | ||
143 | { | ||
144 | return (3 * (unsigned)color.red + 6 * (unsigned)color.green | ||
145 | + (unsigned)color.blue) / 10; | ||
146 | } | ||
147 | |||
148 | /****************************************************************************** | 156 | /****************************************************************************** |
149 | * read_bmp_file() | 157 | * read_bmp_file() |
150 | * | 158 | * |
@@ -165,11 +173,219 @@ int read_bmp_file(const char* filename, | |||
165 | return fd * 10 - 1; | 173 | return fd * 10 - 1; |
166 | } | 174 | } |
167 | 175 | ||
176 | BDEBUGF("read_bmp_file: '%s' remote: %d resize: %d keep_aspect: %d\n", | ||
177 | filename, !!(format & FORMAT_REMOTE), !!(format & FORMAT_RESIZE), | ||
178 | !!(format & FORMAT_KEEP_ASPECT)); | ||
168 | ret = read_bmp_fd(fd, bm, maxsize, format); | 179 | ret = read_bmp_fd(fd, bm, maxsize, format); |
169 | close(fd); | 180 | close(fd); |
170 | return ret; | 181 | return ret; |
171 | } | 182 | } |
172 | 183 | ||
184 | static inline void set_rgb_union(struct uint8_rgb *dst, union rgb_union src) | ||
185 | { | ||
186 | dst->red = src.red; | ||
187 | dst->green = src.green; | ||
188 | dst->blue = src.blue; | ||
189 | } | ||
190 | |||
191 | struct bmp_args { | ||
192 | int fd; | ||
193 | short padded_width; | ||
194 | short read_width; | ||
195 | short width; | ||
196 | short depth; | ||
197 | unsigned char buf[MAX_WIDTH * 4]; | ||
198 | struct uint8_rgb *palette; | ||
199 | #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) | ||
200 | int cur_row; | ||
201 | int cur_col; | ||
202 | struct img_part part; | ||
203 | #endif | ||
204 | }; | ||
205 | |||
206 | static unsigned int read_part_line(struct bmp_args *ba) | ||
207 | { | ||
208 | const int padded_width = ba->padded_width; | ||
209 | const int read_width = ba->read_width; | ||
210 | const int width = ba->width; | ||
211 | const int depth = ba->depth; | ||
212 | #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) | ||
213 | int cur_row = ba->cur_row; | ||
214 | int cur_col = ba->cur_col; | ||
215 | #endif | ||
216 | const int fd = ba->fd; | ||
217 | uint8_t *ibuf; | ||
218 | struct uint8_rgb *buf = (struct uint8_rgb *)(ba->buf); | ||
219 | const struct uint8_rgb *palette = ba->palette; | ||
220 | uint32_t component, data = data; | ||
221 | int ret; | ||
222 | int i, cols, len; | ||
223 | |||
224 | #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) | ||
225 | cols = MIN(width - cur_col,(int)MAX_WIDTH); | ||
226 | len = (cols * (depth == 15 ? 16 : depth) + 7) >> 3; | ||
227 | #else | ||
228 | cols = width; | ||
229 | len = read_width; | ||
230 | #endif | ||
231 | ibuf = ((unsigned char *)buf) + (MAX_WIDTH << 2) - len; | ||
232 | BDEBUGF("read_part_line: cols=%d len=%d\n",cols,len); | ||
233 | ret = read(fd, ibuf, len); | ||
234 | if (ret != len) | ||
235 | { | ||
236 | DEBUGF("read_part_line: error reading image, read returned %d " | ||
237 | "expected %d\n", ret, len); | ||
238 | BDEBUGF("cur_row: %d cur_col: %d cols: %d len: %d\n", cur_row, cur_col, | ||
239 | cols, len); | ||
240 | return 0; | ||
241 | } | ||
242 | for (i = 0; i < cols; i++) | ||
243 | { | ||
244 | switch (depth) | ||
245 | { | ||
246 | case 1: | ||
247 | if ((i & 7) == 0) | ||
248 | data = *ibuf++; | ||
249 | *buf = palette[(data >> 7) & 1]; | ||
250 | data <<= 1; | ||
251 | break; | ||
252 | case 4: | ||
253 | *buf = palette[*ibuf >> 4]; | ||
254 | if (i & 1) | ||
255 | ibuf++; | ||
256 | else | ||
257 | *ibuf <<= 4; | ||
258 | break; | ||
259 | case 8: | ||
260 | *buf = palette[*ibuf++]; | ||
261 | break; | ||
262 | case 15: | ||
263 | case 16: | ||
264 | data = letoh16(*(uint16_t*)ibuf); | ||
265 | component = (data << 3) & 0xf8; | ||
266 | component |= component >> 5; | ||
267 | buf->blue = component; | ||
268 | if (depth == 15) | ||
269 | { | ||
270 | data >>= 2; | ||
271 | component = data & 0xf8; | ||
272 | component |= component >> 5; | ||
273 | } else { | ||
274 | data >>= 3; | ||
275 | component = data & 0xfc; | ||
276 | component |= component >> 6; | ||
277 | } | ||
278 | buf->green = component; | ||
279 | data >>= 5; | ||
280 | component = data & 0xf8; | ||
281 | component |= component >> 5; | ||
282 | buf->red = component; | ||
283 | ibuf += 2; | ||
284 | break; | ||
285 | case 32: | ||
286 | case 24: | ||
287 | buf->blue = *ibuf++; | ||
288 | buf->green = *ibuf++; | ||
289 | buf->red = *ibuf++; | ||
290 | if (depth == 32) | ||
291 | ibuf++; | ||
292 | break; | ||
293 | } | ||
294 | buf++; | ||
295 | } | ||
296 | |||
297 | #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) | ||
298 | cur_col += cols; | ||
299 | if (cur_col == width) | ||
300 | { | ||
301 | #endif | ||
302 | int pad = padded_width - read_width; | ||
303 | if (pad > 0) | ||
304 | { | ||
305 | BDEBUGF("seeking %d bytes to next line\n",pad); | ||
306 | lseek(fd, pad, SEEK_CUR); | ||
307 | } | ||
308 | #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) | ||
309 | cur_col = 0; | ||
310 | BDEBUGF("read_part_line: completed row %d\n", cur_row); | ||
311 | cur_row += 1; | ||
312 | } | ||
313 | |||
314 | ba->cur_row = cur_row; | ||
315 | ba->cur_col = cur_col; | ||
316 | #endif | ||
317 | return cols; | ||
318 | } | ||
319 | |||
320 | #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) | ||
321 | static struct img_part *store_part_bmp(void *args) | ||
322 | { | ||
323 | struct bmp_args *ba = (struct bmp_args *)args; | ||
324 | |||
325 | ba->part.len = read_part_line(ba); | ||
326 | ba->part.buf = (struct uint8_rgb *)ba->buf; | ||
327 | if (ba->part.len) | ||
328 | return &(ba->part); | ||
329 | else | ||
330 | return NULL; | ||
331 | } | ||
332 | |||
333 | static bool skip_lines_bmp(void *args, unsigned int lines) | ||
334 | { | ||
335 | struct bmp_args * ba = (struct bmp_args *)args; | ||
336 | |||
337 | int pad = lines * ba->padded_width + | ||
338 | (ba->cur_col | ||
339 | ? ((ba->cur_col * ba->depth + 7) >> 3) - ba->padded_width | ||
340 | : 0); | ||
341 | if (pad) | ||
342 | { | ||
343 | if(lseek(ba->fd, pad, SEEK_CUR) < 0) | ||
344 | |||
345 | return false; | ||
346 | } | ||
347 | ba->cur_row += lines + (ba->cur_col ? 1 : 0); | ||
348 | ba->cur_col = 0; | ||
349 | return true; | ||
350 | } | ||
351 | #endif | ||
352 | |||
353 | #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) | ||
354 | static inline int recalc_dimension(struct dim *dst, struct dim *src) | ||
355 | { | ||
356 | int tmp; | ||
357 | if (dst->width <= 0) | ||
358 | dst->width = LCD_WIDTH; | ||
359 | if (dst->height <= 0) | ||
360 | dst->height = LCD_HEIGHT; | ||
361 | #ifndef HAVE_UPSCALER | ||
362 | if (dst->width > src->width || dst->height > src->height) | ||
363 | { | ||
364 | dst->width = src->width; | ||
365 | dst->height = src->height; | ||
366 | } | ||
367 | if (src->width == dst->width && src->height == dst->height) | ||
368 | return 1; | ||
369 | #endif | ||
370 | tmp = (src->width * dst->height + (src->height >> 1)) / src->height; | ||
371 | if (tmp > dst->width) | ||
372 | dst->height = (src->height * dst->width + (src->width >> 1)) | ||
373 | / src->width; | ||
374 | else | ||
375 | dst->width = tmp; | ||
376 | return src->width == dst->width && src->height == dst->height; | ||
377 | } | ||
378 | #endif | ||
379 | |||
380 | static inline int rgbcmp(struct uint8_rgb rgb1, struct uint8_rgb rgb2) | ||
381 | { | ||
382 | if ((rgb1.red == rgb2.red) && (rgb1.green == rgb2.green) && | ||
383 | (rgb1.blue == rgb2.blue)) | ||
384 | return 0; | ||
385 | else | ||
386 | return 1; | ||
387 | } | ||
388 | |||
173 | /****************************************************************************** | 389 | /****************************************************************************** |
174 | * read_bmp_fd() | 390 | * read_bmp_fd() |
175 | * | 391 | * |
@@ -183,21 +399,22 @@ int read_bmp_fd(int fd, | |||
183 | int format) | 399 | int format) |
184 | { | 400 | { |
185 | struct bmp_header bmph; | 401 | struct bmp_header bmph; |
186 | int width, height, padded_width; | 402 | int padded_width; |
187 | int dst_height, dst_width; | 403 | int read_width; |
188 | int depth, numcolors, compression, totalsize; | 404 | int depth, numcolors, compression, totalsize; |
189 | int row, col, ret; | 405 | int ret; |
190 | int rowstart, rowstop, rowstep; | ||
191 | 406 | ||
192 | unsigned char *bitmap = bm->data; | 407 | unsigned char *bitmap = bm->data; |
193 | uint32_t bmpbuf[LCD_WIDTH]; /* Buffer for one line */ | 408 | struct uint8_rgb palette[256]; |
194 | uint32_t palette[256]; | 409 | bool remote = false; |
410 | struct rowset rset; | ||
411 | struct dim src_dim; | ||
195 | #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) | 412 | #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) |
196 | bool transparent = false; | 413 | unsigned int resize = IMG_NORESIZE; |
197 | bool dither = false; | 414 | bool dither = false; |
198 | #ifdef HAVE_REMOTE_LCD | 415 | bool transparent = false; |
199 | bool remote = false; | ||
200 | 416 | ||
417 | #ifdef HAVE_REMOTE_LCD | ||
201 | if (format & FORMAT_REMOTE) { | 418 | if (format & FORMAT_REMOTE) { |
202 | remote = true; | 419 | remote = true; |
203 | #if LCD_REMOTE_DEPTH == 1 | 420 | #if LCD_REMOTE_DEPTH == 1 |
@@ -207,6 +424,12 @@ int read_bmp_fd(int fd, | |||
207 | #endif | 424 | #endif |
208 | } | 425 | } |
209 | #endif /* HAVE_REMOTE_LCD */ | 426 | #endif /* HAVE_REMOTE_LCD */ |
427 | |||
428 | if (format & FORMAT_RESIZE) { | ||
429 | resize = IMG_RESIZE; | ||
430 | format &= ~FORMAT_RESIZE; | ||
431 | } | ||
432 | |||
210 | if (format & FORMAT_TRANSPARENT) { | 433 | if (format & FORMAT_TRANSPARENT) { |
211 | transparent = true; | 434 | transparent = true; |
212 | format &= ~FORMAT_TRANSPARENT; | 435 | format &= ~FORMAT_TRANSPARENT; |
@@ -218,7 +441,7 @@ int read_bmp_fd(int fd, | |||
218 | #else | 441 | #else |
219 | 442 | ||
220 | (void)format; | 443 | (void)format; |
221 | #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */ | 444 | #endif /*(LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)*/ |
222 | 445 | ||
223 | /* read fileheader */ | 446 | /* read fileheader */ |
224 | ret = read(fd, &bmph, sizeof(struct bmp_header)); | 447 | ret = read(fd, &bmph, sizeof(struct bmp_header)); |
@@ -231,78 +454,78 @@ int read_bmp_fd(int fd, | |||
231 | return -3; | 454 | return -3; |
232 | } | 455 | } |
233 | 456 | ||
234 | width = readlong(&bmph.width); | 457 | src_dim.width = letoh32(bmph.width); |
235 | if (width > LCD_WIDTH) { | 458 | src_dim.height = letoh32(bmph.height); |
236 | DEBUGF("read_bmp_fd: Bitmap too wide (%d pixels, max is %d)\n", | 459 | if (src_dim.height < 0) { /* Top-down BMP file */ |
237 | width, LCD_WIDTH); | 460 | src_dim.height = -src_dim.height; |
238 | return -4; | 461 | rset.rowstep = 1; |
239 | } | ||
240 | |||
241 | height = readlong(&bmph.height); | ||
242 | if (height < 0) { /* Top-down BMP file */ | ||
243 | height = -height; | ||
244 | rowstart = 0; | ||
245 | rowstop = height; | ||
246 | rowstep = 1; | ||
247 | } else { /* normal BMP */ | 462 | } else { /* normal BMP */ |
248 | rowstart = height - 1; | 463 | rset.rowstep = -1; |
249 | rowstop = -1; | ||
250 | rowstep = -1; | ||
251 | } | 464 | } |
252 | 465 | ||
253 | depth = readshort(&bmph.bit_count); | 466 | depth = letoh16(bmph.bit_count); |
254 | padded_width = ((width * depth + 31) >> 3) & ~3; /* 4-byte boundary aligned */ | 467 | /* 4-byte boundary aligned */ |
468 | read_width = ((src_dim.width * (depth == 15 ? 16 : depth) + 7) >> 3); | ||
469 | padded_width = (read_width + 3) & ~3; | ||
255 | 470 | ||
471 | BDEBUGF("width: %d height: %d depth: %d padded_width: %d\n", src_dim.width, | ||
472 | src_dim.height, depth, padded_width); | ||
473 | |||
256 | #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) | 474 | #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) |
257 | if (format == FORMAT_ANY) { | 475 | if ((format & 3) == FORMAT_ANY) { |
258 | if (depth == 1) | 476 | if (depth == 1) |
259 | format = FORMAT_MONO; | 477 | format = (format & ~3); |
260 | else | 478 | else |
261 | format = FORMAT_NATIVE; | 479 | format = (format & ~3) | FORMAT_NATIVE; |
262 | } | 480 | } |
263 | bm->format = format; | 481 | bm->format = format & 3; |
264 | #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */ | 482 | if ((format & 3) == FORMAT_MONO) |
265 | /* returning image size */ | ||
266 | bm->width = width; | ||
267 | bm->height = height; | ||
268 | |||
269 | #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) | ||
270 | if (format == FORMAT_NATIVE) { | ||
271 | #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 | ||
272 | if (remote) { | ||
273 | #if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) | ||
274 | dst_width = width; | ||
275 | dst_height = (height + 7) >> 3; | ||
276 | #endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */ | ||
277 | totalsize = dst_width * dst_height * sizeof(fb_remote_data); | ||
278 | } else | ||
279 | #endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */ | ||
280 | { | ||
281 | #if LCD_DEPTH == 2 | ||
282 | #if LCD_PIXELFORMAT == HORIZONTAL_PACKING | ||
283 | dst_width = (width + 3) >> 2; | ||
284 | dst_height = height; | ||
285 | #elif LCD_PIXELFORMAT == VERTICAL_PACKING | ||
286 | dst_width = width; | ||
287 | dst_height = (height + 3) >> 2; | ||
288 | #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED | ||
289 | dst_width = width; | ||
290 | dst_height = (height + 7) >> 3; | ||
291 | #endif /* LCD_PIXELFORMAT */ | ||
292 | #elif LCD_DEPTH == 16 | ||
293 | dst_width = width; | ||
294 | dst_height = height; | ||
295 | #endif /* LCD_DEPTH */ | ||
296 | totalsize = dst_width * dst_height * sizeof(fb_data); | ||
297 | } | ||
298 | } else | ||
299 | #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */ | ||
300 | { | 483 | { |
301 | dst_width = width; | 484 | resize &= ~IMG_RESIZE; |
302 | dst_height = (height + 7) >> 3; | 485 | resize |= IMG_NORESIZE; |
303 | totalsize = dst_width * dst_height; | 486 | remote = 0; |
487 | } | ||
488 | #else | ||
489 | if (src_dim.width > MAX_WIDTH) | ||
490 | return -6; | ||
491 | #endif /*(LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)*/ | ||
492 | |||
493 | #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) | ||
494 | if (resize & IMG_RESIZE) { | ||
495 | if(format & FORMAT_KEEP_ASPECT) { | ||
496 | /* keep aspect ratio.. */ | ||
497 | format &= ~FORMAT_KEEP_ASPECT; | ||
498 | struct dim resize_dim = { | ||
499 | .width = bm->width, | ||
500 | .height = bm->height, | ||
501 | }; | ||
502 | if (recalc_dimension(&resize_dim, &src_dim)) | ||
503 | resize = IMG_NORESIZE; | ||
504 | bm->width = resize_dim.width; | ||
505 | bm->height = resize_dim.height; | ||
506 | } | ||
304 | } | 507 | } |
305 | 508 | ||
509 | if (!(resize & IMG_RESIZE)) { | ||
510 | #endif | ||
511 | /* returning image size */ | ||
512 | bm->width = src_dim.width; | ||
513 | bm->height = src_dim.height; | ||
514 | |||
515 | #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) | ||
516 | } | ||
517 | #endif | ||
518 | |||
519 | if (rset.rowstep > 0) { /* Top-down BMP file */ | ||
520 | rset.rowstart = 0; | ||
521 | rset.rowstop = bm->height; | ||
522 | } else { /* normal BMP */ | ||
523 | rset.rowstart = bm->height - 1; | ||
524 | rset.rowstop = -1; | ||
525 | } | ||
526 | |||
527 | totalsize = get_totalsize(bm, remote); | ||
528 | |||
306 | /* Check if this fits the buffer */ | 529 | /* Check if this fits the buffer */ |
307 | if (totalsize > maxsize) { | 530 | if (totalsize > maxsize) { |
308 | DEBUGF("read_bmp_fd: Bitmap too large for buffer: " | 531 | DEBUGF("read_bmp_fd: Bitmap too large for buffer: " |
@@ -310,20 +533,24 @@ int read_bmp_fd(int fd, | |||
310 | return -6; | 533 | return -6; |
311 | } | 534 | } |
312 | 535 | ||
313 | compression = readlong(&bmph.compression); | 536 | compression = letoh32(bmph.compression); |
314 | if (depth <= 8) { | 537 | if (depth <= 8) { |
315 | numcolors = readlong(&bmph.clr_used); | 538 | numcolors = letoh32(bmph.clr_used); |
316 | if (numcolors == 0) | 539 | if (numcolors == 0) |
317 | numcolors = 1 << depth; | 540 | numcolors = 1 << depth; |
318 | } else | 541 | } else |
319 | numcolors = (compression == 3) ? 3 : 0; | 542 | numcolors = (compression == 3) ? 3 : 0; |
320 | 543 | ||
321 | if (numcolors > 0 && numcolors <= 256) { | 544 | if (numcolors > 0 && numcolors <= 256) { |
322 | if (read(fd, palette, numcolors * sizeof(uint32_t)) | 545 | int i; |
323 | != numcolors * (int)sizeof(uint32_t)) | 546 | union rgb_union pal; |
324 | { | 547 | for (i = 0; i < numcolors; i++) { |
325 | DEBUGF("read_bmp_fd: Can't read color palette\n"); | 548 | if (read(fd, &pal, sizeof(pal)) != (int)sizeof(pal)) |
326 | return -7; | 549 | { |
550 | DEBUGF("read_bmp_fd: Can't read color palette\n"); | ||
551 | return -7; | ||
552 | } | ||
553 | set_rgb_union(&palette[i], pal); | ||
327 | } | 554 | } |
328 | } | 555 | } |
329 | 556 | ||
@@ -343,15 +570,27 @@ int read_bmp_fd(int fd, | |||
343 | 570 | ||
344 | case 32: | 571 | case 32: |
345 | if (compression == 3) { /* BI_BITFIELDS */ | 572 | if (compression == 3) { /* BI_BITFIELDS */ |
346 | if (!memcmp(palette, bitfields[0], 12)) { /* 15 bit */ | 573 | bool found; |
347 | depth = 15; | 574 | int i, j; |
348 | break; | 575 | |
576 | /* (i == 0) is 15bit, (i == 1) is 16bit, (i == 2) is 32bit */ | ||
577 | for (i = 0; i < ARRAY_SIZE(bitfields); i++) { | ||
578 | for (j = 0; j < ARRAY_SIZE(bitfields[0]); j++) { | ||
579 | if (!rgbcmp(palette[j], bitfields[i][j])) { | ||
580 | found = true; | ||
581 | } else { | ||
582 | found = false; | ||
583 | break; | ||
584 | } | ||
585 | } | ||
586 | if (found) { | ||
587 | if (i == 0) /* 15bit */ | ||
588 | depth = 15; | ||
589 | break; | ||
590 | } | ||
349 | } | 591 | } |
350 | if (!memcmp(palette, bitfields[1], 12) /* 16 bit */ | 592 | if (found) |
351 | || !memcmp(palette, bitfields[2], 12)) /* 32 bit */ | ||
352 | { | ||
353 | break; | 593 | break; |
354 | } | ||
355 | } /* else fall through */ | 594 | } /* else fall through */ |
356 | 595 | ||
357 | default: | 596 | default: |
@@ -364,227 +603,104 @@ int read_bmp_fd(int fd, | |||
364 | } | 603 | } |
365 | 604 | ||
366 | /* Search to the beginning of the image data */ | 605 | /* Search to the beginning of the image data */ |
367 | lseek(fd, (off_t)readlong(&bmph.off_bits), SEEK_SET); | 606 | lseek(fd, (off_t)letoh32(bmph.off_bits), SEEK_SET); |
368 | 607 | ||
369 | memset(bitmap, 0, totalsize); | 608 | memset(bitmap, 0, totalsize); |
370 | 609 | ||
371 | /* loop to read rows and put them to buffer */ | 610 | struct bmp_args ba = { |
372 | for (row = rowstart; row != rowstop; row += rowstep) { | 611 | .fd = fd, .padded_width = padded_width, .read_width = read_width, |
373 | unsigned data, mask; | 612 | .width = src_dim.width, .depth = depth, .palette = palette, |
374 | unsigned char *p; | 613 | #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) |
375 | uint16_t *p2; | 614 | .cur_row = 0, .cur_col = 0, .part = {0,0} |
376 | uint32_t *rp; | 615 | #endif |
377 | union rgb_union *qp; | 616 | }; |
378 | union rgb_union q0, q1; | ||
379 | |||
380 | /* read one row */ | ||
381 | ret = read(fd, bmpbuf, padded_width); | ||
382 | if (ret != padded_width) { | ||
383 | DEBUGF("read_bmp_fd: error reading image, read returned: %d " | ||
384 | "expected: %d\n", ret, padded_width); | ||
385 | return -9; | ||
386 | } | ||
387 | 617 | ||
388 | /* convert whole line in-place to XRGB8888 (little endian) */ | 618 | #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) |
389 | rp = bmpbuf + width; | 619 | #if LCD_DEPTH == 16 |
390 | switch (depth) { | 620 | #ifdef HAVE_REMOTE_LCD |
391 | case 1: | 621 | if (resize & IMG_RESIZE || remote) |
392 | q0.raw = palette[0]; | 622 | #else |
393 | q1.raw = palette[1]; | 623 | if (resize & IMG_RESIZE) |
394 | p = (unsigned char*)bmpbuf + ((width + 7) >> 3); | 624 | #endif |
395 | mask = 0x80 >> ((width + 7) & 7); | 625 | #else |
396 | while (p > (unsigned char*)bmpbuf) { | 626 | if (format == FORMAT_NATIVE) |
397 | data = *(--p); | 627 | #endif |
398 | for (; mask <= 0x80; mask <<= 1) | 628 | return resize_on_load(bm, dither, &src_dim, &rset, remote, |
399 | *(--rp) = (data & mask) ? q1.raw : q0.raw; | 629 | #ifdef HAVE_LCD_COLOR |
400 | mask = 0x01; | 630 | bitmap + totalsize, maxsize - totalsize, |
401 | } | 631 | #endif |
402 | break; | 632 | store_part_bmp, skip_lines_bmp, &ba); |
633 | #endif /* LCD_DEPTH */ | ||
403 | 634 | ||
404 | case 4: | 635 | int fb_width = get_fb_width(bm, remote); |
405 | if (width & 1) | 636 | int col, row; |
406 | rp++; | ||
407 | p = (unsigned char*)bmpbuf + ((width + 1) >> 1); | ||
408 | while (p > (unsigned char*)bmpbuf) { | ||
409 | data = *(--p); | ||
410 | *(--rp) = palette[data & 0x0f]; | ||
411 | *(--rp) = palette[data >> 4]; | ||
412 | } | ||
413 | break; | ||
414 | 637 | ||
415 | case 8: | 638 | /* loop to read rows and put them to buffer */ |
416 | p = (unsigned char*)bmpbuf + width; | 639 | for (row = rset.rowstart; row != rset.rowstop; row += rset.rowstep) { |
417 | while (p > (unsigned char*)bmpbuf) | 640 | struct uint8_rgb *qp; |
418 | *(--rp) = palette[*(--p)]; | 641 | unsigned mask; |
419 | break; | 642 | unsigned char *p; |
420 | 643 | #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) | |
421 | case 15: | 644 | unsigned int len; |
422 | case 16: | ||
423 | p2 = (uint16_t *)bmpbuf + width; | ||
424 | while (p2 > (uint16_t *)bmpbuf) { | ||
425 | unsigned component, rgb; | ||
426 | |||
427 | data = letoh16(*(--p2)); | ||
428 | /* blue */ | ||
429 | component = (data << 3) & 0xf8; | ||
430 | #ifdef ROCKBOX_BIG_ENDIAN | ||
431 | rgb = (component | (component >> 5)) << 8; | ||
432 | /* green */ | ||
433 | data >>= 2; | ||
434 | if (depth == 15) { | ||
435 | component = data & 0xf8; | ||
436 | rgb |= component | (component >> 5); | ||
437 | } else { | ||
438 | data >>= 1; | ||
439 | component = data & 0xfc; | ||
440 | rgb |= component | (component >> 6); | ||
441 | } | ||
442 | /* red */ | ||
443 | data >>= 5; | ||
444 | component = data & 0xf8; | ||
445 | rgb = (rgb << 8) | component | (component >> 5); | ||
446 | *(--rp) = rgb << 8; | ||
447 | #else /* little endian */ | ||
448 | rgb = component | (component >> 5); | ||
449 | /* green */ | ||
450 | data >>= 2; | ||
451 | if (depth == 15) { | ||
452 | component = data & 0xf8; | ||
453 | rgb |= (component | (component >> 5)) << 8; | ||
454 | } else { | ||
455 | data >>= 1; | ||
456 | component = data & 0xfc; | ||
457 | rgb |= (component | (component >> 6)) << 8; | ||
458 | } | ||
459 | /* red */ | ||
460 | data >>= 5; | ||
461 | component = data & 0xf8; | ||
462 | rgb |= (component | (component >> 5)) << 16; | ||
463 | *(--rp) = rgb; | ||
464 | #endif | ||
465 | } | ||
466 | break; | ||
467 | 645 | ||
468 | case 24: | 646 | if (!(len = read_part_line(&ba))) |
469 | p = (unsigned char*)bmpbuf + 3 * width; | 647 | return -9; |
470 | while (p > (unsigned char*)bmpbuf) { | 648 | #else |
471 | data = *(--p); | 649 | if (!read_part_line(&ba)) |
472 | data = (data << 8) | *(--p); | 650 | return -9; |
473 | data = (data << 8) | *(--p); | 651 | #endif |
474 | *(--rp) = htole32(data); | ||
475 | } | ||
476 | break; | ||
477 | 652 | ||
478 | case 32: /* already in desired format */ | ||
479 | break; | ||
480 | } | ||
481 | |||
482 | /* Convert to destination format */ | 653 | /* Convert to destination format */ |
483 | qp = (union rgb_union *)bmpbuf; | 654 | qp = (struct uint8_rgb *) ba.buf; |
484 | #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) | 655 | #if LCD_DEPTH == 16 |
485 | if (format == FORMAT_NATIVE) { | 656 | if (format == FORMAT_NATIVE) |
486 | #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 | 657 | { |
487 | if (remote) { | 658 | /* iriver h300, colour iPods, X5 */ |
488 | #if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) | 659 | fb_data *dest = (fb_data *)bitmap + fb_width * row; |
489 | /* iAudio X5/M5 remote */ | 660 | int delta = 127; |
490 | fb_remote_data *dest = (fb_remote_data *)bitmap | 661 | unsigned r, g, b; |
491 | + dst_width * (row >> 3); | 662 | struct uint8_rgb q0; |
492 | int shift = row & 7; | 663 | |
493 | int delta = 127; | 664 | for (col = 0; col < src_dim.width; col++) { |
494 | unsigned bright; | 665 | if (dither) |
495 | 666 | delta = dither_mat(row & 0xf, col & 0xf); | |
496 | for (col = 0; col < width; col++) { | 667 | if (!len) |
497 | if (dither) | 668 | { |
498 | delta = dither_matrix[row & 0xf][col & 0xf]; | 669 | if(!(len = read_part_line(&ba))) |
499 | bright = brightness(*qp++); | 670 | return -9; |
500 | bright = (3 * bright + (bright >> 6) + delta) >> 8; | 671 | else |
501 | *dest++ |= vi_pattern[bright] << shift; | 672 | qp = (struct uint8_rgb *)ba.buf; |
502 | } | ||
503 | #endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */ | ||
504 | } else | ||
505 | #endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */ | ||
506 | { | ||
507 | #if LCD_DEPTH == 2 | ||
508 | #if LCD_PIXELFORMAT == HORIZONTAL_PACKING | ||
509 | /* greyscale iPods */ | ||
510 | fb_data *dest = (fb_data *)bitmap + dst_width * row; | ||
511 | int shift = 6; | ||
512 | int delta = 127; | ||
513 | unsigned bright; | ||
514 | unsigned data = 0; | ||
515 | |||
516 | for (col = 0; col < width; col++) { | ||
517 | if (dither) | ||
518 | delta = dither_matrix[row & 0xf][col & 0xf]; | ||
519 | bright = brightness(*qp++); | ||
520 | bright = (3 * bright + (bright >> 6) + delta) >> 8; | ||
521 | data |= (~bright & 3) << shift; | ||
522 | shift -= 2; | ||
523 | if (shift < 0) { | ||
524 | *dest++ = data; | ||
525 | data = 0; | ||
526 | shift = 6; | ||
527 | } | ||
528 | } | ||
529 | if (shift < 6) | ||
530 | *dest++ = data; | ||
531 | #elif LCD_PIXELFORMAT == VERTICAL_PACKING | ||
532 | /* iriver H1x0 */ | ||
533 | fb_data *dest = (fb_data *)bitmap + dst_width * (row >> 2); | ||
534 | int shift = 2 * (row & 3); | ||
535 | int delta = 127; | ||
536 | unsigned bright; | ||
537 | |||
538 | for (col = 0; col < width; col++) { | ||
539 | if (dither) | ||
540 | delta = dither_matrix[row & 0xf][col & 0xf]; | ||
541 | bright = brightness(*qp++); | ||
542 | bright = (3 * bright + (bright >> 6) + delta) >> 8; | ||
543 | *dest++ |= (~bright & 3) << shift; | ||
544 | } | ||
545 | #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED | ||
546 | /* iAudio M3 */ | ||
547 | fb_data *dest = (fb_data *)bitmap + dst_width * (row >> 3); | ||
548 | int shift = row & 7; | ||
549 | int delta = 127; | ||
550 | unsigned bright; | ||
551 | |||
552 | for (col = 0; col < width; col++) { | ||
553 | if (dither) | ||
554 | delta = dither_matrix[row & 0xf][col & 0xf]; | ||
555 | bright = brightness(*qp++); | ||
556 | bright = (3 * bright + (bright >> 6) + delta) >> 8; | ||
557 | *dest++ |= vi_pattern[bright] << shift; | ||
558 | } | ||
559 | #endif /* LCD_PIXELFORMAT */ | ||
560 | #elif LCD_DEPTH == 16 | ||
561 | /* iriver h300, colour iPods, X5 */ | ||
562 | fb_data *dest = (fb_data *)bitmap + dst_width * row; | ||
563 | int delta = 127; | ||
564 | unsigned r, g, b; | ||
565 | |||
566 | for (col = 0; col < width; col++) { | ||
567 | if (dither) | ||
568 | delta = dither_matrix[row & 0xf][col & 0xf]; | ||
569 | q0 = *qp++; | ||
570 | r = (31 * q0.red + (q0.red >> 3) + delta) >> 8; | ||
571 | g = (63 * q0.green + (q0.green >> 2) + delta) >> 8; | ||
572 | b = (31 * q0.blue + (q0.blue >> 3) + delta) >> 8; | ||
573 | *dest++ = LCD_RGBPACK_LCD(r, g, b); | ||
574 | } | 673 | } |
575 | #endif /* LCD_DEPTH */ | 674 | q0 = *qp++; |
675 | len--; | ||
676 | r = (31 * q0.red + (q0.red >> 3) + delta) >> 8; | ||
677 | g = (63 * q0.green + (q0.green >> 2) + delta) >> 8; | ||
678 | b = (31 * q0.blue + (q0.blue >> 3) + delta) >> 8; | ||
679 | *dest++ = LCD_RGBPACK_LCD(r, g, b); | ||
576 | } | 680 | } |
577 | } else | 681 | } |
578 | #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */ | 682 | else |
683 | #endif | ||
579 | { | 684 | { |
580 | p = bitmap + dst_width * (row >> 3); | 685 | p = bitmap + fb_width * (row >> 3); |
581 | mask = 1 << (row & 7); | 686 | mask = 1 << (row & 7); |
582 | 687 | for (col = 0; col < src_dim.width; col++) | |
583 | for (col = 0; col < width; col++, p++) | 688 | { |
689 | #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) | ||
690 | if (!len) | ||
691 | { | ||
692 | if(!(len = read_part_line(&ba))) | ||
693 | return -9; | ||
694 | else | ||
695 | qp = (struct uint8_rgb *)ba.buf; | ||
696 | } | ||
697 | len--; | ||
698 | #endif | ||
584 | if (brightness(*qp++) < 128) | 699 | if (brightness(*qp++) < 128) |
585 | *p |= mask; | 700 | *p |= mask; |
701 | p++; | ||
702 | } | ||
586 | } | 703 | } |
587 | } | 704 | } |
588 | |||
589 | return totalsize; /* return the used buffer size. */ | 705 | return totalsize; /* return the used buffer size. */ |
590 | } | 706 | } |