summaryrefslogtreecommitdiff
path: root/apps/recorder/bmp.c
diff options
context:
space:
mode:
authorAndrew Mahone <andrew.mahone@gmail.com>2008-12-09 23:07:59 +0000
committerAndrew Mahone <andrew.mahone@gmail.com>2008-12-09 23:07:59 +0000
commit781421afa2085b841b52f876d80f484f565c0755 (patch)
treee952fe4857a1ee3edb91642bfbb96c93947748b4 /apps/recorder/bmp.c
parenta2c71fde1bdb1a62cf66ae0e3b9a864824930dd0 (diff)
downloadrockbox-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.c752
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
322008-11-02 Akio Idehara: refactor for scaler frontend
332008-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) */
92static const unsigned char bitfields[3][12] = { 105static 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 */
100static const unsigned char dither_matrix[16][16] = { 128const 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))
123static const unsigned short vi_pattern[4] = { 151const 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 */
129static 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
135static 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
142static 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
184static 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
191struct 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
206static 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)
321static 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
333static 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)
354static 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
380static 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}