summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/recorder/bmp.c677
1 files changed, 340 insertions, 337 deletions
diff --git a/apps/recorder/bmp.c b/apps/recorder/bmp.c
index ab0b8bf721..8fe7663286 100644
--- a/apps/recorder/bmp.c
+++ b/apps/recorder/bmp.c
@@ -22,6 +22,11 @@
22 - New BMP loader function, based on the old one (borrowed a lot of 22 - New BMP loader function, based on the old one (borrowed a lot of
23 calculations and checks there.) 23 calculations and checks there.)
24 - Conversion part needs some optimization, doing unneeded calulations now. 24 - Conversion part needs some optimization, doing unneeded calulations now.
252006-11-18 Jens Arnold: complete rework
26 - All canonical formats supported now (1, 4, 8, 15/16, 24 and 32 bit)
27 - better protection against malformed / non-standard BMPs
28 - code heavily optimised for both size and speed
29 - dithering for 2 bit targets
25*/ 30*/
26 31
27#include <stdio.h> 32#include <stdio.h>
@@ -43,98 +48,89 @@
43#pragma pack (push, 2) 48#pragma pack (push, 2)
44#endif 49#endif
45 50
46/* Struct from original code. */ 51/* BMP header structure */
47struct Fileheader { 52struct bmp_header {
48 uint16_t Type; /* signature - 'BM' */ 53 uint16_t type; /* signature - 'BM' */
49 uint32_t Size; /* file size in bytes */ 54 uint32_t size; /* file size in bytes */
50 uint16_t Reserved1; /* 0 */ 55 uint16_t reserved1; /* 0 */
51 uint16_t Reserved2; /* 0 */ 56 uint16_t reserved2; /* 0 */
52 uint32_t OffBits; /* offset to bitmap */ 57 uint32_t off_bits; /* offset to bitmap */
53 uint32_t StructSize; /* size of this struct (40) */ 58 uint32_t struct_size; /* size of this struct (40) */
54 uint32_t Width; /* bmap width in pixels */ 59 uint32_t width; /* bmap width in pixels */
55 uint32_t Height; /* bmap height in pixels */ 60 uint32_t height; /* bmap height in pixels */
56 uint16_t Planes; /* num planes - always 1 */ 61 uint16_t planes; /* num planes - always 1 */
57 uint16_t BitCount; /* bits per pixel */ 62 uint16_t bit_count; /* bits per pixel */
58 uint32_t Compression; /* compression flag */ 63 uint32_t compression; /* compression flag */
59 uint32_t SizeImage; /* image size in bytes */ 64 uint32_t size_image; /* image size in bytes */
60 int32_t XPelsPerMeter; /* horz resolution */ 65 int32_t x_pels_per_meter; /* horz resolution */
61 int32_t YPelsPerMeter; /* vert resolution */ 66 int32_t y_pels_per_meter; /* vert resolution */
62 uint32_t ClrUsed; /* 0 -> color table size */ 67 uint32_t clr_used; /* 0 -> color table size */
63 uint32_t ClrImportant; /* important color count */ 68 uint32_t clr_important; /* important color count */
64} STRUCT_PACKED; 69} STRUCT_PACKED;
65 70
66struct rgb_quad { /* Little endian */ 71union rgb_union {
67 unsigned char blue; 72 struct { /* Little endian */
68 unsigned char green; 73 unsigned char blue;
69 unsigned char red; 74 unsigned char green;
70 unsigned char reserved; 75 unsigned char red;
71} STRUCT_PACKED; 76 unsigned char reserved;
77 };
78 uint32_t raw;
79};
72 80
73/* big endian functions */ 81/* masks for supported BI_BITFIELDS encodings (16/32 bit), little endian */
74static uint16_t readshort(uint16_t *value) { 82static const unsigned char bitfields[3][12] = {
75 unsigned char* bytes = (unsigned char*) value; 83 { 0x00,0x7c,0x00,0, 0xe0,0x03,0x00,0, 0x1f,0x00,0x00,0 }, /* 15 bit */
76 return bytes[0] | (bytes[1] << 8); 84 { 0x00,0xf8,0x00,0, 0xe0,0x07,0x00,0, 0x1f,0x00,0x00,0 }, /* 16 bit */
77} 85 { 0x00,0x00,0xff,0, 0x00,0xff,0x00,0, 0xff,0x00,0x00,0 }, /* 32 bit */
86};
78 87
79static uint32_t readlong(uint32_t *value) { 88#if LCD_DEPTH > 1
80 unsigned char* bytes = (unsigned char*) value; 89/* canonical ordered dither matrix */
81 return (long)bytes[0] | ((long)bytes[1] << 8) | 90static const unsigned char dither_matrix[16][16] = {
82 ((long)bytes[2] << 16) | ((long)bytes[3] << 24); 91 { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 },
83} 92 { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 },
93 { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 },
94 { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 },
95 { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 },
96 { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 },
97 { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 },
98 { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 },
99 { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 },
100 { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 },
101 { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 },
102 { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 },
103 { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 },
104 { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 },
105 { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 },
106 { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 }
107};
108#endif
84 109
85unsigned char brightness(struct rgb_quad color) 110/* little endian functions */
111static inline unsigned readshort(uint16_t *value)
86{ 112{
87 return (3 * (unsigned int)color.red + 6 * (unsigned int)color.green 113 unsigned char* bytes = (unsigned char*) value;
88 + (unsigned int)color.blue) / 10; 114 return (unsigned)bytes[0] | ((unsigned)bytes[1] << 8);
89} 115}
90 116
91/* Function to get a pixel from a line. (Tomas: maybe a better way?) */ 117static inline uint32_t readlong(uint32_t *value)
92inline int getpix(int px, unsigned char *bmpbuf) { 118{
93 int a = (px / 8); 119 unsigned char* bytes = (unsigned char*) value;
94 int b = (7 - (px % 8)); 120 return (uint32_t)bytes[0] | ((uint32_t)bytes[1] << 8) |
95 121 ((uint32_t)bytes[2] << 16) | ((uint32_t)bytes[3] << 24);
96 return (bmpbuf[a] & (1 << b)) != 0;
97} 122}
98 123
99#if LCD_DEPTH == 16 124static inline unsigned brightness(union rgb_union color)
100/* 24 -> lcd depth dither */
101static fb_data dither_24_to_lcd(struct rgb_quad rgb, int row, int col)
102{ 125{
103 static const unsigned char dith[][16] = 126 return (3 * (unsigned)color.red + 6 * (unsigned)color.green
104 { 127 + (unsigned)color.blue) / 10;
105 { /* 5 bit */
106 0,6,1,7,
107 4,2,5,3,
108 1,7,0,6,
109 5,3,4,2
110 },
111 { /* 6 bit */
112 0,3,0,3,
113 2,1,2,1,
114 0,3,0,3,
115 2,1,2,1
116 },
117 };
118
119 const unsigned elm = (row & 3) + ((col & 3) << 2);
120 unsigned b, g, r;
121
122 b = ((unsigned)rgb.blue + dith[0][elm]) >> (8-LCD_BLUE_BITS);
123 if (b > LCD_MAX_BLUE) b = LCD_MAX_BLUE;
124 g = ((unsigned)rgb.green + dith[1][elm]) >> (8-LCD_GREEN_BITS);
125 if (g > LCD_MAX_GREEN) g = LCD_MAX_GREEN;
126 r = ((unsigned)rgb.red + dith[0][elm]) >> (8-LCD_RED_BITS);
127 if (r > LCD_MAX_RED) r = LCD_MAX_RED;
128
129 return LCD_RGBPACK_LCD(r, g, b);
130} 128}
131#endif /* LCD_DEPTH == 16 */
132
133 129
134/****************************************************************************** 130/******************************************************************************
135 * read_bmp_file() 131 * read_bmp_file()
136 * 132 *
137 * Reads a monochrome BMP file and puts the data in rockbox format in *bitmap. 133 * Reads a BMP file and puts the data in rockbox format in *bitmap.
138 * 134 *
139 *****************************************************************************/ 135 *****************************************************************************/
140int read_bmp_file(char* filename, 136int read_bmp_file(char* filename,
@@ -142,352 +138,359 @@ int read_bmp_file(char* filename,
142 int maxsize, 138 int maxsize,
143 int format) 139 int format)
144{ 140{
145 struct Fileheader fh; 141 struct bmp_header bmph;
146 int width, height, PaddedWidth, PaddedHeight, dst_width; 142 int width, height, padded_width;
143 int dst_height, dst_width;
147 int fd, row, col, ret; 144 int fd, row, col, ret;
148 struct rgb_quad palette[256]; 145 int depth, numcolors, compression, totalsize;
149 int invert_pixel = 0; 146
150 int numcolors; 147 unsigned char *bitmap = bm->data;
151 int depth; 148 uint32_t bmpbuf[LCD_WIDTH]; /* Buffer for one line */
152 int totalsize; 149 uint32_t palette[256];
153 char *bitmap = bm->data; 150#if LCD_DEPTH > 1
154 unsigned char bmpbuf[LCD_WIDTH*sizeof(struct rgb_quad)]; /* Buffer for one line */
155#if LCD_DEPTH != 1
156 bool transparent = false; 151 bool transparent = false;
157#if LCD_DEPTH == 16
158 /* Should adapt dithering to all native depths */
159 bool dither = false; 152 bool dither = false;
160 if(format & FORMAT_DITHER) { 153
161 dither = true; 154 if (format & FORMAT_TRANSPARENT) {
162 format &= ~FORMAT_DITHER;
163 }
164#endif
165 if(format & FORMAT_TRANSPARENT) {
166 transparent = true; 155 transparent = true;
167 format &= ~FORMAT_TRANSPARENT; 156 format &= ~FORMAT_TRANSPARENT;
168 } 157 }
158 if (format & FORMAT_DITHER) {
159 dither = true;
160 format &= ~FORMAT_DITHER;
161 }
169#else 162#else
170 format = FORMAT_MONO; 163
164 (void)format;
171#endif 165#endif
172 166
173 fd = open(filename, O_RDONLY); 167 fd = open(filename, O_RDONLY);
174 168
175 /* Exit if file opening failed */ 169 /* Exit if file opening failed */
176 if (fd < 0) { 170 if (fd < 0) {
177 DEBUGF("error - can't open '%s' open returned: %d\n", filename, fd); 171 DEBUGF("read_bmp_file: can't open '%s', rc: %d\n", filename, fd);
178 return (fd * 10) - 1; 172 return fd * 10 - 1;
179 } 173 }
180 174
181 /* read fileheader */ 175 /* read fileheader */
182 ret = read(fd, &fh, sizeof(struct Fileheader)); 176 ret = read(fd, &bmph, sizeof(struct bmp_header));
183 if(ret < 0) { 177 if (ret < 0) {
184 close(fd); 178 close(fd);
185 return (ret * 10 - 2); 179 return ret * 10 - 2;
186 } 180 }
187 181
188 if(ret != sizeof(struct Fileheader)) { 182 if (ret != sizeof(struct bmp_header)) {
189 DEBUGF("error - can't read Fileheader structure."); 183 DEBUGF("read_bmp_file: can't read BMP header.");
190 close(fd); 184 close(fd);
191 return -3; 185 return -3;
192 } 186 }
193 187
194 /* Exit if too wide */ 188 width = readlong(&bmph.width);
195 if (readlong(&fh.Width) > LCD_WIDTH) { 189 if (width > LCD_WIDTH) {
196 DEBUGF("error - Bitmap is too wide (%d pixels, max is %d)\n", 190 DEBUGF("read_bmp_file: Bitmap too wide (%d pixels, max is %d)\n",
197 readlong(&fh.Width), LCD_WIDTH); 191 width, LCD_WIDTH);
198 close(fd); 192 close(fd);
199 return -5; 193 return -4;
200 } 194 }
201 195
202 /* Exit if too high */ 196 height = readlong(&bmph.height);
203 if (readlong(&fh.Height) > LCD_HEIGHT) { 197 if (height > LCD_HEIGHT) {
204 DEBUGF("error - Bitmap is too high (%d pixels, max is %d)\n", 198 DEBUGF("read_bmp_file: Bitmap too high (%d pixels, max is %d)\n",
205 readlong(&fh.Height), LCD_HEIGHT); 199 height, LCD_HEIGHT);
206 close(fd); 200 close(fd);
207 return -6; 201 return -5;
208 } 202 }
209 203
210 /* Calculate image size */ 204 depth = readshort(&bmph.bit_count);
211 height = readlong(&fh.Height); 205 padded_width = ((width * depth + 31) / 8) & ~3; /* 4-byte boundary aligned */
212 width = readlong(&fh.Width);
213 depth = readshort(&fh.BitCount);
214
215 /* 4-byte boundary aligned */
216 PaddedWidth = ((width * depth + 31) / 8) & ~3;
217 206
218#if LCD_DEPTH > 1 207#if LCD_DEPTH > 1
219 if(format == FORMAT_ANY) { 208 if (format == FORMAT_ANY) {
220 if(depth == 1) 209 if (depth == 1)
221 format = FORMAT_MONO; 210 format = FORMAT_MONO;
222 else 211 else
223 format = FORMAT_NATIVE; 212 format = FORMAT_NATIVE;
224 } 213 }
214 bm->format = format;
225#endif 215#endif
216 /* returning image size */
217 bm->width = width;
218 bm->height = height;
226 219
227 /* PaddedHeight is for rockbox format. */ 220#if LCD_DEPTH > 1
228 if(format == FORMAT_MONO) { 221 if (format == FORMAT_NATIVE) {
229 PaddedHeight = (height + 7) / 8;
230 dst_width = width;
231 totalsize = PaddedHeight * dst_width;
232 } else {
233#if LCD_DEPTH == 2 222#if LCD_DEPTH == 2
234#if LCD_PIXELFORMAT == VERTICAL_PACKING 223#if LCD_PIXELFORMAT == VERTICAL_PACKING
235 PaddedHeight = (height + 3) / 4; 224 dst_width = width;
236 dst_width = width; 225 dst_height = (height + 3) / 4;
237#else 226#else /* LCD_PIXELFORMAT == HORIZONTAL_PACKING */
238 PaddedHeight = height; 227 dst_width = (width + 3) / 4;
239 dst_width = (width + 3) / 4; 228 dst_height = height;
240#endif 229#endif /* LCD_PIXELFORMAT */
241#else 230#elif LCD_DEPTH == 16
242 PaddedHeight = height; 231 dst_width = width;
243 dst_width = width; 232 dst_height = height;
244#endif 233#endif /* LCD_DEPTH */
245 totalsize = PaddedHeight * dst_width * sizeof(fb_data); 234 totalsize = dst_width * dst_height * sizeof(fb_data);
235 } else
236#endif /* LCD_DEPTH > 1 */
237 {
238 dst_width = width;
239 dst_height = (height + 7) / 8;
240 totalsize = dst_width * dst_height;
246 } 241 }
247 242
248 /* Check if this fits the buffer */ 243 /* Check if this fits the buffer */
249
250 if (totalsize > maxsize) { 244 if (totalsize > maxsize) {
251 DEBUGF("error - Bitmap is too large to fit the supplied buffer: " 245 DEBUGF("read_bmp_file: Bitmap too large for buffer: "
252 "%d bytes.\n", (PaddedHeight * dst_width)); 246 "%d bytes.\n", totalsize);
253 close(fd); 247 close(fd);
254 return -7; 248 return -6;
255 } 249 }
256 250
257 if (depth <= 8) 251 compression = readlong(&bmph.compression);
258 { 252 if (depth <= 8) {
259 numcolors = readlong(&fh.ClrUsed); 253 numcolors = readlong(&bmph.clr_used);
260 if (numcolors == 0) 254 if (numcolors == 0)
261 numcolors = 1 << depth; 255 numcolors = 1 << depth;
262 256 } else
263 if(read(fd, palette, numcolors * sizeof(struct rgb_quad)) 257 numcolors = (compression == 3) ? 3 : 0;
264 != numcolors * (int)sizeof(struct rgb_quad)) 258
259 if (numcolors > 0 && numcolors <= 256) {
260 if (read(fd, palette, numcolors * sizeof(uint32_t))
261 != numcolors * (int)sizeof(uint32_t))
265 { 262 {
266 DEBUGF("error - Can't read bitmap's color palette\n"); 263 DEBUGF("read_bmp_file: Can't read color palette\n");
267 close(fd); 264 close(fd);
268 return -8; 265 return -7;
269 } 266 }
270 } 267 }
271 268
272 /* Use the darker palette color as foreground on mono bitmaps */ 269 switch (depth) {
273 if(depth == 1) { 270 case 16:
274 if(brightness(palette[0]) < brightness(palette[1])) 271#if LCD_DEPTH >= 16
275 invert_pixel = 1; 272 /* don't dither 16 bit BMP to LCD with same or larger depth */
273 dither = false;
274#endif
275 if (compression == 0) { /* BI_RGB, i.e. 15 bit */
276 depth = 15;
277 break;
278 } /* else fall through */
279
280 case 32:
281 if (compression == 3) { /* BI_BITFIELDS */
282 if (!memcmp(palette, bitfields[0], 12)) { /* 15 bit */
283 depth = 15;
284 break;
285 }
286 if (!memcmp(palette, bitfields[1], 12) /* 16 bit */
287 || !memcmp(palette, bitfields[2], 12)) /* 32 bit */
288 {
289 break;
290 }
291 } /* else fall through */
292
293 default:
294 if (compression != 0) { /* not BI_RGB */
295 DEBUGF("read_bmp_file: Unsupported compression (type %d)\n",
296 compression);
297 close(fd);
298 return -8;
299 }
300 break;
276 } 301 }
277 302
278 /* Search to the beginning of the image data */ 303 /* Search to the beginning of the image data */
279 lseek(fd, (off_t)readlong(&fh.OffBits), SEEK_SET); 304 lseek(fd, (off_t)readlong(&bmph.off_bits), SEEK_SET);
280
281#if LCD_DEPTH == 2
282 if(format == FORMAT_NATIVE)
283 memset(bitmap, 0, totalsize);
284#endif
285 305
286#if LCD_DEPTH > 1 306#if LCD_DEPTH >= 8
287 fb_data *dest = (fb_data *)bitmap; 307 if (format == FORMAT_MONO)
288#endif 308#endif
309 memset(bitmap, 0, totalsize);
289 310
290 /* loop to read rows and put them to buffer */ 311 /* loop to read rows and put them to buffer */
291 for (row = 0; row < height; row++) { 312 for (row = height - 1; row >= 0; row--) {
313 unsigned data, mask;
292 unsigned char *p; 314 unsigned char *p;
315 uint16_t *p2;
316 uint32_t *rp;
317 union rgb_union *qp;
318 union rgb_union q0, q1;
293 319
294 /* read one row */ 320 /* read one row */
295 ret = read(fd, bmpbuf, PaddedWidth); 321 ret = read(fd, bmpbuf, padded_width);
296 if (ret != PaddedWidth) { 322 if (ret != padded_width) {
297 DEBUGF("error reading image, read returned: %d expected was: " 323 DEBUGF("read_bmp_file: error reading image, read returned: %d "
298 "%d\n", ret, PaddedWidth); 324 "expected: %d\n", ret, padded_width);
299 close(fd); 325 close(fd);
300 return -9; 326 return -9;
301 } 327 }
302 328
303 switch(depth) { 329 /* convert whole line in-place to XRGB8888 (little endian) */
304 case 1: 330 rp = bmpbuf + width;
305#if LCD_DEPTH > 1 331 switch (depth) {
306 if(format == FORMAT_MONO) { 332 case 1:
307#endif 333 q0.raw = palette[0];
308 /* Mono -> Mono */ 334 q1.raw = palette[1];
309 for (col = 0; col < width; col++) { 335 p = (unsigned char*)bmpbuf + (width + 7) / 8;
310 ret = getpix(col, bmpbuf) ^ invert_pixel; 336 mask = 0x80 >> ((width + 7) & 7);
311 if (ret) { 337 while (p > (unsigned char*)bmpbuf) {
312 bitmap[width * ((height - row - 1) / 8) + col] 338 data = *(--p);
313 |= 1 << ((height - row - 1) % 8); 339 for (; mask <= 0x80; mask <<= 1)
314 } else { 340 *(--rp) = (data & mask) ? q1.raw : q0.raw;
315 bitmap[width * ((height - row - 1) / 8) + col] 341 mask = 0x01;
316 &= ~ 1 << ((height - row - 1) % 8);
317 }
318 }
319#if LCD_DEPTH == 2
320#if LCD_PIXELFORMAT == VERTICAL_PACKING
321 } else {
322 /* Mono -> 2gray (iriver H1xx) */
323 for (col = 0; col < width; col++) {
324 ret = getpix(col, bmpbuf) ^ invert_pixel;
325
326 if (ret)
327 dest[((height - row - 1)/4) * width + col] |=
328 0xC0 >> (2 * (~(height - row - 1) & 3));
329 }
330 } 342 }
331#else
332 } else {
333 /* Mono -> 2gray (ipod) */
334 for (col = 0; col < width; col++) {
335 ret = getpix(col, bmpbuf) ^ invert_pixel;
336
337 if (ret)
338 dest[(height - row - 1) * dst_width + col/4] |=
339 0xC0 >> (2 * (col & 3));
340 }
341 }
342#endif
343#elif LCD_DEPTH == 16
344 } else {
345 /* Mono -> RGB16 */
346 for (col = 0; col < width; col++) {
347 ret = getpix(col, bmpbuf);
348 unsigned short rgb16 = LCD_RGBPACK(palette[ret].red,
349 palette[ret].green,
350 palette[ret].blue);
351 dest[width * (height - row - 1) + col] = rgb16;
352 }
353 }
354#endif
355 break; 343 break;
356 344
345 case 4:
346 if (width & 1)
347 rp++;
348 p = (unsigned char*)bmpbuf + (width + 1) / 2;
349 while (p > (unsigned char*)bmpbuf) {
350 data = *(--p);
351 *(--rp) = palette[data & 0x0f];
352 *(--rp) = palette[data >> 4];
353 }
354 break;
357 355
358 case 8: 356 case 8:
359 p = bmpbuf; 357 p = (unsigned char*)bmpbuf + width;
360#if LCD_DEPTH > 1 358 while (p > (unsigned char*)bmpbuf)
361 if(format == FORMAT_MONO) { 359 *(--rp) = palette[*(--p)];
362#endif 360 break;
363 /* 8-bit RGB24 palette -> mono */ 361
364 for (col = 0; col < width; col++) { 362 case 15:
365 struct rgb_quad rgb = palette[*p]; 363 case 16:
366 ret = brightness(rgb); 364 p2 = (uint16_t *)bmpbuf + width;
367 if (ret > 96) { 365 while (p2 > (uint16_t *)bmpbuf) {
368 bitmap[width * ((height - row - 1) / 8) + col] 366 unsigned component, rgb;
369 &= ~ 1 << ((height - row - 1) % 8); 367
370 } else { 368 data = letoh16(*(--p2));
371 bitmap[width * ((height - row - 1) / 8) + col] 369 /* blue */
372 |= 1 << ((height - row - 1) % 8); 370 component = (data << 3) & 0xf8;
373 } 371#ifdef ROCKBOX_BIG_ENDIAN
374 p++; 372 rgb = (component | (component >> 5)) << 8;
375 } 373 /* green */
376#if LCD_DEPTH == 2 374 data >>= 2;
377#if LCD_PIXELFORMAT == VERTICAL_PACKING 375 if (depth == 15) {
378 } else { 376 component = data & 0xf8;
379 /* 8-bit RGB24 palette -> 2gray (iriver H1xx) */ 377 rgb |= component | (component >> 5);
380 for (col = 0; col < width; col++) { 378 } else {
381 struct rgb_quad rgb = palette[*p]; 379 data >>= 1;
382 ret = brightness(rgb); 380 component = data & 0xfc;
383 381 rgb |= component | (component >> 6);
384 dest[((height - row - 1)/4) * width + col] |=
385 (~ret & 0xC0) >> (2 * (~(height - row - 1) & 3));
386 p++;
387 } 382 }
388 } 383 /* red */
389#else 384 data >>= 5;
390 } else { 385 component = data & 0xf8;
391 /* 8-bit RGB24 palette -> 2gray (ipod) */ 386 rgb = (rgb << 8) | component | (component >> 5);
392 for (col = 0; col < width; col++) { 387 *(--rp) = rgb << 8;
393 struct rgb_quad rgb = palette[*p]; 388#else /* little endian */
394 ret = brightness(rgb); 389 rgb = component | (component >> 5);
395 390 /* green */
396 dest[(height - row - 1) * dst_width + col/4] |= 391 data >>= 2;
397 (~ret & 0xC0) >> (2 * (col & 3)); 392 if (depth == 15) {
398 p++; 393 component = data & 0xf8;
394 rgb |= (component | (component >> 5)) << 8;
395 } else {
396 data >>= 1;
397 component = data & 0xfc;
398 rgb |= (component | (component >> 6)) << 8;
399 } 399 }
400 } 400 /* red */
401 data >>= 5;
402 component = data & 0xf8;
403 rgb |= (component | (component >> 5)) << 16;
404 *(--rp) = rgb;
401#endif 405#endif
402#elif LCD_DEPTH == 16
403 } else {
404 /* 8-bit RGB24 palette -> RGB16 */
405 for (col = 0; col < width; col++, p++) {
406 struct rgb_quad rgb = palette[*p];
407 dest[width * (height - row - 1) + col] = dither ?
408 dither_24_to_lcd(rgb, row, col) :
409 (fb_data)LCD_RGBPACK(rgb.red, rgb.green, rgb.blue);
410 }
411 } 406 }
412#endif
413 break; 407 break;
414 408
415 case 24: 409 case 24:
416 p = bmpbuf; 410 p = (unsigned char*)bmpbuf + 3 * width;
411 while (p > (unsigned char*)bmpbuf) {
412 data = *(--p);
413 data = (data << 8) | *(--p);
414 data = (data << 8) | *(--p);
415 *(--rp) = htole32(data);
416 }
417 break;
418
419 case 32: /* already in desired format */
420 break;
421 }
422
423 /* Convert to destination format */
424 qp = (union rgb_union *)bmpbuf;
417#if LCD_DEPTH > 1 425#if LCD_DEPTH > 1
418 if(format == FORMAT_MONO) { 426 if (format == FORMAT_NATIVE) {
419#endif
420 /* RGB24 -> mono */
421 for (col = 0; col < width; col++) {
422 struct rgb_quad rgb;
423 rgb.red = p[2];
424 rgb.green = p[1];
425 rgb.blue = p[0];
426 ret = brightness(rgb);
427 if (ret > 96) {
428 bitmap[width * ((height - row - 1) / 8) + col]
429 &= ~ 1 << ((height - row - 1) % 8);
430 } else {
431 bitmap[width * ((height - row - 1) / 8) + col]
432 |= 1 << ((height - row - 1) % 8);
433 }
434 p += 3;
435 }
436#if LCD_DEPTH == 2 427#if LCD_DEPTH == 2
437#if LCD_PIXELFORMAT == VERTICAL_PACKING 428#if LCD_PIXELFORMAT == VERTICAL_PACKING
438 } else { 429 /* iriver H1x0 */
439 /* RGB24 -> 2gray (iriver H1xx) */ 430 fb_data *dest = (fb_data *)bitmap + dst_width * (row / 4);
440 for (col = 0; col < width; col++) { 431 int shift = 2 * (row & 3);
441 struct rgb_quad rgb; 432 int delta = 127;
442 rgb.red = p[2]; 433 unsigned bright;
443 rgb.green = p[1]; 434
444 rgb.blue = p[0]; 435 for (col = 0; col < width; col++) {
445 ret = brightness(rgb); 436 if (dither)
446 437 delta = dither_matrix[row & 0xf][col & 0xf];
447 dest[((height - row - 1)/4) * width + col] |= 438 bright = (257 * (3 * brightness(*qp++) + delta)) >> 16;
448 (~ret & 0xC0) >> (2 * (~(height - row - 1) & 3)); 439 *dest++ |= (~bright & 3) << shift;
449 p += 3;
450 }
451 } 440 }
452#else 441#else /* LCD_PIXELFORMAT == HORIZONTAL_PACKING */
453 } else { 442 /* greyscale iPods */
454 /* RGB24 -> 2gray (ipod) */ 443 fb_data *dest = (fb_data *)bitmap + dst_width * row;
455 for (col = 0; col < width; col++) { 444 int shift = 6;
456 struct rgb_quad rgb; 445 int delta = 127;
457 rgb.red = p[2]; 446 unsigned bright;
458 rgb.green = p[1]; 447 unsigned data = 0;
459 rgb.blue = p[0]; 448
460 ret = brightness(rgb); 449 for (col = 0; col < width; col++) {
461 450 if (dither)
462 dest[(height - row - 1) * dst_width + col/4] |= 451 delta = dither_matrix[row & 0xf][col & 0xf];
463 (~ret & 0xC0) >> (2 * (col & 3)); 452 bright = (257 * (3 * brightness(*qp++) + delta)) >> 16;
464 p += 3; 453 data |= (~bright & 3) << shift;
454 shift -= 2;
455 if (shift < 0) {
456 *dest++ = data;
457 data = 0;
458 shift = 6;
465 } 459 }
466 } 460 }
467#endif 461 if (shift < 6)
462 *dest++ = data;
463#endif /* LCD_PIXELFORMAT */
468#elif LCD_DEPTH == 16 464#elif LCD_DEPTH == 16
469 } else { 465 /* iriver h300, colour iPods, X5 */
470 /* RGB24 -> RGB16 */ 466 fb_data *dest = (fb_data *)bitmap + dst_width * row;
471 for (col = 0; col < width; col++, p += 3) { 467 int delta = 127;
472 dest[width * (height - row - 1) + col] = dither ? 468 unsigned r, g, b;
473 dither_24_to_lcd(*(struct rgb_quad *)p, row, col) : 469
474 (fb_data)LCD_RGBPACK(p[2], p[1], p[0]); 470 for (col = 0; col < width; col++) {
475 } 471 if (dither)
472 delta = dither_matrix[row & 0xf][col & 0xf];
473 q0 = *qp++;
474 r = (257 * (31 * q0.red + delta)) >> 16;
475 g = (257 * (63 * q0.green + delta)) >> 16;
476 b = (257 * (31 * q0.blue + delta)) >> 16;
477 *dest++ = LCD_RGBPACK_LCD(r, g, b);
476 } 478 }
477#endif 479#endif /* LCD_DEPTH */
478 break; 480 } else
481#endif /* LCD_DEPTH > 1 */
482 {
483 p = bitmap + dst_width * (row / 8);
484 mask = 1 << (row & 7);
485
486 for (col = 0; col < width; col++, p++)
487 if (brightness(*qp++) < 128)
488 *p |= mask;
479 } 489 }
480 } 490 }
481 491
482 close(fd); 492 close(fd);
483 493
484 /* returning image size: */ 494 DEBUGF("totalsize: %d\n", totalsize);
485 bm->width = width;
486 bm->height = height;
487#if LCD_DEPTH > 1
488 bm->format = format;
489#endif
490
491DEBUGF("totalsize: %d\n", totalsize);
492 return totalsize; /* return the used buffer size. */ 495 return totalsize; /* return the used buffer size. */
493} 496}