summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJens Arnold <amiconn@rockbox.org>2005-07-07 22:32:42 +0000
committerJens Arnold <amiconn@rockbox.org>2005-07-07 22:32:42 +0000
commitc5e87ae1e03b33c34266f6c7fed2cb5b159e0e65 (patch)
tree5f2c4a1c9eb8cd76b026939f5a1db5609bb0ff8c
parent3a5bd7acb677a37d8662f7ce0c9a392d0d75da18 (diff)
downloadrockbox-c5e87ae1e03b33c34266f6c7fed2cb5b159e0e65.tar.gz
rockbox-c5e87ae1e03b33c34266f6c7fed2cb5b159e0e65.tar.bz2
rockbox-c5e87ae1e03b33c34266f6c7fed2cb5b159e0e65.zip
Heavily extended bmp2rb conversion tool: Handles 4, 16, 24 and 32 bit BMPs in addition to 1 and 8 bit. Generates one of 3 output formats: (0) Archos recorder, Ondio, Gmini, H1x0 monochrome; this is the default. (1) Archos player graphics library. (2) H1x0 4-shade greyscale. Decision about the pixel value is based on the true pixel brightness, so hopefully no more inverted images.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7058 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--tools/bmp2rb.c771
1 files changed, 429 insertions, 342 deletions
diff --git a/tools/bmp2rb.c b/tools/bmp2rb.c
index f874fed677..52941fca15 100644
--- a/tools/bmp2rb.c
+++ b/tools/bmp2rb.c
@@ -16,13 +16,17 @@
* KIND, either express or implied.
*
****************************************************************************/
-/*********************************************************************
+/****************************************************************************
*
* Converts BMP files to Rockbox bitmap format
*
* 1999-05-03 Linus Nielsen Feltzing
*
- **********************************************/
+ * 2005-07-06 Jens Arnold
+ * added reading of 4, 16, 24 and 32 bit bmps
+ * added 2 new target formats (playergfx and iriver 4-grey)
+ *
+ ****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
@@ -44,33 +48,32 @@
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 */
+ 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;
struct RGBQUAD
{
- unsigned char rgbBlue;
- unsigned char rgbGreen;
- unsigned char rgbRed;
- unsigned char rgbReserved;
+ unsigned char rgbBlue;
+ unsigned char rgbGreen;
+ unsigned char rgbRed;
+ unsigned char rgbReserved;
} STRUCT_PACKED;
-
short readshort(void* value)
{
unsigned char* bytes = (unsigned char*) value;
@@ -83,366 +86,450 @@ int readlong(void* value)
return bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24);
}
-/*********************************************************************
+unsigned char brightness(unsigned char red, unsigned char green,
+ unsigned char blue)
+{
+ return (3 * (unsigned int)red + 6 * (unsigned int)green
+ + (unsigned int)blue) / 10;
+}
+
+/****************************************************************************
* read_bmp_file()
*
- * Reads a 8bit BMP file and puts the data in a 1-pixel-per-byte
- * array. Returns 0 on success.
+ * Reads an uncompressed BMP file and puts the data in a 1-pixel-per-byte
+ * array, sorted by brightness. Returns 0 on success.
*
- *********************************************************************/
+ ***************************************************************************/
+
int read_bmp_file(char* filename,
- int *get_width, /* in pixels */
- int *get_height, /* in pixels */
- char **bitmap)
+ long *get_width, /* in pixels */
+ long *get_height, /* in pixels */
+ unsigned char **bitmap)
{
struct Fileheader fh;
- struct RGBQUAD palette[2]; /* two colors only */
+ struct RGBQUAD palette[256];
+ unsigned char bright[256];
- unsigned int bitmap_width, bitmap_height;
-
- long PaddedWidth;
- int background;
int fd = open(filename, O_RDONLY);
- long size;
- long allocsize;
- unsigned int row, col;
- int l;
+ unsigned short data;
unsigned char *bmp;
- int width;
- int height;
+ long width, height;
+ long padded_width;
+ long size;
+ long row, col, i;
+ long numcolors, compression;
int depth;
- if(fd == -1)
+ if (fd == -1)
{
debugf("error - can't open '%s'\n", filename);
return 1;
}
- else
- {
- if(read(fd, &fh, sizeof(struct Fileheader)) !=
+ if (read(fd, &fh, sizeof(struct Fileheader)) !=
sizeof(struct Fileheader))
- {
- debugf("error - can't Read Fileheader Stucture\n");
- close(fd);
- return 2;
- }
-
- /* Exit if more than 8 bits */
- depth = readshort(&fh.BitCount);
- if(depth > 8)
- {
- debugf("error - Bitmap uses more than 8 bit depth, got %d\n",
- depth);
- close(fd);
- return 2;
- }
-
- /* Exit if too wide */
- if(readlong(&fh.Width) > 160)
- {
- debugf("error - Bitmap is too wide for iRiver models (%d pixels, max is 160)\n",
- readlong(&fh.Width));
- return 3;
- }
- if(readlong(&fh.Width) > 112)
- {
- debugf("info - Bitmap is too wide for Archos models (%d pixels, max is 112)\n",
- readlong(&fh.Width));
- }
-
- /* Exit if too high */
- if(readlong(&fh.Height) > 128)
- {
- debugf("error - Bitmap is too high for iRiver models (%d pixels, max is 128)\n",
- readlong(&fh.Height));
- return 4;
- }
- if(readlong(&fh.Height) > 64)
- {
- debugf("info - Bitmap is too high for Archos models (%d pixels, max is 64)\n",
- readlong(&fh.Height));
- }
-
- for(l=0;l < 2;l++)
- {
- if(read(fd, &palette[l],sizeof(struct RGBQUAD)) !=
- sizeof(struct RGBQUAD))
- {
- debugf("error - Can't read bitmap's color palette\n");
- close(fd);
- return 5;
- }
- }
- if(depth == 8 ) {
- /* pass the other palettes */
- lseek(fd, 254*sizeof(struct RGBQUAD), SEEK_CUR);
- }
-
- /* Try to guess the foreground and background colors.
- We assume that the foreground color is the darkest. */
- if(((int)palette[0].rgbRed +
- (int)palette[0].rgbGreen +
- (int)palette[0].rgbBlue) >
- ((int)palette[1].rgbRed +
- (int)palette[1].rgbGreen +
- (int)palette[1].rgbBlue))
- {
- background = 0;
- }
- else
- {
- background = 1;
- }
-
- width = readlong(&fh.Width);
-
- if(depth == 8)
- PaddedWidth = ((width+3)&(~0x3)); /* aligned 4-bytes boundaries */
- else
- PaddedWidth = ((width+31)&(~0x1f))/8;
-
- height = readlong(&fh.Height);
-
- allocsize = size = PaddedWidth*height; /* read this many bytes */
- bmp = (unsigned char *)malloc(size);
-
- if(height%8) {
- /* not even 8 bytes, add up to a full 8 pixels boundary */
- height += 8-(height%8);
- allocsize = PaddedWidth*height; /* bytes to alloc */
- }
-
- *bitmap = (unsigned char *)malloc(allocsize);
-
- if(bmp == NULL)
- {
- debugf("error - Out of memory\n");
- close(fd);
- return 6;
- }
- else
- {
- if(read(fd, (unsigned char*)bmp,(long)size) != size) {
- debugf("error - Can't read image\n");
- close(fd);
- return 7;
- }
- }
-
- bitmap_height = readlong(&fh.Height);
- bitmap_width = readlong(&fh.Width);
-
- *get_width = bitmap_width;
- *get_height = bitmap_height;
-
- if(depth == 8)
- {
- /* Now convert the bitmap into an array with 1 byte per pixel,
- exactly the size of the image */
- for(row = 0;row < bitmap_height;row++) {
- for(col = 0;col < bitmap_width;col++) {
- if(bmp[(bitmap_height-1 -row) * PaddedWidth + col]) {
- (*bitmap)[ (row/8) * bitmap_width + col ] &=
- ~ (1<<(row&7));
- }
- else {
- (*bitmap)[ (row/8) * bitmap_width + col ] |=
- 1<<(row&7);
- }
- }
- }
- }
- else
- {
- int bit;
- int byte;
- /* monocrome BMP conversion uses 8 pixels per byte */
- for(row = 0; row < bitmap_height; row++) {
- bit = 7;
- byte = 0;
- for(col = 0;col < bitmap_width;col++) {
- if((bmp[(bitmap_height - row - 1) * PaddedWidth + byte] &
- (1 << bit))) {
- (*bitmap)[(row/8) * bitmap_width + col ] &=
- ~(1<<(row&7));
- }
- else {
- (*bitmap)[(row/8) * bitmap_width + col ] |=
- 1<<(row&7);
- }
- if(bit) {
- bit--;
- }
- else {
- bit = 7;
- byte++;
- }
- }
- }
- }
-
- free(bmp);
-
- }
- close(fd);
- return 0; /* success */
+ {
+ debugf("error - can't Read Fileheader Stucture\n");
+ close(fd);
+ return 2;
+ }
+
+ compression = readlong(&fh.Compression);
+
+ if (compression != 0)
+ {
+ debugf("error - Unsupported compression %ld\n", compression);
+ close(fd);
+ return 3;
+ }
+
+ depth = readshort(&fh.BitCount);
+
+ if (depth <= 8)
+ {
+ numcolors = readlong(&fh.ClrUsed);
+ if (numcolors == 0)
+ numcolors = 1 << depth;
+
+ if (read(fd, &palette[0], numcolors * sizeof(struct RGBQUAD))
+ != numcolors * sizeof(struct RGBQUAD))
+ {
+ debugf("error - Can't read bitmap's color palette\n");
+ close(fd);
+ return 4;
+ }
+
+ /* Precalculate weighted brightnesses for the palette */
+ for (i = 0; i < numcolors; i++)
+ bright[i] = brightness(palette[i].rgbRed, palette[i].rgbGreen,
+ palette[i].rgbBlue);
+ }
+
+ width = readlong(&fh.Width);
+ height = readlong(&fh.Height);
+ padded_width = (width * depth / 8 + 3) & ~3; /* aligned 4-bytes boundaries */
+
+ size = padded_width * height; /* read this many bytes */
+ bmp = (unsigned char *)malloc(size);
+ *bitmap = (unsigned char *)malloc(width * height);
+
+ if ((bmp == NULL) || (*bitmap == NULL))
+ {
+ debugf("error - Out of memory\n");
+ close(fd);
+ return 5;
+ }
+
+ if (lseek(fd, (off_t)readlong(&fh.OffBits), SEEK_SET) < 0)
+ {
+ debugf("error - Can't seek to start of image data\n");
+ close(fd);
+ return 6;
+ }
+ if (read(fd, (unsigned char*)bmp, (long)size) != size)
+ {
+ debugf("error - Can't read image\n");
+ close(fd);
+ return 7;
+ }
+
+ close(fd);
+ *get_width = width;
+ *get_height = height;
+
+ switch (depth)
+ {
+ case 1:
+ for (row = 0; row < height; row++)
+ for (col = 0; col < width; col++)
+ {
+ data = (bmp[(height - 1 - row) * padded_width + col / 8]
+ >> (~col & 7)) & 1;
+ (*bitmap)[row * width + col] = bright[data];
+ }
+ break;
+
+ case 4:
+ for (row = 0; row < height; row++)
+ for (col = 0; col < width; col++)
+ {
+ data = (bmp[(height - 1 - row) * padded_width + col / 2]
+ >> (4 * (~col & 1))) & 0x0F;
+ (*bitmap)[row * width + col] = bright[data];
+ }
+ break;
+
+ case 8:
+ for (row = 0; row < height; row++)
+ for (col = 0; col < width; col++)
+ {
+ data = bmp[(height - 1 - row) * padded_width + col];
+ (*bitmap)[row * width + col] = bright[data];
+ }
+ break;
+
+ case 16:
+ for (row = 0; row < height; row++)
+ for (col = 0; col < width; col++)
+ {
+ data = readshort(&bmp[(height - 1 - row) * padded_width + 2 * col]);
+ (*bitmap)[row * width + col] = brightness((data >> 7) & 0xF8,
+ (data >> 2) & 0xF8, (data << 3) & 0xF8);
+ }
+ break;
+
+ case 24:
+ for (row = 0; row < height; row++)
+ for (col = 0; col < width; col++)
+ {
+ i = (height - 1 - row) * padded_width + 3 * col;
+ (*bitmap)[row * width + col] =
+ brightness(bmp[i+2], bmp[i+1], bmp[i]);
+ }
+ break;
+
+ case 32:
+ for (row = 0; row < height; row++)
+ for (col = 0; col < width; col++)
+ {
+ i = (height - 1 - row) * padded_width + 4 * col;
+ (*bitmap)[row * width + col] =
+ brightness(bmp[i+2], bmp[i+1], bmp[i]);
+ }
+ break;
+
+ default: /* should never happen */
+ debugf("error - Unsupported bitmap depth %d.\n", depth);
+ return 8;
+ }
+
+ free(bmp);
+
+ return 0; /* success */
+}
+
+/****************************************************************************
+ * transform_bitmap()
+ *
+ * Transform a 1-byte-per-pixel bitmap into one of the supported
+ * destination formats
+ ****************************************************************************/
+
+int transform_bitmap(const unsigned char *src, long width, long height,
+ int format, unsigned char **dest, long *dst_width,
+ long *dst_height)
+{
+ long row, col;
+ long dst_w, dst_h;
+
+ switch (format)
+ {
+ case 0: /* Archos recorders, Ondio, Gmini 120/SP, Iriver H1x0 monochrome */
+ dst_w = width;
+ dst_h = (height + 7) / 8;
+ break;
+
+ case 1: /* Archos player graphics library */
+ dst_w = (width + 7) / 8;
+ dst_h = height;
+ break;
+
+ case 2: /* Iriver H1x0 4-grey */
+ dst_w = width;
+ dst_h = (height + 3) / 4;
+ break;
+
+ default: /* unknown */
+ debugf("error - Undefined destination format\n");
+ return 1;
+ }
+
+ *dest = (unsigned char *)malloc(dst_w * dst_h);
+ if (*dest == NULL)
+ {
+ debugf("error - Out of memory.\n");
+ return 2;
+ }
+ memset(*dest, 0, dst_w * dst_h);
+ *dst_width = dst_w;
+ *dst_height = dst_h;
+
+ switch (format)
+ {
+ case 0: /* Archos recorders, Ondio, Gmini 120/SP, Iriver H1x0 b&w */
+ for (row = 0; row < height; row++)
+ for (col = 0; col < width; col++)
+ {
+ (*dest)[(row/8) * dst_w + col] |=
+ (~src[row * width + col] & 0x80) >> (~row & 7);
+ }
+ break;
+
+ case 1: /* Archos player graphics library */
+ for (row = 0; row < height; row++)
+ for (col = 0; col < width; col++)
+ {
+ (*dest)[row * dst_w + (col/8)] |=
+ (~src[row * width + col] & 0x80) >> (col & 7);
+ }
+ break;
+
+ case 2: /* Iriver H1x0 4-grey */
+ for (row = 0; row < height; row++)
+ for (col = 0; col < width; col++)
+ {
+ (*dest)[(row/4) * dst_w + col] |=
+ (~src[row * width + col] & 0xC0) >> (2 * (~row & 3));
+ }
+ break;
+ }
+
+ return 0;
}
-/*********************************************************************
-** generate_c_source()
-**
-** Outputs a C source code with the bitmap in an array, accompanied by
-** some #define's
-**********************************************************************/
-void generate_c_source(char *id, int width, int height, unsigned char *bitmap)
+/****************************************************************************
+ * generate_c_source()
+ *
+ * Outputs a C source code with the bitmap in an array, accompanied by
+ * some #define's
+ ****************************************************************************/
+
+void generate_c_source(char *id, long width, long height,
+ const unsigned char *t_bitmap, long t_width,
+ long t_height)
{
- FILE *f;
- unsigned int i, a, eline;
+ FILE *f;
+ long i, a;
- f = stdout;
+ f = stdout;
- if(!id || !id[0])
- id = "bitmap";
+ if (!id || !id[0])
+ id = "bitmap";
- fprintf(f,
- "#define BMPHEIGHT_%s %d"
- "\n#define BMPWIDTH_%s %d"
- "\nconst unsigned char %s[] = {\n",
- id, height, id, width, id );
+ fprintf(f,
+ "#define BMPHEIGHT_%s %ld\n"
+ "#define BMPWIDTH_%s %ld\n"
+ "const unsigned char %s[] = {\n",
+ id, height, id, width, id);
- for(i=0, eline=0; i< height; i+=8, eline++) {
- for (a=0; a<width; a++)
- fprintf(f, "0x%02x,%c", bitmap[eline*width + a],
- (a+1)%13?' ':'\n');
- fprintf(f, "\n");
- }
-
+ for (i = 0; i < t_height; i++)
+ {
+ for (a = 0; a < t_width; a++)
+ fprintf(f, "0x%02x,%c", t_bitmap[i * t_width + a],
+ (a + 1) % 13 ? ' ' : '\n');
+ fprintf(f, "\n");
+ }
- fprintf(f, "\n};\n");
+ fprintf(f, "\n};\n");
}
+/****************************************************************************
+ * generate_ascii()
+ *
+ * Outputs an ascii picture of the bitmap
+ ****************************************************************************/
-/*********************************************************************
-** generate_ascii()
-**
-** Outputs an ascii picture of the bitmap
-**********************************************************************/
-void generate_ascii(int width, int height, unsigned char *bitmap)
+void generate_ascii(long width, long height, unsigned char *bitmap)
{
FILE *f;
- unsigned int i, eline;
+ long x, y;
f = stdout;
/* for screen output debugging */
- for(i=0, eline=0; i< height; i+=8, eline++) {
- unsigned int x, y;
- for(y=0; y<8 && (i+y < height); y++) {
- for(x=0; x < width; x++) {
-
- if(bitmap[eline*width + x] & (1<<y)) {
- fprintf(f, "*");
- }
- else
- fprintf(f, " ");
- }
- fprintf(f, "\n");
+ for (y = 0; y < height; y++)
+ {
+ for (x = 0; x < width; x++)
+ {
+ fprintf(f, (bitmap[y * width + x] & 0x80) ? " " : "*");
}
+ fprintf(f, "\n");
}
}
void print_usage(void)
{
- printf("Usage: %s [-i <id>] [-a] <bitmap file>\n"
- "\t-i <id> Bitmap name (default is filename without extension)\n"
- "\t-a Show ascii picture of bitmap\n",
- APPLICATION_NAME);
- printf("build date: " __DATE__ "\n\n");
+ printf("Usage: %s [-i <id>] [-a] <bitmap file>\n"
+ "\t-i <id> Bitmap name (default is filename without extension)\n"
+ "\t-a Show ascii picture of bitmap\n"
+ "\t-f <n> Generate destination format n, default = 0\n"
+ "\t 0 Archos recorder, Ondio, Gmini 120/SP, Iriver H1x0 mono\n"
+ "\t 1 Archos player graphics library\n"
+ "\t 2 Iriver H1x0 4-grey\n"
+ , APPLICATION_NAME);
+ printf("build date: " __DATE__ "\n\n");
}
int main(int argc, char **argv)
{
- char *bmp_filename = NULL;
- char *id = NULL;
- int i;
- int height, width;
- int ascii = false;
- char* bitmap = NULL;
-
-
- for(i = 1;i < argc;i++)
- {
- if(argv[i][0] == '-')
- {
- switch(argv[i][1])
- {
- case 'i': /* ID */
- if(argv[i][2])
- {
- id = &argv[i][2];
- }
- else if(argc > i+1)
- {
- id = argv[i+1];
- i++;
- }
- else
- {
- print_usage();
- exit(1);
- }
- break;
-
- case 'a': /* Assembly */
- ascii = true;
- break;
-
- default:
- print_usage();
- exit(1);
- break;
- }
- }
- else
- {
- if(!bmp_filename)
- {
- bmp_filename = argv[i];
- }
- else
- {
- print_usage();
- exit(1);
- }
- }
- }
-
- if (!bmp_filename)
- {
- print_usage();
- exit(1);
- }
-
- if (!id)
- {
- char *ptr=strrchr(bmp_filename, '/');
- if(ptr)
- ptr++;
- else
- ptr = bmp_filename;
- id = strdup(ptr);
- for (i = 0; id[i]; i++)
- if (id[i] == '.')
- id[i] = '\0';
- }
-
- if (read_bmp_file(bmp_filename, &width, &height, &bitmap))
- return 0;
-
- if (ascii)
- generate_ascii(width, height, bitmap);
- else
- generate_c_source(id, width, height, bitmap);
-
- return 0;
+ char *bmp_filename = NULL;
+ char *id = NULL;
+ int i;
+ int ascii = false;
+ int format = 0;
+ unsigned char *bitmap = NULL;
+ unsigned char *t_bitmap = NULL;
+ long width, height;
+ long t_width, t_height;
+
+
+ for (i = 1;i < argc;i++)
+ {
+ if (argv[i][0] == '-')
+ {
+ switch (argv[i][1])
+ {
+ case 'i': /* ID */
+ if (argv[i][2])
+ {
+ id = &argv[i][2];
+ }
+ else if (argc > i+1)
+ {
+ id = argv[i+1];
+ i++;
+ }
+ else
+ {
+ print_usage();
+ exit(1);
+ }
+ break;
+
+ case 'a': /* Ascii art */
+ ascii = true;
+ break;
+
+ case 'f':
+ if (argv[i][2])
+ {
+ format = atoi(&argv[i][2]);
+ }
+ else if (argc > i+1)
+ {
+ format = atoi(argv[i+1]);
+ i++;
+ }
+ else
+ {
+ print_usage();
+ exit(1);
+ }
+ break;
+
+ default:
+ print_usage();
+ exit(1);
+ break;
+ }
+ }
+ else
+ {
+ if (!bmp_filename)
+ {
+ bmp_filename = argv[i];
+ }
+ else
+ {
+ print_usage();
+ exit(1);
+ }
+ }
+ }
+
+ if (!bmp_filename)
+ {
+ print_usage();
+ exit(1);
+ }
+
+ if (!id)
+ {
+ char *ptr=strrchr(bmp_filename, '/');
+ if (ptr)
+ ptr++;
+ else
+ ptr = bmp_filename;
+ id = strdup(ptr);
+ for (i = 0; id[i]; i++)
+ if (id[i] == '.')
+ id[i] = '\0';
+ }
+
+ if (read_bmp_file(bmp_filename, &width, &height, &bitmap))
+ exit(1);
+
+
+ if (ascii)
+ {
+ generate_ascii(width, height, bitmap);
+ }
+ else
+ {
+ if (transform_bitmap(bitmap, width, height, format, &t_bitmap,
+ &t_width, &t_height))
+ exit(1);
+ generate_c_source(id, width, height, t_bitmap, t_width, t_height);
+ }
+
+ return 0;
}