| /*************************************************************************** |
| * __________ __ ___. |
| * 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. */ |
| |
| } |