Iriver: Another grayscale bmp loader bug fixed: clear the right amount of data, to...
[kugel-rb.git] / apps / recorder / bmp.c
blob1d4d8147b1056026506592e6f3ffa27ae8b16d96
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
21 2005-04-16 Tomas Salfischberger:
22 - New BMP loader function, based on the old one (borrowed a lot of
23 calculations and checks there.)
24 - Conversion part needs some optimization, doing unneeded calulations now.
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include "debug.h"
31 #include "lcd.h"
32 #include "file.h"
33 #include "config.h"
34 #include "bmp.h"
35 #include "lcd.h"
37 #ifdef __GNUC__
38 #define STRUCT_PACKED __attribute__((packed))
39 #else
40 #define STRUCT_PACKED
41 #pragma pack (push, 2)
42 #endif
44 /* Struct from original code. */
45 struct Fileheader {
46 unsigned short Type; /* signature - 'BM' */
47 unsigned long Size; /* file size in bytes */
48 unsigned short Reserved1; /* 0 */
49 unsigned short Reserved2; /* 0 */
50 unsigned long OffBits; /* offset to bitmap */
51 unsigned long StructSize; /* size of this struct (40) */
52 unsigned long Width; /* bmap width in pixels */
53 unsigned long Height; /* bmap height in pixels */
54 unsigned short Planes; /* num planes - always 1 */
55 unsigned short BitCount; /* bits per pixel */
56 unsigned long Compression; /* compression flag */
57 unsigned long SizeImage; /* image size in bytes */
58 long XPelsPerMeter; /* horz resolution */
59 long YPelsPerMeter; /* vert resolution */
60 unsigned long ClrUsed; /* 0 -> color table size */
61 unsigned long ClrImportant; /* important color count */
62 } STRUCT_PACKED;
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;
71 /* big endian functions */
72 static short readshort(short *value) {
73 unsigned char* bytes = (unsigned char*) value;
74 return bytes[0] | (bytes[1] << 8);
77 static long readlong(long *value) {
78 unsigned char* bytes = (unsigned char*) value;
79 return (long)bytes[0] | ((long)bytes[1] << 8) |
80 ((long)bytes[2] << 16) | ((long)bytes[3] << 24);
83 unsigned char brightness(struct rgb_quad color)
85 return (3 * (unsigned int)color.red + 6 * (unsigned int)color.green
86 + (unsigned int)color.blue) / 10;
89 /* Function to get a pixel from a line. (Tomas: maybe a better way?) */
90 inline int getpix(int px, unsigned char *bmpbuf) {
91 int a = (px / 8);
92 int b = (7 - (px % 8));
94 return (bmpbuf[a] & (1 << b)) != 0;
98 /******************************************************************************
99 * read_bmp_file()
101 * Reads a monochrome BMP file and puts the data in rockbox format in *bitmap.
103 *****************************************************************************/
104 int read_bmp_file(char* filename,
105 struct bitmap *bm,
106 int maxsize,
107 int format)
109 struct Fileheader fh;
110 int width, height, PaddedWidth, PaddedHeight;
111 int fd, row, col, ret;
112 struct rgb_quad palette[256];
113 int invert_pixel = 0;
114 int numcolors;
115 int depth;
116 int totalsize;
117 char *bitmap = bm->data;
119 unsigned char bmpbuf[LCD_WIDTH*sizeof(struct rgb_quad)]; /* Buffer for one line */
121 #if LCD_DEPTH == 1
122 (void)format;
123 #else
124 bool transparent;
126 if(format & FORMAT_TRANSPARENT) {
127 transparent = true;
128 format &= ~FORMAT_TRANSPARENT;
130 #endif
133 fd = open(filename, O_RDONLY);
135 /* Exit if file opening failed */
136 if (fd < 0) {
137 DEBUGF("error - can't open '%s' open returned: %d\n", filename, fd);
138 return (fd * 10) - 1;
141 /* read fileheader */
142 ret = read(fd, &fh, sizeof(struct Fileheader));
143 if(ret < 0) {
144 close(fd);
145 return (ret * 10 - 2);
148 if(ret != sizeof(struct Fileheader)) {
149 DEBUGF("error - can't read Fileheader structure.");
150 close(fd);
151 return -3;
154 /* Exit if too wide */
155 if (readlong(&fh.Width) > LCD_WIDTH) {
156 DEBUGF("error - Bitmap is too wide (%d pixels, max is %d)\n",
157 readlong(&fh.Width), LCD_WIDTH);
158 close(fd);
159 return -5;
162 /* Exit if too high */
163 if (readlong(&fh.Height) > LCD_HEIGHT) {
164 DEBUGF("error - Bitmap is too high (%d pixels, max is %d)\n",
165 readlong(&fh.Height), LCD_HEIGHT);
166 close(fd);
167 return -6;
170 /* Calculate image size */
171 height = readlong(&fh.Height);
172 width = readlong(&fh.Width);
173 depth = readshort(&fh.BitCount);
175 /* 4-byte boundary aligned */
176 PaddedWidth = ((width * depth + 31) / 8) & ~3;
178 #if LCD_DEPTH > 1
179 if(format == FORMAT_ANY) {
180 if(depth == 1)
181 format = FORMAT_MONO;
182 else
183 format = FORMAT_NATIVE;
185 #endif
187 /* PaddedHeight is for rockbox format. */
188 if(format == FORMAT_MONO) {
189 PaddedHeight = (height + 7) / 8;
190 totalsize = PaddedHeight * width;
191 } else {
192 #if LCD_DEPTH == 2
193 PaddedHeight = (height + 3) / 4;
194 #else
195 PaddedHeight = height;
196 #endif
197 totalsize = PaddedHeight * width * sizeof(fb_data);
200 /* Check if this fits the buffer */
202 if (totalsize > maxsize) {
203 DEBUGF("error - Bitmap is too large to fit the supplied buffer: "
204 "%d bytes.\n", (PaddedHeight * width));
205 close(fd);
206 return -7;
209 if (depth <= 8)
211 numcolors = readlong(&fh.ClrUsed);
212 if (numcolors == 0)
213 numcolors = 1 << depth;
215 if(read(fd, palette, numcolors * sizeof(struct rgb_quad))
216 != numcolors * (int)sizeof(struct rgb_quad))
218 DEBUGF("error - Can't read bitmap's color palette\n");
219 close(fd);
220 return -8;
224 /* Use the darker palette color as foreground on mono bitmaps */
225 if(readshort(&fh.BitCount) == 1) {
226 if(brightness(palette[0]) > brightness(palette[1]))
227 invert_pixel = 1;
230 /* Search to the beginning of the image data */
231 lseek(fd, (off_t)readlong(&fh.OffBits), SEEK_SET);
233 #if LCD_DEPTH == 2
234 if(format == FORMAT_NATIVE)
235 memset(bitmap, 0, totalsize);
236 #endif
238 #if LCD_DEPTH > 1
239 fb_data *dest = (fb_data *)bitmap;
240 #endif
242 /* loop to read rows and put them to buffer */
243 for (row = 0; row < height; row++) {
244 unsigned char *p;
246 /* read one row */
247 ret = read(fd, bmpbuf, PaddedWidth);
248 if (ret != PaddedWidth) {
249 DEBUGF("error reading image, read returned: %d expected was: "
250 "%d\n", ret, PaddedWidth);
251 close(fd);
252 return -9;
255 switch(depth) {
256 case 1:
257 #if LCD_DEPTH > 1
258 if(format == FORMAT_MONO) {
259 #endif
260 /* Mono -> Mono */
261 for (col = 0; col < width; col++) {
262 ret = getpix(col, bmpbuf) ^ invert_pixel;
263 if (ret == 1) {
264 bitmap[width * ((height - row - 1) / 8) + col]
265 &= ~ 1 << ((height - row - 1) % 8);
266 } else {
267 bitmap[width * ((height - row - 1) / 8) + col]
268 |= 1 << ((height - row - 1) % 8);
271 #if LCD_DEPTH == 2
272 } else {
273 /* Mono -> 2gray (iriver H1xx) */
274 for (col = 0; col < width; col++) {
275 ret = brightness(palette[getpix(col, bmpbuf)]);
277 if (ret > 96) {
278 bitmap[width * ((height - row - 1) / 8) + col]
279 &= ~ 1 << ((height - row - 1) % 8);
280 } else {
281 bitmap[width * ((height - row - 1) / 8) + col]
282 |= 1 << ((height - row - 1) % 8);
286 #elif LCD_DEPTH == 16
287 } else {
288 /* Mono -> RGB16 */
289 for (col = 0; col < width; col++) {
290 ret = getpix(col, bmpbuf);
291 unsigned short rgb = (((palette[ret].red >> 3) << 11) |
292 ((palette[ret].green >> 2) << 5) |
293 ((palette[ret].blue >> 3)));
294 dest[width * (height - row - 1) + col] = rgb;
297 #endif
298 break;
300 case 24:
301 p = bmpbuf;
302 #if LCD_DEPTH > 1
303 if(format == FORMAT_MONO) {
304 #endif
305 /* RGB24 -> mono */
306 for (col = 0; col < width; col++) {
307 struct rgb_quad rgb;
308 rgb.red = p[2];
309 rgb.green = p[1];
310 rgb.blue = p[0];
311 ret = brightness(rgb);
312 if (ret > 96) {
313 bitmap[width * ((height - row - 1) / 8) + col]
314 &= ~ 1 << ((height - row - 1) % 8);
315 } else {
316 bitmap[width * ((height - row - 1) / 8) + col]
317 |= 1 << ((height - row - 1) % 8);
319 p += 3;
321 #if LCD_DEPTH == 2
322 } else {
323 /* RGB24 -> 2gray (iriver H1xx) */
324 for (col = 0; col < width; col++) {
325 struct rgb_quad rgb;
326 rgb.red = p[2];
327 rgb.green = p[1];
328 rgb.blue = p[0];
329 ret = brightness(rgb);
331 dest[((height - row - 1)/4) * width + col] |=
332 (~ret & 0xC0) >> (2 * (~(height - row - 1) & 3));
333 p += 3;
336 #elif LCD_DEPTH == 16
337 } else {
338 /* RGB24 -> RGB16 */
339 for (col = 0; col < width; col++) {
340 unsigned short rgb = LCD_RGBPACK(p[2],p[1],p[0]);
341 dest[width * (height - row - 1) + col] = rgb;
342 p += 3;
345 #endif
346 break;
350 close(fd);
352 /* returning image size: */
353 bm->width = width;
354 bm->height = height;
355 #if LCD_DEPTH > 1
356 bm->format = format;
357 #endif
359 DEBUGF("totalsize: %d\n", totalsize);
360 return totalsize; /* return the used buffer size. */