diff options
-rw-r--r-- | apps/recorder/bmp.c | 677 |
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. |
25 | 2006-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 */ |
47 | struct Fileheader { | 52 | struct 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 | ||
66 | struct rgb_quad { /* Little endian */ | 71 | union 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 */ |
74 | static uint16_t readshort(uint16_t *value) { | 82 | static 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 | ||
79 | static 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) | | 90 | static 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 | ||
85 | unsigned char brightness(struct rgb_quad color) | 110 | /* little endian functions */ |
111 | static 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?) */ | 117 | static inline uint32_t readlong(uint32_t *value) |
92 | inline 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 | 124 | static inline unsigned brightness(union rgb_union color) |
100 | /* 24 -> lcd depth dither */ | ||
101 | static 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 | *****************************************************************************/ |
140 | int read_bmp_file(char* filename, | 136 | int 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 | |||
491 | DEBUGF("totalsize: %d\n", totalsize); | ||
492 | return totalsize; /* return the used buffer size. */ | 495 | return totalsize; /* return the used buffer size. */ |
493 | } | 496 | } |