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 | |
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')
-rw-r--r-- | apps/recorder/albumart.c | 9 | ||||
-rw-r--r-- | apps/recorder/albumart.h | 2 | ||||
-rw-r--r-- | apps/recorder/bmp.c | 752 | ||||
-rw-r--r-- | apps/recorder/bmp.h | 157 | ||||
-rw-r--r-- | apps/recorder/resize.c | 718 | ||||
-rw-r--r-- | apps/recorder/resize.h | 60 |
6 files changed, 1380 insertions, 318 deletions
diff --git a/apps/recorder/albumart.c b/apps/recorder/albumart.c index 30a4e0c49f..babf63ef1c 100644 --- a/apps/recorder/albumart.c +++ b/apps/recorder/albumart.c | |||
@@ -297,3 +297,12 @@ void draw_album_art(struct gui_wps *gwps, int handle_id, bool clear) | |||
297 | gwps->display->set_drawmode(DRMODE_SOLID); | 297 | gwps->display->set_drawmode(DRMODE_SOLID); |
298 | } | 298 | } |
299 | } | 299 | } |
300 | |||
301 | void get_albumart_size(struct bitmap *bmp) | ||
302 | { | ||
303 | /* FIXME: What should we do with albumart on remote? */ | ||
304 | struct wps_data *data = gui_wps[0].data; | ||
305 | |||
306 | bmp->width = data->albumart_max_width; | ||
307 | bmp->height = data->albumart_max_height; | ||
308 | } | ||
diff --git a/apps/recorder/albumart.h b/apps/recorder/albumart.h index 52e7c74c02..ecfdb9c9ed 100644 --- a/apps/recorder/albumart.h +++ b/apps/recorder/albumart.h | |||
@@ -40,6 +40,8 @@ void draw_album_art(struct gui_wps *gwps, int handle_id, bool clear); | |||
40 | bool search_albumart_files(const struct mp3entry *id3, const char *size_string, | 40 | bool search_albumart_files(const struct mp3entry *id3, const char *size_string, |
41 | char *buf, int buflen); | 41 | char *buf, int buflen); |
42 | 42 | ||
43 | void get_albumart_size(struct bitmap *bmp); | ||
44 | |||
43 | #endif /* HAVE_ALBUMART */ | 45 | #endif /* HAVE_ALBUMART */ |
44 | 46 | ||
45 | #endif /* _ALBUMART_H_ */ | 47 | #endif /* _ALBUMART_H_ */ |
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 | } |
diff --git a/apps/recorder/bmp.h b/apps/recorder/bmp.h index 3ac73de03b..1f29103556 100644 --- a/apps/recorder/bmp.h +++ b/apps/recorder/bmp.h | |||
@@ -23,6 +23,163 @@ | |||
23 | 23 | ||
24 | #include "config.h" | 24 | #include "config.h" |
25 | #include "lcd.h" | 25 | #include "lcd.h" |
26 | #include "inttypes.h" | ||
27 | #ifdef HAVE_REMOTE_LCD | ||
28 | #include "lcd-remote.h" | ||
29 | #endif | ||
30 | |||
31 | #define ARRAY_SIZE(array) (int)(sizeof(array)/(sizeof(array[0]))) | ||
32 | |||
33 | #define IMG_NORESIZE 0 | ||
34 | #define IMG_RESIZE 1 | ||
35 | #if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) | ||
36 | #define MAX_WIDTH 8 | ||
37 | #else | ||
38 | #define MAX_WIDTH LCD_WIDTH | ||
39 | #endif | ||
40 | |||
41 | struct uint8_rgb { | ||
42 | uint8_t blue; | ||
43 | uint8_t green; | ||
44 | uint8_t red; | ||
45 | }; | ||
46 | |||
47 | struct dim { | ||
48 | short width; | ||
49 | short height; | ||
50 | }; | ||
51 | |||
52 | struct rowset { | ||
53 | short rowstep; | ||
54 | short rowstart; | ||
55 | short rowstop; | ||
56 | }; | ||
57 | |||
58 | #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) | ||
59 | extern const unsigned char dither_matrix[16][16]; | ||
60 | static inline unsigned char dither_mat(unsigned int x, unsigned int y) | ||
61 | { | ||
62 | return dither_matrix[y][x]; | ||
63 | } | ||
64 | #endif | ||
65 | |||
66 | static inline unsigned brightness(struct uint8_rgb color) | ||
67 | { | ||
68 | return (3 * (unsigned)color.red + 6 * (unsigned)color.green | ||
69 | + (unsigned)color.blue) / 10; | ||
70 | } | ||
71 | |||
72 | #if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \ | ||
73 | || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH == 2) \ | ||
74 | && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)) | ||
75 | extern const unsigned short vi_pattern[4]; | ||
76 | static inline unsigned short vi_pat(unsigned int bright) | ||
77 | { | ||
78 | return vi_pattern[bright]; | ||
79 | } | ||
80 | #endif | ||
81 | |||
82 | static inline int get_fb_height(struct bitmap *bm, bool remote) | ||
83 | { | ||
84 | const int height = bm->height; | ||
85 | #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) | ||
86 | const int format = bm->format; | ||
87 | #endif | ||
88 | int dst_height; | ||
89 | |||
90 | #if !defined(HAVE_REMOTE_LCD) || \ | ||
91 | (defined(HAVE_REMOTE_LCD) &&(LCD_REMOTE_DEPTH == 1)) | ||
92 | (void) remote; | ||
93 | #endif | ||
94 | |||
95 | #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) | ||
96 | if (format == FORMAT_NATIVE) { | ||
97 | #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 | ||
98 | if (remote) { | ||
99 | #if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) | ||
100 | dst_height = (height + 7) >> 3; | ||
101 | #endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */ | ||
102 | } else | ||
103 | #endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */ | ||
104 | { | ||
105 | #if LCD_DEPTH == 2 | ||
106 | #if LCD_PIXELFORMAT == HORIZONTAL_PACKING | ||
107 | dst_height = height; | ||
108 | #elif LCD_PIXELFORMAT == VERTICAL_PACKING | ||
109 | dst_height = (height + 3) >> 2; | ||
110 | #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED | ||
111 | dst_height = (height + 7) >> 3; | ||
112 | #endif /* LCD_PIXELFORMAT */ | ||
113 | #elif LCD_DEPTH == 16 | ||
114 | dst_height = height; | ||
115 | #endif /* LCD_DEPTH */ | ||
116 | } | ||
117 | } else | ||
118 | #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */ | ||
119 | { | ||
120 | dst_height = (height + 7) >> 3; | ||
121 | } | ||
122 | |||
123 | return dst_height; | ||
124 | } | ||
125 | |||
126 | static inline int get_fb_width(struct bitmap *bm, bool remote) | ||
127 | { | ||
128 | const int width = bm->width; | ||
129 | #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) | ||
130 | const int format = bm->format; | ||
131 | #endif | ||
132 | int dst_width; | ||
133 | |||
134 | #if !defined(HAVE_REMOTE_LCD) || \ | ||
135 | (defined(HAVE_REMOTE_LCD) &&(LCD_REMOTE_DEPTH == 1)) | ||
136 | (void) remote; | ||
137 | #endif | ||
138 | |||
139 | #if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) | ||
140 | if (format == FORMAT_NATIVE) { | ||
141 | #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 | ||
142 | if (remote) { | ||
143 | #if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) | ||
144 | dst_width = width; | ||
145 | #endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */ | ||
146 | } else | ||
147 | #endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */ | ||
148 | { | ||
149 | #if LCD_DEPTH == 2 | ||
150 | #if LCD_PIXELFORMAT == HORIZONTAL_PACKING | ||
151 | dst_width = (width + 3) >> 2; | ||
152 | #elif LCD_PIXELFORMAT == VERTICAL_PACKING | ||
153 | dst_width = width; | ||
154 | #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED | ||
155 | dst_width = width; | ||
156 | #endif /* LCD_PIXELFORMAT */ | ||
157 | #elif LCD_DEPTH == 16 | ||
158 | dst_width = width; | ||
159 | #endif /* LCD_DEPTH */ | ||
160 | } | ||
161 | } else | ||
162 | #endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */ | ||
163 | { | ||
164 | dst_width = width; | ||
165 | } | ||
166 | |||
167 | return dst_width; | ||
168 | } | ||
169 | |||
170 | static inline int get_totalsize(struct bitmap *bm, bool remote) | ||
171 | { | ||
172 | int sz; | ||
173 | #if defined(HAVE_REMOTE_LCD) && \ | ||
174 | (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) | ||
175 | if (remote) | ||
176 | sz = sizeof(fb_remote_data); | ||
177 | else | ||
178 | #endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */ | ||
179 | sz = sizeof(fb_data); | ||
180 | |||
181 | return get_fb_width(bm, remote) * get_fb_height(bm, remote) * sz; | ||
182 | } | ||
26 | 183 | ||
27 | /********************************************************************* | 184 | /********************************************************************* |
28 | * read_bmp_file() | 185 | * read_bmp_file() |
diff --git a/apps/recorder/resize.c b/apps/recorder/resize.c new file mode 100644 index 0000000000..cce20cdd77 --- /dev/null +++ b/apps/recorder/resize.c | |||
@@ -0,0 +1,718 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id | ||
9 | * | ||
10 | * Copyright (C) 2008 by Akio Idehara, Andrew Mahone | ||
11 | * | ||
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. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | /* | ||
23 | * Implementation of area average and linear row and vertical scalers, and | ||
24 | * nearest-neighbor grey scaler (C) 2008 Andrew Mahone | ||
25 | * | ||
26 | * All files in this archive are subject to the GNU General Public License. | ||
27 | * See the file COPYING in the source tree root for full license agreement. | ||
28 | * | ||
29 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
30 | * KIND, either express or implied. | ||
31 | * | ||
32 | ****************************************************************************/ | ||
33 | |||
34 | #include <stdio.h> | ||
35 | #include <stdlib.h> | ||
36 | #include <string.h> | ||
37 | #include "inttypes.h" | ||
38 | #include "debug.h" | ||
39 | #include "lcd.h" | ||
40 | #include "file.h" | ||
41 | #ifdef HAVE_REMOTE_LCD | ||
42 | #include "lcd-remote.h" | ||
43 | #endif | ||
44 | #ifdef ROCKBOX_DEBUG_SCALERS | ||
45 | #define SDEBUGF DEBUGF | ||
46 | #else | ||
47 | #define SDEBUGF(...) | ||
48 | #endif | ||
49 | #ifndef __PCTOOL__ | ||
50 | #include "config.h" | ||
51 | #include "system.h" | ||
52 | #include "bmp.h" | ||
53 | #include "resize.h" | ||
54 | #include "resize.h" | ||
55 | #include "debug.h" | ||
56 | #else | ||
57 | #undef DEBUGF | ||
58 | #define DEBUGF(...) | ||
59 | #endif | ||
60 | |||
61 | #ifdef HAVE_LCD_COLOR | ||
62 | #define PACKRED(r, delta) ((31 * r + (r >> 3) + delta) >> 8) | ||
63 | #define PACKGREEN(g, delta) ((63 * g + (g >> 2) + delta) >> 8) | ||
64 | #define PACKBLUE(b, delta) ((31 * b + (b >> 3) + delta) >> 8) | ||
65 | |||
66 | #define FILL_BUF_INIT(img_part, store_part, args) { \ | ||
67 | part = store_part(args); \ | ||
68 | if (part == NULL) \ | ||
69 | return false; \ | ||
70 | } | ||
71 | |||
72 | #define FILL_BUF(img_part, store_part, args) { \ | ||
73 | if (part->len == 0) \ | ||
74 | part = store_part(args); \ | ||
75 | if (part == NULL) \ | ||
76 | return false; \ | ||
77 | } | ||
78 | |||
79 | struct uint32_rgb { | ||
80 | uint32_t r; | ||
81 | uint32_t g; | ||
82 | uint32_t b; | ||
83 | }; | ||
84 | |||
85 | struct scaler_context { | ||
86 | uint32_t divmul; | ||
87 | uint32_t round; | ||
88 | struct img_part* (*store_part)(void *); | ||
89 | long last_tick; | ||
90 | unsigned char *buf; | ||
91 | int len; | ||
92 | void *args; | ||
93 | }; | ||
94 | |||
95 | static void scale_h_area_setup(struct bitmap *bm, struct dim *src, | ||
96 | struct scaler_context *ctx) | ||
97 | { | ||
98 | (void) bm; | ||
99 | ctx->divmul = ((src->width - 1 + 0x80000000U) / src->width) << 1; | ||
100 | ctx->round = (src->width + 1) >> 1; | ||
101 | } | ||
102 | |||
103 | /* horizontal area average scaler */ | ||
104 | static bool scale_h_area(struct bitmap *bm, struct dim *src, | ||
105 | struct uint32_rgb *out_line, | ||
106 | struct scaler_context *ctx, bool accum) | ||
107 | { | ||
108 | SDEBUGF("scale_h_area\n"); | ||
109 | unsigned int ix, ox, oxe, mul; | ||
110 | struct uint32_rgb rgbval1, rgbval2; | ||
111 | struct img_part *part; | ||
112 | FILL_BUF_INIT(part,ctx->store_part,ctx->args); | ||
113 | ox = 0; | ||
114 | oxe = 0; | ||
115 | rgbval1.r = 0; | ||
116 | rgbval1.g = 0; | ||
117 | rgbval1.b = 0; | ||
118 | rgbval2.r = 0; | ||
119 | rgbval2.g = 0; | ||
120 | rgbval2.b = 0; | ||
121 | mul = 0; | ||
122 | for (ix = 0; ix < (unsigned int)src->width; ix++) | ||
123 | { | ||
124 | oxe += bm->width; | ||
125 | if (oxe >= (unsigned int)src->width) | ||
126 | { | ||
127 | if (ctx->last_tick != current_tick) | ||
128 | { | ||
129 | yield(); | ||
130 | ctx->last_tick = current_tick; | ||
131 | } | ||
132 | oxe -= src->width; | ||
133 | rgbval1.r = rgbval1.r * bm->width + rgbval2.r * mul; | ||
134 | rgbval1.g = rgbval1.g * bm->width + rgbval2.g * mul; | ||
135 | rgbval1.b = rgbval1.b * bm->width + rgbval2.b * mul; | ||
136 | FILL_BUF(part,ctx->store_part,ctx->args); | ||
137 | rgbval2.r = part->buf->red; | ||
138 | rgbval2.g = part->buf->green; | ||
139 | rgbval2.b = part->buf->blue; | ||
140 | part->buf++; | ||
141 | part->len--; | ||
142 | mul = bm->width - oxe; | ||
143 | rgbval1.r += rgbval2.r * mul; | ||
144 | rgbval1.g += rgbval2.g * mul; | ||
145 | rgbval1.b += rgbval2.b * mul; | ||
146 | out_line[ox].r = (accum ? out_line[ox].r : 0) + | ||
147 | (((uint64_t)rgbval1.r + ctx->round) * | ||
148 | ctx->divmul >> 32); | ||
149 | out_line[ox].g = (accum ? out_line[ox].g : 0) + | ||
150 | (((uint64_t)rgbval1.g + ctx->round) * | ||
151 | ctx->divmul >> 32); | ||
152 | out_line[ox].b = (accum ? out_line[ox].b : 0) + | ||
153 | (((uint64_t)rgbval1.b + ctx->round) * | ||
154 | ctx->divmul >> 32); | ||
155 | rgbval1.r = 0; | ||
156 | rgbval1.g = 0; | ||
157 | rgbval1.b = 0; | ||
158 | mul = bm->width - mul; | ||
159 | ox += 1; | ||
160 | } else { | ||
161 | FILL_BUF(part,ctx->store_part,ctx->args); | ||
162 | rgbval1.r += part->buf->red; | ||
163 | rgbval1.g += part->buf->green; | ||
164 | rgbval1.b += part->buf->blue; | ||
165 | part->buf++; | ||
166 | part->len--; | ||
167 | } | ||
168 | } | ||
169 | return true; | ||
170 | } | ||
171 | |||
172 | /* vertical area average scaler */ | ||
173 | static bool scale_v_area(struct bitmap *bm, bool dither, struct dim *src, | ||
174 | struct rowset *rset, | ||
175 | bool (*h_scaler)(struct bitmap*, struct dim*, | ||
176 | struct uint32_rgb*, | ||
177 | struct scaler_context*, bool), | ||
178 | struct scaler_context *ctx) | ||
179 | { | ||
180 | uint32_t mul, divmul, x, oy, iy, oye, round; | ||
181 | int delta = 127, r, g, b; | ||
182 | fb_data *row, *pix; | ||
183 | divmul = ((src->height - 1 + 0x80000000U) / src->height) << 1; | ||
184 | round = (src->height + 1) >> 1; | ||
185 | mul = 0; | ||
186 | oy = 0; | ||
187 | oye = 0; | ||
188 | struct uint32_rgb *crow1 = (struct uint32_rgb *)(ctx->buf), | ||
189 | *crow2 = crow1 + bm->width; | ||
190 | |||
191 | SDEBUGF("scale_v_area\n"); | ||
192 | memset((void *)ctx->buf, 0, bm->width * 2 * sizeof(struct uint32_rgb)); | ||
193 | row = (fb_data *)(bm->data) + bm->width * | ||
194 | (rset->rowstep == -1 ? bm->height - 1 : 0); | ||
195 | for (iy = 0; iy < (unsigned int)src->height; iy++) | ||
196 | { | ||
197 | oye += bm->height; | ||
198 | if (oye >= (unsigned int)src->height) | ||
199 | { | ||
200 | oye -= src->height; | ||
201 | for (x = 0; x < 3 *(unsigned int)bm->width; x++) | ||
202 | ((uint32_t*)crow1)[x] = ((uint32_t*)crow1)[x] * | ||
203 | bm->height + mul * | ||
204 | ((uint32_t*)crow2)[x]; | ||
205 | if(!h_scaler(bm, src, crow2, ctx, false)) | ||
206 | goto fail; | ||
207 | mul = bm->height - oye; | ||
208 | for (x = 0; x < 3 *(unsigned int)bm->width; x++) | ||
209 | { | ||
210 | ((uint32_t*)crow1)[x] += mul * ((uint32_t*)crow2)[x]; | ||
211 | ((uint32_t*)crow1)[x] = (uint64_t)(round + | ||
212 | ((uint32_t*)crow1)[x]) * | ||
213 | divmul >> 32; | ||
214 | } | ||
215 | pix = row; | ||
216 | for (x = 0; x < (unsigned int)bm->width; x++) | ||
217 | { | ||
218 | if (dither) | ||
219 | delta = dither_mat(x & 0xf, oy & 0xf); | ||
220 | r = PACKRED(crow1[x].r,delta); | ||
221 | g = PACKGREEN(crow1[x].g,delta); | ||
222 | b = PACKBLUE(crow1[x].b,delta); | ||
223 | *pix++ = LCD_RGBPACK_LCD(r, g, b); | ||
224 | } | ||
225 | memset((void *)crow1, 0, bm->width * sizeof(struct uint32_rgb)); | ||
226 | mul = oye; | ||
227 | row += bm->width * rset->rowstep; | ||
228 | oy += 1; | ||
229 | } else { | ||
230 | if (!h_scaler(bm, src, crow1, ctx, true)) | ||
231 | goto fail; | ||
232 | } | ||
233 | } | ||
234 | return true; | ||
235 | fail: | ||
236 | return false; | ||
237 | } | ||
238 | |||
239 | #ifdef HAVE_UPSCALER | ||
240 | static void scale_h_linear_setup(struct bitmap *bm, struct dim *src, | ||
241 | struct scaler_context *ctx) | ||
242 | { | ||
243 | (void) src; | ||
244 | ctx->divmul = ((bm->width - 2 + 0x80000000U) / (bm->width - 1)) << 1; | ||
245 | ctx->round = bm->width >> 1; | ||
246 | } | ||
247 | |||
248 | /* horizontal linear scaler */ | ||
249 | static bool scale_h_linear(struct bitmap *bm, struct dim *src, | ||
250 | struct uint32_rgb *out_line, | ||
251 | struct scaler_context *ctx, bool accum) | ||
252 | { | ||
253 | unsigned int ix, ox, ixe; | ||
254 | struct uint32_rgb rgbval=rgbval, rgbinc=rgbinc; | ||
255 | struct img_part *part; | ||
256 | SDEBUGF("scale_h_linear\n"); | ||
257 | FILL_BUF_INIT(part,ctx->store_part,ctx->args); | ||
258 | ix = 0; | ||
259 | ixe = bm->width - 1; | ||
260 | for (ox = 0; ox < (uint32_t)bm->width; ox++) { | ||
261 | if (ixe >= ((uint32_t)bm->width - 1)) | ||
262 | { | ||
263 | if (ctx->last_tick != current_tick) | ||
264 | { | ||
265 | yield(); | ||
266 | ctx->last_tick = current_tick; | ||
267 | } | ||
268 | ixe -= (bm->width - 1); | ||
269 | rgbinc.r = -(part->buf->red); | ||
270 | rgbinc.g = -(part->buf->green); | ||
271 | rgbinc.b = -(part->buf->blue); | ||
272 | rgbval.r = (part->buf->red) * (bm->width - 1); | ||
273 | rgbval.g = (part->buf->green) * (bm->width - 1); | ||
274 | rgbval.b = (part->buf->blue) * (bm->width - 1); | ||
275 | ix += 1; | ||
276 | if (ix < (uint32_t)src->width) { | ||
277 | part->buf++; | ||
278 | part->len--; | ||
279 | FILL_BUF(part,ctx->store_part,ctx->args); | ||
280 | rgbinc.r += part->buf->red; | ||
281 | rgbinc.g += part->buf->green; | ||
282 | rgbinc.b += part->buf->blue; | ||
283 | rgbval.r += rgbinc.r * ixe; | ||
284 | rgbval.g += rgbinc.g * ixe; | ||
285 | rgbval.b += rgbinc.b * ixe; | ||
286 | } | ||
287 | rgbinc.r *= src->width - 1; | ||
288 | rgbinc.g *= src->width - 1; | ||
289 | rgbinc.b *= src->width - 1; | ||
290 | } | ||
291 | out_line[ox].r = (accum ? out_line[ox].r : 0) + | ||
292 | (((uint64_t)rgbval.r + ctx->round) * | ||
293 | ctx->divmul >> 32); | ||
294 | out_line[ox].g = (accum ? out_line[ox].g : 0) + | ||
295 | (((uint64_t)rgbval.g + ctx->round) * | ||
296 | ctx->divmul >> 32); | ||
297 | out_line[ox].b = (accum ? out_line[ox].b : 0) + | ||
298 | (((uint64_t)rgbval.b + ctx->round) * | ||
299 | ctx->divmul >> 32); | ||
300 | rgbval.r += rgbinc.r; | ||
301 | rgbval.g += rgbinc.g; | ||
302 | rgbval.b += rgbinc.b; | ||
303 | ixe += src->width - 1; | ||
304 | } | ||
305 | return true; | ||
306 | } | ||
307 | |||
308 | /* vertical linear scaler */ | ||
309 | static bool scale_v_linear(struct bitmap *bm, bool dither, struct dim *src, | ||
310 | struct rowset *rset, | ||
311 | bool (*h_scaler)(struct bitmap*, struct dim*, | ||
312 | struct uint32_rgb*, | ||
313 | struct scaler_context*, bool), | ||
314 | struct scaler_context *ctx) | ||
315 | { | ||
316 | uint32_t mul, divmul, x, oy, iy, iye, round; | ||
317 | int delta = 127; | ||
318 | struct uint32_rgb p; | ||
319 | fb_data *row, *pix; | ||
320 | divmul = ((bm->height - 2 + 0x80000000U) / (bm->height - 1)) << 1; | ||
321 | round = bm->height >> 1; | ||
322 | mul = 0; | ||
323 | iy = 0; | ||
324 | iye = bm->height - 1; | ||
325 | struct uint32_rgb *crow1 = (struct uint32_rgb *)(ctx->buf), | ||
326 | *crow2 = crow1 + bm->width, | ||
327 | *t; | ||
328 | |||
329 | SDEBUGF("scale_v_linear\n"); | ||
330 | row = (fb_data *)(bm->data) + bm->width * | ||
331 | (rset->rowstep == -1 ? bm->height - 1 : 0); | ||
332 | if(!h_scaler(bm, src, crow2, ctx, false)) | ||
333 | goto fail; | ||
334 | for (oy = 0; oy < (uint32_t)bm->height; oy++) | ||
335 | { | ||
336 | if (iye >= (uint32_t)bm->height - 1) | ||
337 | { | ||
338 | t = crow2; | ||
339 | crow2 = crow1; | ||
340 | crow1 = t; | ||
341 | iye -= bm->height - 1; | ||
342 | iy += 1; | ||
343 | if (iy < (uint32_t)src->height) | ||
344 | { | ||
345 | if (!h_scaler(bm, src, crow2, ctx, false)) | ||
346 | goto fail; | ||
347 | } | ||
348 | } | ||
349 | pix = row; | ||
350 | for (x = 0; x < (uint32_t)bm->width; x++) | ||
351 | { | ||
352 | p.r = (uint64_t)(crow1[x].r * (bm->height - 1 - iye) + | ||
353 | crow2[x].r * iye + round) * divmul >> 32; | ||
354 | p.g = (uint64_t)(crow1[x].g * (bm->height - 1 - iye) + | ||
355 | crow2[x].g * iye + round) * divmul >> 32; | ||
356 | p.b = (uint64_t)(crow1[x].b * (bm->height - 1 - iye) + | ||
357 | crow2[x].b * iye + round) * divmul >> 32; | ||
358 | if (dither) | ||
359 | delta = dither_mat(x & 0xf, oy & 0xf); | ||
360 | p.r = PACKRED(p.r,delta); | ||
361 | p.g = PACKGREEN(p.g,delta); | ||
362 | p.b = PACKBLUE(p.b,delta); | ||
363 | *pix++ = LCD_RGBPACK_LCD(p.r, p.g, p.b); | ||
364 | } | ||
365 | row += bm->width * rset->rowstep; | ||
366 | iye += src->height - 1; | ||
367 | } | ||
368 | return true; | ||
369 | fail: | ||
370 | return false; | ||
371 | } | ||
372 | #endif /* HAVE_UPSCALER */ | ||
373 | #endif /* HAVE_LCD_COLOR */ | ||
374 | |||
375 | #if LCD_DEPTH < 8 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH < 8) | ||
376 | /* nearest-neighbor up/down/non-scaler */ | ||
377 | static inline bool scale_nearest(struct bitmap *bm, | ||
378 | struct dim *src, | ||
379 | struct rowset *rset, | ||
380 | bool remote, bool dither, | ||
381 | struct img_part* (*store_part)(void *args), | ||
382 | bool (*skip_lines)(void *args, unsigned int), | ||
383 | void *args) | ||
384 | { | ||
385 | const int sw = src->width; | ||
386 | const int sh = src->height; | ||
387 | const int dw = bm->width; | ||
388 | const int dh = bm->height; | ||
389 | unsigned char *bitmap = bm->data; | ||
390 | const int rowstep = rset->rowstep; | ||
391 | const int rowstart = rset->rowstart; | ||
392 | const int rowstop = rset->rowstop; | ||
393 | const int fb_width = get_fb_width(bm, false); | ||
394 | long last_tick = current_tick; | ||
395 | int ix, ox, lx, xe, iy, oy, ly, ye, yet, oyt; | ||
396 | int ixls, xels, iyls, yelsi, oyls, yelso, p; | ||
397 | struct img_part *cur_part; | ||
398 | #ifndef HAVE_LCD_COLOR | ||
399 | fb_data *dest, *dest_t; | ||
400 | #endif | ||
401 | #ifdef HAVE_REMOTE_LCD | ||
402 | fb_remote_data *rdest, *rdest_t; | ||
403 | #endif | ||
404 | |||
405 | SDEBUGF("scale_nearest sw=%d sh=%d dw=%d dh=%d remote=%d\n", sw, sh, dw, | ||
406 | dh, remote); | ||
407 | ly = 0; | ||
408 | iy = 0; | ||
409 | ye = 0; | ||
410 | ixls = (sw > (dw - 1) && dw > 1) ? sw / (dw - 1) : 1; | ||
411 | xels = sw - ixls * (dw - 1) + (dw == 1 ? 1 : 0); | ||
412 | iyls = (sh > (dh - 1) && dh > 1) ? sh / (dh - 1) : 1; | ||
413 | oyls = dh > sh ? dh / sh : 1; | ||
414 | yelsi = iyls * (dh - 1) + (dh == 1 ? 1 : 0); | ||
415 | yelso = oyls * sh; | ||
416 | oyls *= rowstep; | ||
417 | int delta = 127; | ||
418 | #if LCD_PIXELFORMAT == HORIZONTAL_PACKING || \ | ||
419 | (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_PIXELFORMAT == HORIZONTAL_PACKING) | ||
420 | uint8_t buf[4]; | ||
421 | int data, oxt; | ||
422 | #endif | ||
423 | #if LCD_PIXELFORMAT == VERTICAL_PACKING || \ | ||
424 | LCD_PIXELFORMAT == VERTICAL_INTERLEAVED || \ | ||
425 | (defined(HAVE_REMOTE_LCD) && \ | ||
426 | (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED || \ | ||
427 | LCD_REMOTE_PIXELFORMAT == VERTICAL_PACKING)) | ||
428 | int bright, shift; | ||
429 | #endif | ||
430 | for (oy = rowstart; oy != rowstop;) { | ||
431 | SDEBUGF("oy=%d iy=%d\n", oy, iy); | ||
432 | if (last_tick != current_tick) | ||
433 | { | ||
434 | yield(); | ||
435 | last_tick = current_tick; | ||
436 | } | ||
437 | if (iy > ly && !skip_lines(args, iy - ly - 1)) | ||
438 | return false; | ||
439 | ly = iy; | ||
440 | |||
441 | cur_part = store_part(args); | ||
442 | if (cur_part == NULL) | ||
443 | return false; | ||
444 | |||
445 | lx = 0; | ||
446 | ix = 0; | ||
447 | xe = 0; | ||
448 | #if defined(HAVE_REMOTE_LCD) && !defined(HAVE_LCD_COLOR) | ||
449 | if(!remote) | ||
450 | #else | ||
451 | (void)remote; | ||
452 | #endif | ||
453 | #if LCD_PIXELFORMAT == HORIZONTAL_PACKING | ||
454 | dest = (fb_data *)bitmap + fb_width * oy; | ||
455 | #elif LCD_PIXELFORMAT == VERTICAL_PACKING | ||
456 | dest = (fb_data *)bitmap + fb_width * (oy >> 2); | ||
457 | #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED | ||
458 | dest = (fb_data *)bitmap + fb_width * (oy >> 3); | ||
459 | #endif | ||
460 | #ifdef HAVE_REMOTE_LCD | ||
461 | #ifndef HAVE_LCD_COLOR | ||
462 | else | ||
463 | #endif | ||
464 | rdest = (fb_remote_data *)bitmap + fb_width * (oy >> 3); | ||
465 | #endif | ||
466 | for (ox = 0; ox < dw; ox++) { | ||
467 | while (cur_part->len <= ix - lx) | ||
468 | { | ||
469 | lx += cur_part->len; | ||
470 | cur_part = store_part(args); | ||
471 | if (cur_part == NULL) | ||
472 | return false; | ||
473 | } | ||
474 | cur_part->len -= ix - lx; | ||
475 | cur_part->buf += ix - lx; | ||
476 | lx = ix; | ||
477 | #if defined(HAVE_REMOTE_LCD) && !defined(HAVE_LCD_COLOR) | ||
478 | if(!remote) | ||
479 | { | ||
480 | #endif | ||
481 | #if LCD_PIXELFORMAT == HORIZONTAL_PACKING | ||
482 | /* greyscale iPods */ | ||
483 | buf[ox & 3] = brightness(*(cur_part->buf)); | ||
484 | if ((ox & 3) == 3 || ox == dw - 1) | ||
485 | { | ||
486 | dest_t = dest++; | ||
487 | oyt = oy; | ||
488 | yet = ye; | ||
489 | int xo = ox & ~3; | ||
490 | while(yet < dh) | ||
491 | { | ||
492 | data = 0; | ||
493 | for (oxt = 0; oxt < (ox & 3) + 1; oxt++) | ||
494 | { | ||
495 | if (dither) | ||
496 | delta = dither_mat(oyt & 0xf, (xo + oxt) & 0xf); | ||
497 | p = (3 * buf[oxt] + (buf[oxt] >> 6) + delta) >> 8; | ||
498 | data |= (~p & 3) << ((3 - oxt) << 1); | ||
499 | } | ||
500 | *dest_t = data; | ||
501 | dest_t += rowstep * fb_width; | ||
502 | yet += sh; | ||
503 | oyt += 1; | ||
504 | } | ||
505 | } | ||
506 | #elif LCD_PIXELFORMAT == VERTICAL_PACKING | ||
507 | /* iriver H1x0 */ | ||
508 | bright = brightness(*(cur_part->buf)); | ||
509 | dest_t = dest++; | ||
510 | oyt = oy; | ||
511 | yet = ye; | ||
512 | while(yet < dh) | ||
513 | { | ||
514 | shift = (oyt & 3) << 1; | ||
515 | if (dither) | ||
516 | delta = dither_mat(oyt & 0xf, ox & 0xf); | ||
517 | |||
518 | p = (3 * bright + (bright >> 6) + delta) >> 8; | ||
519 | *dest_t |= (~p & 3) << shift; | ||
520 | if ((rowstep > 0 && shift == 6) || shift == 0) | ||
521 | dest_t += rowstep * fb_width; | ||
522 | yet += sh; | ||
523 | oyt += 1; | ||
524 | } | ||
525 | #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED | ||
526 | bright = brightness(*(cur_part->buf)); | ||
527 | dest_t = dest++; | ||
528 | oyt = oy; | ||
529 | yet = ye; | ||
530 | while(yet < dh) | ||
531 | { | ||
532 | shift = oyt & 7; | ||
533 | if (dither) | ||
534 | delta = dither_mat(oyt & 0xf, ox & 0xf); | ||
535 | |||
536 | p = (3 * bright + (bright >> 6) + delta) >> 8; | ||
537 | *dest_t |= vi_pat(p) << shift; | ||
538 | if ((rowstep > 0 && shift == 7) || shift == 0) | ||
539 | dest_t += rowstep * fb_width; | ||
540 | yet += sh; | ||
541 | oyt += 1; | ||
542 | } | ||
543 | #endif /* LCD_PIXELFORMAT */ | ||
544 | #ifdef HAVE_REMOTE_LCD | ||
545 | #ifndef HAVE_LCD_COLOR | ||
546 | } else | ||
547 | #endif | ||
548 | { | ||
549 | #if LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED | ||
550 | bright = brightness(*(cur_part->buf)); | ||
551 | rdest_t = rdest++; | ||
552 | oyt = oy; | ||
553 | yet = ye; | ||
554 | while(yet < dh) | ||
555 | { | ||
556 | shift = oyt & 7; | ||
557 | if (dither) | ||
558 | delta = dither_mat(oyt & 0xf, ox & 0xf); | ||
559 | |||
560 | p = (3 * bright + (bright >> 6) + delta) >> 8; | ||
561 | *rdest_t |= vi_pat(p) << shift; | ||
562 | if ((rowstep > 0 && shift == 7) || shift == 0) | ||
563 | rdest_t += rowstep * fb_width; | ||
564 | yet += sh; | ||
565 | oyt += 1; | ||
566 | } | ||
567 | #else | ||
568 | bright = brightness(*(cur_part->buf)); | ||
569 | rdest_t = rdest++; | ||
570 | oyt = oy; | ||
571 | yet = ye; | ||
572 | while(yet < dh) | ||
573 | { | ||
574 | shift = oyt & 7; | ||
575 | if (dither) | ||
576 | delta = dither_mat(oyt & 0xf, ox & 0xf); | ||
577 | p = (bright + delta) >> 8; | ||
578 | *rdest_t |= (~p & 1) << shift; | ||
579 | if ((rowstep > 0 && shift == 7) || shift == 0) | ||
580 | rdest_t += rowstep * fb_width; | ||
581 | yet += sh; | ||
582 | oyt += 1; | ||
583 | } | ||
584 | #endif | ||
585 | } | ||
586 | #endif | ||
587 | xe += xels; | ||
588 | ix += ixls; | ||
589 | while (xe >= dw) | ||
590 | { | ||
591 | xe -= dw - 1; | ||
592 | ix += 1; | ||
593 | } | ||
594 | } | ||
595 | oy += oyls; | ||
596 | ye += yelso; | ||
597 | while (ye < dh) | ||
598 | { | ||
599 | ye += sh; | ||
600 | oy += rowstep; | ||
601 | } | ||
602 | iy += iyls; | ||
603 | ye -= yelsi; | ||
604 | while (ye >= dh) | ||
605 | { | ||
606 | ye -= dh - 1; | ||
607 | iy += 1; | ||
608 | } | ||
609 | } | ||
610 | return true; | ||
611 | } | ||
612 | #endif | ||
613 | |||
614 | int resize_on_load(struct bitmap *bm, bool dither, struct dim *src, | ||
615 | struct rowset *rset, bool remote, | ||
616 | #ifdef HAVE_LCD_COLOR | ||
617 | unsigned char *buf, unsigned int len, | ||
618 | #endif | ||
619 | struct img_part* (*store_part)(void *args), | ||
620 | bool (*skip_lines)(void *args, unsigned int lines), | ||
621 | void *args) | ||
622 | { | ||
623 | |||
624 | #if defined(HAVE_LCD_COLOR) && !defined(HAVE_REMOTE_LCD) | ||
625 | (void)skip_lines; | ||
626 | #endif | ||
627 | #ifdef HAVE_LCD_COLOR | ||
628 | #ifdef HAVE_REMOTE_LCD | ||
629 | if (!remote) | ||
630 | #endif | ||
631 | { | ||
632 | #ifdef HAVE_UPSCALER | ||
633 | const int sw = src->width; | ||
634 | const int sh = src->height; | ||
635 | const int dw = bm->width; | ||
636 | const int dh = bm->height; | ||
637 | #endif | ||
638 | int ret; | ||
639 | unsigned int needed = sizeof(struct uint32_rgb) * 2 * bm->width; | ||
640 | #if MAX_SC_STACK_ALLOC | ||
641 | uint8_t sc_buf[(needed <= len || needed > MAX_SC_STACK_ALLOC) ? | ||
642 | 0 : needed]; | ||
643 | #endif | ||
644 | if (needed > len) | ||
645 | { | ||
646 | #if MAX_SC_STACK_ALLOC | ||
647 | if (needed > MAX_SC_STACK_ALLOC) | ||
648 | { | ||
649 | DEBUGF("unable to allocate required buffer: %d needed, " | ||
650 | "%d available, %d permitted from stack\n", | ||
651 | needed, len, MAX_SC_STACK_ALLOC); | ||
652 | return 0; | ||
653 | } | ||
654 | if (sizeof(sc_buf) < needed) | ||
655 | { | ||
656 | DEBUGF("failed to allocate large enough buffer on stack: " | ||
657 | "%d needed, only got %d", | ||
658 | needed, MAX_SC_STACK_ALLOC); | ||
659 | return 0; | ||
660 | } | ||
661 | #else | ||
662 | DEBUGF("unable to allocate required buffer: %d needed, " | ||
663 | "%d available\n", needed, len); | ||
664 | return 0; | ||
665 | #endif | ||
666 | } | ||
667 | |||
668 | bool (*h_scaler)(struct bitmap*, struct dim*, | ||
669 | struct uint32_rgb*, | ||
670 | struct scaler_context*, bool); | ||
671 | struct scaler_context ctx; | ||
672 | ctx.last_tick = current_tick; | ||
673 | cpu_boost(true); | ||
674 | #ifdef HAVE_UPSCALER | ||
675 | if (sw > dw) | ||
676 | { | ||
677 | #endif | ||
678 | h_scaler = scale_h_area; | ||
679 | scale_h_area_setup(bm, src, &ctx); | ||
680 | #ifdef HAVE_UPSCALER | ||
681 | } else { | ||
682 | h_scaler = scale_h_linear; | ||
683 | scale_h_linear_setup(bm, src, &ctx); | ||
684 | } | ||
685 | #endif | ||
686 | ctx.store_part = store_part; | ||
687 | ctx.args = args; | ||
688 | #if MAX_SC_STACK_ALLOC | ||
689 | ctx.buf = needed > len ? sc_buf : buf; | ||
690 | #else | ||
691 | ctx.buf = buf; | ||
692 | #endif | ||
693 | ctx.len = len; | ||
694 | #ifdef HAVE_UPSCALER | ||
695 | if (sh > dh) | ||
696 | #endif | ||
697 | ret = scale_v_area(bm, dither, src, rset, h_scaler, &ctx); | ||
698 | #ifdef HAVE_UPSCALER | ||
699 | else | ||
700 | ret = scale_v_linear(bm, dither, src, rset, h_scaler, &ctx); | ||
701 | #endif | ||
702 | cpu_boost(false); | ||
703 | if (!ret) | ||
704 | return 0; | ||
705 | } | ||
706 | #ifdef HAVE_REMOTE_LCD | ||
707 | else | ||
708 | #endif | ||
709 | #endif /* HAVE_LCD_COLOR */ | ||
710 | #if !defined(HAVE_LCD_COLOR) || defined(HAVE_REMOTE_LCD) | ||
711 | { | ||
712 | if (!scale_nearest(bm, src, rset, remote, dither, store_part, | ||
713 | skip_lines, args)) | ||
714 | return 0; | ||
715 | } | ||
716 | #endif /* !HAVE_LCD_COLOR || HAVE_REMOTE_LCD*/ | ||
717 | return get_totalsize(bm, remote); | ||
718 | } | ||
diff --git a/apps/recorder/resize.h b/apps/recorder/resize.h new file mode 100644 index 0000000000..133ac50fdd --- /dev/null +++ b/apps/recorder/resize.h | |||
@@ -0,0 +1,60 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id | ||
9 | * | ||
10 | * Copyright (C) 2008 by Akio Idehara | ||
11 | * | ||
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. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #ifndef _RESIZE_H_ | ||
22 | #define _RESIZE_H_ | ||
23 | |||
24 | #include "config.h" | ||
25 | #include "lcd.h" | ||
26 | |||
27 | /**************************************************************** | ||
28 | * resize_on_load() | ||
29 | * | ||
30 | * resize bitmap on load with scaling | ||
31 | * | ||
32 | * If HAVE_LCD_COLOR then this func use smooth scaling algorithm | ||
33 | * - downscaling both way use "Area Sampling" | ||
34 | * if IMG_RESIZE_BILINER or IMG_RESIZE_NEAREST is NOT set | ||
35 | * - otherwise "Bilinear" or "Nearest Neighbour" | ||
36 | * | ||
37 | * If !(HAVE_LCD_COLOR) then use simple scaling algorithm "Nearest Neighbour" | ||
38 | * | ||
39 | * return -1 for error | ||
40 | ****************************************************************/ | ||
41 | |||
42 | /* nothing needs the on-stack buffer right now */ | ||
43 | #define MAX_SC_STACK_ALLOC 0 | ||
44 | #define HAVE_UPSCALER 1 | ||
45 | |||
46 | struct img_part { | ||
47 | int len; | ||
48 | struct uint8_rgb* buf; | ||
49 | }; | ||
50 | |||
51 | int resize_on_load(struct bitmap *bm, bool dither, | ||
52 | struct dim *src, | ||
53 | struct rowset *tmp_row, bool remote, | ||
54 | #ifdef HAVE_LCD_COLOR | ||
55 | unsigned char *buf, unsigned int len, | ||
56 | #endif | ||
57 | struct img_part* (*store_part)(void *args), | ||
58 | bool (*skip_lines)(void *args, unsigned int lines), | ||
59 | void *args); | ||
60 | #endif /* _RESIZE_H_ */ | ||