diff options
Diffstat (limited to 'apps/recorder')
-rw-r--r-- | apps/recorder/bmp.c | 240 | ||||
-rw-r--r-- | apps/recorder/bmp.h | 14 |
2 files changed, 213 insertions, 41 deletions
diff --git a/apps/recorder/bmp.c b/apps/recorder/bmp.c index d2be8c9172..61d7430bb6 100644 --- a/apps/recorder/bmp.c +++ b/apps/recorder/bmp.c | |||
@@ -26,11 +26,13 @@ | |||
26 | 26 | ||
27 | #include <stdio.h> | 27 | #include <stdio.h> |
28 | #include <stdlib.h> | 28 | #include <stdlib.h> |
29 | 29 | #include <string.h> | |
30 | #include "debug.h" | 30 | #include "debug.h" |
31 | #include "lcd.h" | 31 | #include "lcd.h" |
32 | #include "file.h" | 32 | #include "file.h" |
33 | #include "autoconf.h" | 33 | #include "config.h" |
34 | #include "bmp.h" | ||
35 | #include "lcd.h" | ||
34 | 36 | ||
35 | #ifdef __GNUC__ | 37 | #ifdef __GNUC__ |
36 | #define STRUCT_PACKED __attribute__((packed)) | 38 | #define STRUCT_PACKED __attribute__((packed)) |
@@ -59,6 +61,12 @@ struct Fileheader { | |||
59 | unsigned long ClrImportant; /* important color count */ | 61 | unsigned long ClrImportant; /* important color count */ |
60 | } STRUCT_PACKED; | 62 | } STRUCT_PACKED; |
61 | 63 | ||
64 | struct rgb_quad { /* Little endian */ | ||
65 | unsigned char blue; | ||
66 | unsigned char green; | ||
67 | unsigned char red; | ||
68 | unsigned char reserved; | ||
69 | } STRUCT_PACKED; | ||
62 | 70 | ||
63 | #ifdef ROCKBOX_LITTLE_ENDIAN | 71 | #ifdef ROCKBOX_LITTLE_ENDIAN |
64 | #define readshort(x) *(x) | 72 | #define readshort(x) *(x) |
@@ -79,6 +87,19 @@ static long readlong(long *value) { | |||
79 | 87 | ||
80 | #endif | 88 | #endif |
81 | 89 | ||
90 | unsigned char brightness(struct rgb_quad color) | ||
91 | { | ||
92 | return (3 * (unsigned int)color.red + 6 * (unsigned int)color.green | ||
93 | + (unsigned int)color.blue) / 10; | ||
94 | } | ||
95 | |||
96 | /* Function to get a pixel from a line. (Tomas: maybe a better way?) */ | ||
97 | inline int getpix(int px, unsigned char *bmpbuf) { | ||
98 | int a = (px / 8); | ||
99 | int b = (7 - (px % 8)); | ||
100 | |||
101 | return (bmpbuf[a] & (1 << b)) != 0; | ||
102 | } | ||
82 | 103 | ||
83 | 104 | ||
84 | /****************************************************************************** | 105 | /****************************************************************************** |
@@ -88,16 +109,26 @@ static long readlong(long *value) { | |||
88 | * | 109 | * |
89 | *****************************************************************************/ | 110 | *****************************************************************************/ |
90 | int read_bmp_file(char* filename, | 111 | int read_bmp_file(char* filename, |
91 | int *get_width, /* in pixels */ | 112 | struct bitmap *bm, |
92 | int *get_height, /* in pixels */ | 113 | int maxsize, |
93 | char *bitmap, | 114 | int format) |
94 | int maxsize) /* Maximum amount of bytes to write to bitmap */ | ||
95 | { | 115 | { |
96 | struct Fileheader fh; | 116 | struct Fileheader fh; |
97 | int bitmap_width, bitmap_height, PaddedWidth, PaddedHeight; | 117 | int width, height, PaddedWidth, PaddedHeight; |
98 | int fd, row, col, ret; | 118 | int fd, row, col, ret; |
99 | char bmpbuf[(LCD_WIDTH / 8 + 3) & ~3]; /* Buffer for one line */ | 119 | struct rgb_quad palette[256]; |
120 | int invert_pixel = 0; | ||
121 | int numcolors; | ||
122 | int depth; | ||
123 | int totalsize; | ||
124 | char *bitmap = bm->data; | ||
125 | |||
126 | unsigned char bmpbuf[LCD_WIDTH*sizeof(struct rgb_quad)]; /* Buffer for one line */ | ||
100 | 127 | ||
128 | #if LCD_DEPTH == 1 | ||
129 | (void)format; | ||
130 | #endif | ||
131 | |||
101 | fd = open(filename, O_RDONLY); | 132 | fd = open(filename, O_RDONLY); |
102 | 133 | ||
103 | /* Exit if file opening failed */ | 134 | /* Exit if file opening failed */ |
@@ -119,14 +150,6 @@ int read_bmp_file(char* filename, | |||
119 | return -3; | 150 | return -3; |
120 | } | 151 | } |
121 | 152 | ||
122 | /* Exit if not monochrome */ | ||
123 | if (readshort(&fh.BitCount) != 1) { | ||
124 | DEBUGF("error - Bitmap must be in 1 bit per pixel format. " | ||
125 | "This one is: %d\n", readshort(&fh.BitCount)); | ||
126 | close(fd); | ||
127 | return -4; | ||
128 | } | ||
129 | |||
130 | /* Exit if too wide */ | 153 | /* Exit if too wide */ |
131 | if (readlong(&fh.Width) > LCD_WIDTH) { | 154 | if (readlong(&fh.Width) > LCD_WIDTH) { |
132 | DEBUGF("error - Bitmap is too wide (%d pixels, max is %d)\n", | 155 | DEBUGF("error - Bitmap is too wide (%d pixels, max is %d)\n", |
@@ -144,28 +167,80 @@ int read_bmp_file(char* filename, | |||
144 | } | 167 | } |
145 | 168 | ||
146 | /* Calculate image size */ | 169 | /* Calculate image size */ |
147 | bitmap_height = readlong(&fh.Height); | 170 | height = readlong(&fh.Height); |
148 | bitmap_width = readlong(&fh.Width); | 171 | width = readlong(&fh.Width); |
149 | /* Paddedwidth is for BMP files. */ | 172 | depth = readshort(&fh.BitCount); |
150 | PaddedWidth = ((bitmap_width + 31) & (~0x1f)) / 8; | 173 | |
174 | /* 4-byte boundary aligned */ | ||
175 | PaddedWidth = (width * depth / 8 + 3) & ~3; | ||
176 | |||
177 | #if LCD_DEPTH > 1 | ||
178 | if(format == FORMAT_ANY) { | ||
179 | if(depth == 1) | ||
180 | format = FORMAT_MONO; | ||
181 | else | ||
182 | format = FORMAT_NATIVE; | ||
183 | } | ||
184 | #endif | ||
185 | |||
151 | /* PaddedHeight is for rockbox format. */ | 186 | /* PaddedHeight is for rockbox format. */ |
152 | PaddedHeight = (bitmap_height + 7) / 8; | 187 | if(format == FORMAT_MONO) { |
188 | PaddedHeight = (height + 7) / 8; | ||
189 | totalsize = PaddedHeight * width; | ||
190 | } else { | ||
191 | #if LCD_DEPTH == 2 | ||
192 | PaddedHeight = height/4; | ||
193 | #else | ||
194 | PaddedHeight = height; | ||
195 | #endif | ||
196 | totalsize = PaddedHeight * width * sizeof(fb_data); | ||
197 | } | ||
153 | 198 | ||
154 | /* Check if this fits the buffer */ | 199 | /* Check if this fits the buffer */ |
155 | if ((PaddedHeight * bitmap_width) > maxsize) { | 200 | |
201 | if (totalsize > maxsize) { | ||
156 | DEBUGF("error - Bitmap is too large to fit the supplied buffer: " | 202 | DEBUGF("error - Bitmap is too large to fit the supplied buffer: " |
157 | "%d bytes.\n", (PaddedHeight * bitmap_width)); | 203 | "%d bytes.\n", (PaddedHeight * width)); |
158 | close(fd); | 204 | close(fd); |
159 | return -7; | 205 | return -7; |
160 | } | 206 | } |
161 | 207 | ||
208 | if (depth <= 8) | ||
209 | { | ||
210 | numcolors = readlong(&fh.ClrUsed); | ||
211 | if (numcolors == 0) | ||
212 | numcolors = 1 << depth; | ||
213 | |||
214 | if(read(fd, palette, numcolors * sizeof(struct rgb_quad)) | ||
215 | != numcolors * (int)sizeof(struct rgb_quad)) | ||
216 | { | ||
217 | DEBUGF("error - Can't read bitmap's color palette\n"); | ||
218 | close(fd); | ||
219 | return -8; | ||
220 | } | ||
221 | } | ||
222 | |||
223 | /* Use the darker palette color as foreground on mono bitmaps */ | ||
224 | if(readshort(&fh.BitCount) == 1) { | ||
225 | if(brightness(palette[0]) > brightness(palette[1])) | ||
226 | invert_pixel = 1; | ||
227 | } | ||
228 | |||
162 | /* Search to the beginning of the image data */ | 229 | /* Search to the beginning of the image data */ |
163 | lseek(fd, (off_t)readlong(&fh.OffBits), SEEK_SET); | 230 | lseek(fd, (off_t)readlong(&fh.OffBits), SEEK_SET); |
164 | 231 | ||
232 | #if LCD_DEPTH == 2 | ||
233 | if(format == FORMAT_NATIVE) | ||
234 | memset(bitmap, 0, width * height / 4); | ||
235 | #endif | ||
236 | |||
237 | #if LCD_DEPTH > 1 | ||
238 | fb_data *dest = (fb_data *)bitmap; | ||
239 | #endif | ||
240 | |||
165 | /* loop to read rows and put them to buffer */ | 241 | /* loop to read rows and put them to buffer */ |
166 | for (row = 0; row < bitmap_height; row++) { | 242 | for (row = 0; row < height; row++) { |
167 | int bitsel = 1 << ((bitmap_height - row - 1) % 8); | 243 | unsigned char *p; |
168 | int bytesel = bitmap_width * ((bitmap_height - row - 1) / 8); | ||
169 | 244 | ||
170 | /* read one row */ | 245 | /* read one row */ |
171 | ret = read(fd, bmpbuf, PaddedWidth); | 246 | ret = read(fd, bmpbuf, PaddedWidth); |
@@ -173,24 +248,115 @@ int read_bmp_file(char* filename, | |||
173 | DEBUGF("error reading image, read returned: %d expected was: " | 248 | DEBUGF("error reading image, read returned: %d expected was: " |
174 | "%d\n", ret, PaddedWidth); | 249 | "%d\n", ret, PaddedWidth); |
175 | close(fd); | 250 | close(fd); |
176 | return -8; | 251 | return -9; |
177 | } | 252 | } |
178 | 253 | ||
179 | /* loop though the pixels in this line. */ | 254 | switch(depth) { |
180 | for (col = 0; col < bitmap_width; col++) { | 255 | case 1: |
181 | ret = (bmpbuf[col/8] & (1 << (7 - (col % 8)))) != 0; | 256 | #if LCD_DEPTH > 1 |
182 | if (ret == 1) | 257 | if(format == FORMAT_MONO) { |
183 | bitmap[bytesel + col] &= ~bitsel; | 258 | #endif |
184 | else | 259 | /* Mono -> Mono */ |
185 | bitmap[bytesel + col] |= bitsel; | 260 | for (col = 0; col < width; col++) { |
261 | ret = getpix(col, bmpbuf) ^ invert_pixel; | ||
262 | if (ret == 1) { | ||
263 | bitmap[width * ((height - row - 1) / 8) + col] | ||
264 | &= ~ 1 << ((height - row - 1) % 8); | ||
265 | } else { | ||
266 | bitmap[width * ((height - row - 1) / 8) + col] | ||
267 | |= 1 << ((height - row - 1) % 8); | ||
268 | } | ||
269 | } | ||
270 | #if LCD_DEPTH == 2 | ||
271 | } else { | ||
272 | /* Mono -> 2gray (iriver H1xx) */ | ||
273 | for (col = 0; col < width; col++) { | ||
274 | ret = brightness(palette[getpix(col, bmpbuf)]); | ||
275 | |||
276 | if (ret > 96) { | ||
277 | bitmap[width * ((height - row - 1) / 8) + col] | ||
278 | &= ~ 1 << ((height - row - 1) % 8); | ||
279 | } else { | ||
280 | bitmap[width * ((height - row - 1) / 8) + col] | ||
281 | |= 1 << ((height - row - 1) % 8); | ||
282 | } | ||
283 | } | ||
284 | } | ||
285 | #elif LCD_DEPTH == 16 | ||
286 | } else { | ||
287 | /* Mono -> RGB16 */ | ||
288 | for (col = 0; col < width; col++) { | ||
289 | ret = getpix(col, bmpbuf); | ||
290 | unsigned short rgb = (((palette[ret].red >> 3) << 11) | | ||
291 | ((palette[ret].green >> 2) << 5) | | ||
292 | ((palette[ret].blue >> 3))); | ||
293 | dest[width * (height - row - 1) + col] = rgb; | ||
294 | } | ||
295 | } | ||
296 | #endif | ||
297 | break; | ||
298 | |||
299 | case 24: | ||
300 | p = bmpbuf; | ||
301 | #if LCD_DEPTH > 1 | ||
302 | if(format == FORMAT_MONO) { | ||
303 | #endif | ||
304 | /* RGB24 -> mono */ | ||
305 | for (col = 0; col < width; col++) { | ||
306 | struct rgb_quad rgb; | ||
307 | rgb.red = p[2]; | ||
308 | rgb.green = p[1]; | ||
309 | rgb.blue = p[0]; | ||
310 | ret = brightness(rgb); | ||
311 | if (ret > 96) { | ||
312 | bitmap[width * ((height - row - 1) / 8) + col] | ||
313 | &= ~ 1 << ((height - row - 1) % 8); | ||
314 | } else { | ||
315 | bitmap[width * ((height - row - 1) / 8) + col] | ||
316 | |= 1 << ((height - row - 1) % 8); | ||
317 | } | ||
318 | p += 3; | ||
319 | } | ||
320 | #if LCD_DEPTH == 2 | ||
321 | } else { | ||
322 | /* RGB24 -> 2gray (iriver H1xx) */ | ||
323 | for (col = 0; col < width; col++) { | ||
324 | struct rgb_quad rgb; | ||
325 | rgb.red = p[2]; | ||
326 | rgb.green = p[1]; | ||
327 | rgb.blue = p[0]; | ||
328 | ret = brightness(rgb); | ||
329 | |||
330 | dest[((height - row - 1)/4) * width + col] |= | ||
331 | (~ret & 0xC0) >> (2 * (~(height - row - 1) & 3)); | ||
332 | p += 3; | ||
333 | } | ||
334 | } | ||
335 | #elif LCD_DEPTH == 16 | ||
336 | } else { | ||
337 | /* RGB24 -> RGB16 */ | ||
338 | for (col = 0; col < width; col++) { | ||
339 | unsigned short rgb = (((p[2] >> 3) << 11) | | ||
340 | ((p[1] >> 2) << 5) | | ||
341 | ((p[0] >> 3))); | ||
342 | dest[width * (height - row - 1) + col] = rgb; | ||
343 | p += 3; | ||
344 | } | ||
345 | } | ||
346 | #endif | ||
347 | break; | ||
186 | } | 348 | } |
187 | } | 349 | } |
188 | 350 | ||
189 | close(fd); | 351 | close(fd); |
190 | 352 | ||
191 | /* returning image size: */ | 353 | /* returning image size: */ |
192 | *get_width = bitmap_width; | 354 | bm->width = width; |
193 | *get_height = bitmap_height; | 355 | bm->height = height; |
356 | #if LCD_DEPTH > 1 | ||
357 | bm->format = format; | ||
358 | #endif | ||
194 | 359 | ||
195 | return (PaddedHeight * bitmap_width); /* return the used buffer size. */ | 360 | DEBUGF("totalsize: %d\n", totalsize); |
361 | return totalsize; /* return the used buffer size. */ | ||
196 | } | 362 | } |
diff --git a/apps/recorder/bmp.h b/apps/recorder/bmp.h index 5414ad893a..3bd8da74b7 100644 --- a/apps/recorder/bmp.h +++ b/apps/recorder/bmp.h | |||
@@ -16,6 +16,12 @@ | |||
16 | * KIND, either express or implied. | 16 | * KIND, either express or implied. |
17 | * | 17 | * |
18 | ****************************************************************************/ | 18 | ****************************************************************************/ |
19 | #ifndef _BMP_H_ | ||
20 | #define _BMP_H_ | ||
21 | |||
22 | #include "config.h" | ||
23 | #include "lcd.h" | ||
24 | |||
19 | /********************************************************************* | 25 | /********************************************************************* |
20 | * read_bmp_file() | 26 | * read_bmp_file() |
21 | * | 27 | * |
@@ -24,7 +30,7 @@ | |||
24 | * | 30 | * |
25 | **********************************************/ | 31 | **********************************************/ |
26 | int read_bmp_file(char* filename, | 32 | int read_bmp_file(char* filename, |
27 | int *get_width, /* in pixels */ | 33 | struct bitmap *bm, |
28 | int *get_height, /* in pixels */ | 34 | int maxsize, |
29 | char *bitmap, | 35 | int format); |
30 | int maxsize);/* Maximum amount of bytes to write to bitmap */ | 36 | #endif |