rockbox/apps/recorder/bmp.c

206 lines
6.5 KiB
C
Raw Normal View History

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002 by Linus Nielsen Feltzing
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
/*
2005-04-16 Tomas Salfischberger:
- New BMP loader function, based on the old one (borrowed a lot of
calculations and checks there.)
- Conversion part needs some optimization, doing unneeded calulations now.
*/
#include <stdio.h>
#include <stdlib.h>
#include "debug.h"
#include "lcd.h"
#include "file.h"
#include "autoconf.h"
#ifdef __GNUC__
#define STRUCT_PACKED __attribute__((packed))
#else
#define STRUCT_PACKED
#pragma pack (push, 2)
#endif
/* Struct from original code. */
struct Fileheader {
unsigned short Type; /* signature - 'BM' */
unsigned long Size; /* file size in bytes */
unsigned short Reserved1; /* 0 */
unsigned short Reserved2; /* 0 */
unsigned long OffBits; /* offset to bitmap */
unsigned long StructSize; /* size of this struct (40) */
unsigned long Width; /* bmap width in pixels */
unsigned long Height; /* bmap height in pixels */
unsigned short Planes; /* num planes - always 1 */
unsigned short BitCount; /* bits per pixel */
unsigned long Compression; /* compression flag */
unsigned long SizeImage; /* image size in bytes */
long XPelsPerMeter; /* horz resolution */
long YPelsPerMeter; /* vert resolution */
unsigned long ClrUsed; /* 0 -> color table size */
unsigned long ClrImportant; /* important color count */
} STRUCT_PACKED;
#ifdef ROCKBOX_LITTLE_ENDIAN
#define readshort(x) *(x)
#define readlong(x) *(x)
#else
/* big endian functions */
static short readshort(short *value) {
unsigned char* bytes = (unsigned char*) value;
return bytes[0] | (bytes[1] << 8);
}
static long readlong(long *value) {
unsigned char* bytes = (unsigned char*) value;
return (long)bytes[0] | ((long)bytes[1] << 8) |
((long)bytes[2] << 16) | ((long)bytes[3] << 24);
}
#endif
/* Function to get a pixel from a line. (Tomas: maybe a better way?) */
int getpix(int px, unsigned char *bmpbuf) {
int a = (px / 8);
int b = (7 - (px % 8));
return (bmpbuf[a] & (1 << b)) != 0;
}
/******************************************************************************
* read_bmp_file()
*
* Reads a monochrome BMP file and puts the data in rockbox format in *bitmap.
*
*****************************************************************************/
int read_bmp_file(char* filename,
int *get_width, /* in pixels */
int *get_height, /* in pixels */
char *bitmap,
int maxsize) /* Maximum amount of bytes to write to bitmap */
{
struct Fileheader fh;
int bitmap_width, bitmap_height, PaddedWidth, PaddedHeight;
int fd, row, col, ret;
char bmpbuf[(LCD_WIDTH / 8 + 3) & ~3]; /* Buffer for one line */
fd = open(filename, O_RDONLY);
/* Exit if file opening failed */
if (fd < 0) {
DEBUGF("error - can't open '%s' open returned: %d\n", filename, fd);
return (fd * 10) - 1;
}
/* read fileheader */
ret = read(fd, &fh, sizeof(struct Fileheader));
if(ret < 0) {
close(fd);
return (ret * 10 - 2);
}
if(ret != sizeof(struct Fileheader)) {
DEBUGF("error - can't read Fileheader structure.");
close(fd);
return -3;
}
/* Exit if not monochrome */
if (readshort(&fh.BitCount) != 1) {
DEBUGF("error - Bitmap must be in 1 bit per pixel format. "
"This one is: %d\n", readshort(&fh.BitCount));
close(fd);
return -4;
}
/* Exit if too wide */
if (readlong(&fh.Width) > LCD_WIDTH) {
DEBUGF("error - Bitmap is too wide (%d pixels, max is %d)\n",
readlong(&fh.Width), LCD_WIDTH);
close(fd);
return -5;
}
/* Exit if too high */
if (readlong(&fh.Height) > LCD_HEIGHT) {
DEBUGF("error - Bitmap is too high (%d pixels, max is %d)\n",
readlong(&fh.Height), LCD_HEIGHT);
close(fd);
return -6;
}
/* Calculate image size */
bitmap_height = readlong(&fh.Height);
bitmap_width = readlong(&fh.Width);
/* Paddedwidth is for BMP files. */
PaddedWidth = ((bitmap_width + 31) & (~0x1f)) / 8;
/* PaddedHeight is for rockbox format. */
PaddedHeight = (bitmap_height + 7) / 8;
/* Check if this fits the buffer */
if ((PaddedHeight * bitmap_width) > maxsize) {
DEBUGF("error - Bitmap is too large to fit the supplied buffer: "
"%d bytes.\n", (PaddedHeight * bitmap_width));
close(fd);
return -7;
}
/* Search to the beginning of the image data */
lseek(fd, (off_t)readlong(&fh.OffBits), SEEK_SET);
/* loop to read rows and put them to buffer */
for (row = 0; row < bitmap_height; row++) {
/* read one row */
ret = read(fd, bmpbuf, PaddedWidth);
if (ret != PaddedWidth) {
DEBUGF("error reading image, read returned: %d expected was: "
"%d\n", ret, PaddedWidth);
close(fd);
return -8;
}
/* loop though the pixels in this line. */
for (col = 0; col < bitmap_width; col++) {
ret = getpix(col, bmpbuf);
if (ret == 1) {
bitmap[bitmap_width * ((bitmap_height - row - 1) / 8) + col]
&= ~ 1 << ((bitmap_height - row - 1) % 8);
} else {
bitmap[bitmap_width * ((bitmap_height - row - 1) / 8) + col]
|= 1 << ((bitmap_height - row - 1) % 8);
}
}
}
close(fd);
/* returning image size: */
*get_width = bitmap_width;
*get_height = bitmap_height;
return (PaddedHeight * bitmap_width); /* return the used buffer size. */
}