1
0
Fork 0
forked from len0rd/rockbox

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
This commit is contained in:
Jens Arnold 2005-07-07 22:32:42 +00:00
parent 3a5bd7acb6
commit c5e87ae1e0

View file

@ -16,13 +16,17 @@
* KIND, either express or implied. * KIND, either express or implied.
* *
****************************************************************************/ ****************************************************************************/
/********************************************************************* /****************************************************************************
* *
* Converts BMP files to Rockbox bitmap format * Converts BMP files to Rockbox bitmap format
* *
* 1999-05-03 Linus Nielsen Feltzing * 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 <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -70,7 +74,6 @@ struct RGBQUAD
unsigned char rgbReserved; unsigned char rgbReserved;
} STRUCT_PACKED; } STRUCT_PACKED;
short readshort(void* value) short readshort(void* value)
{ {
unsigned char* bytes = (unsigned char*) value; unsigned char* bytes = (unsigned char*) value;
@ -83,33 +86,38 @@ int readlong(void* value)
return bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24); 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() * read_bmp_file()
* *
* Reads a 8bit BMP file and puts the data in a 1-pixel-per-byte * Reads an uncompressed BMP file and puts the data in a 1-pixel-per-byte
* array. Returns 0 on success. * array, sorted by brightness. Returns 0 on success.
* *
*********************************************************************/ ***************************************************************************/
int read_bmp_file(char* filename, int read_bmp_file(char* filename,
int *get_width, /* in pixels */ long *get_width, /* in pixels */
int *get_height, /* in pixels */ long *get_height, /* in pixels */
char **bitmap) unsigned char **bitmap)
{ {
struct Fileheader fh; 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); int fd = open(filename, O_RDONLY);
long size; unsigned short data;
long allocsize;
unsigned int row, col;
int l;
unsigned char *bmp; unsigned char *bmp;
int width; long width, height;
int height; long padded_width;
long size;
long row, col, i;
long numcolors, compression;
int depth; int depth;
if (fd == -1) if (fd == -1)
@ -117,8 +125,6 @@ int read_bmp_file(char* filename,
debugf("error - can't open '%s'\n", filename); debugf("error - can't open '%s'\n", filename);
return 1; return 1;
} }
else
{
if (read(fd, &fh, sizeof(struct Fileheader)) != if (read(fd, &fh, sizeof(struct Fileheader)) !=
sizeof(struct Fileheader)) sizeof(struct Fileheader))
{ {
@ -127,177 +133,232 @@ int read_bmp_file(char* filename,
return 2; return 2;
} }
/* Exit if more than 8 bits */ compression = readlong(&fh.Compression);
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 (compression != 0)
if(readlong(&fh.Width) > 160)
{ {
debugf("error - Bitmap is too wide for iRiver models (%d pixels, max is 160)\n", debugf("error - Unsupported compression %ld\n", compression);
readlong(&fh.Width)); close(fd);
return 3; 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 */ depth = readshort(&fh.BitCount);
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 (depth <= 8)
{ {
if(read(fd, &palette[l],sizeof(struct RGBQUAD)) != numcolors = readlong(&fh.ClrUsed);
sizeof(struct RGBQUAD)) 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"); debugf("error - Can't read bitmap's color palette\n");
close(fd); close(fd);
return 5; return 4;
}
}
if(depth == 8 ) {
/* pass the other palettes */
lseek(fd, 254*sizeof(struct RGBQUAD), SEEK_CUR);
} }
/* Try to guess the foreground and background colors. /* Precalculate weighted brightnesses for the palette */
We assume that the foreground color is the darkest. */ for (i = 0; i < numcolors; i++)
if(((int)palette[0].rgbRed + bright[i] = brightness(palette[i].rgbRed, palette[i].rgbGreen,
(int)palette[0].rgbGreen + palette[i].rgbBlue);
(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); 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); height = readlong(&fh.Height);
padded_width = (width * depth / 8 + 3) & ~3; /* aligned 4-bytes boundaries */
allocsize = size = PaddedWidth*height; /* read this many bytes */ size = padded_width * height; /* read this many bytes */
bmp = (unsigned char *)malloc(size); bmp = (unsigned char *)malloc(size);
*bitmap = (unsigned char *)malloc(width * height);
if(height%8) { if ((bmp == NULL) || (*bitmap == NULL))
/* 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"); debugf("error - Out of memory\n");
close(fd); 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; return 6;
} }
else if (read(fd, (unsigned char*)bmp, (long)size) != size)
{ {
if(read(fd, (unsigned char*)bmp,(long)size) != size) {
debugf("error - Can't read image\n"); debugf("error - Can't read image\n");
close(fd); close(fd);
return 7; return 7;
} }
}
bitmap_height = readlong(&fh.Height); close(fd);
bitmap_width = readlong(&fh.Width); *get_width = width;
*get_height = height;
*get_width = bitmap_width; switch (depth)
*get_height = bitmap_height;
if(depth == 8)
{ {
/* Now convert the bitmap into an array with 1 byte per pixel, case 1:
exactly the size of the image */ for (row = 0; row < height; row++)
for(row = 0;row < bitmap_height;row++) { for (col = 0; col < width; col++)
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; data = (bmp[(height - 1 - row) * padded_width + col / 8]
int byte; >> (~col & 7)) & 1;
/* monocrome BMP conversion uses 8 pixels per byte */ (*bitmap)[row * width + col] = bright[data];
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 { break;
(*bitmap)[(row/8) * bitmap_width + col ] |=
1<<(row&7); 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];
} }
if(bit) { break;
bit--;
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];
} }
else { break;
bit = 7;
byte++; 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); free(bmp);
}
close(fd);
return 0; /* success */ return 0; /* success */
} }
/********************************************************************* /****************************************************************************
** generate_c_source() * transform_bitmap()
** *
** Outputs a C source code with the bitmap in an array, accompanied by * Transform a 1-byte-per-pixel bitmap into one of the supported
** some #define's * destination formats
**********************************************************************/ ****************************************************************************/
void generate_c_source(char *id, int width, int height, unsigned char *bitmap)
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, long width, long height,
const unsigned char *t_bitmap, long t_width,
long t_height)
{ {
FILE *f; FILE *f;
unsigned int i, a, eline; long i, a;
f = stdout; f = stdout;
@ -305,58 +366,56 @@ void generate_c_source(char *id, int width, int height, unsigned char *bitmap)
id = "bitmap"; id = "bitmap";
fprintf(f, fprintf(f,
"#define BMPHEIGHT_%s %d" "#define BMPHEIGHT_%s %ld\n"
"\n#define BMPWIDTH_%s %d" "#define BMPWIDTH_%s %ld\n"
"\nconst unsigned char %s[] = {\n", "const unsigned char %s[] = {\n",
id, height, id, width, id); id, height, id, width, id);
for(i=0, eline=0; i< height; i+=8, eline++) { for (i = 0; i < t_height; i++)
for (a=0; a<width; a++) {
fprintf(f, "0x%02x,%c", bitmap[eline*width + a], for (a = 0; a < t_width; a++)
fprintf(f, "0x%02x,%c", t_bitmap[i * t_width + a],
(a + 1) % 13 ? ' ' : '\n'); (a + 1) % 13 ? ' ' : '\n');
fprintf(f, "\n"); fprintf(f, "\n");
} }
fprintf(f, "\n};\n"); fprintf(f, "\n};\n");
} }
/****************************************************************************
* generate_ascii()
*
* Outputs an ascii picture of the bitmap
****************************************************************************/
/********************************************************************* void generate_ascii(long width, long height, unsigned char *bitmap)
** generate_ascii()
**
** Outputs an ascii picture of the bitmap
**********************************************************************/
void generate_ascii(int width, int height, unsigned char *bitmap)
{ {
FILE *f; FILE *f;
unsigned int i, eline; long x, y;
f = stdout; f = stdout;
/* for screen output debugging */ /* for screen output debugging */
for(i=0, eline=0; i< height; i+=8, eline++) { for (y = 0; y < height; y++)
unsigned int x, y; {
for(y=0; y<8 && (i+y < height); y++) { for (x = 0; x < width; x++)
for(x=0; x < width; x++) { {
fprintf(f, (bitmap[y * width + x] & 0x80) ? " " : "*");
if(bitmap[eline*width + x] & (1<<y)) {
fprintf(f, "*");
}
else
fprintf(f, " ");
} }
fprintf(f, "\n"); fprintf(f, "\n");
} }
} }
}
void print_usage(void) void print_usage(void)
{ {
printf("Usage: %s [-i <id>] [-a] <bitmap file>\n" printf("Usage: %s [-i <id>] [-a] <bitmap file>\n"
"\t-i <id> Bitmap name (default is filename without extension)\n" "\t-i <id> Bitmap name (default is filename without extension)\n"
"\t-a Show ascii picture of bitmap\n", "\t-a Show ascii picture of bitmap\n"
APPLICATION_NAME); "\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"); printf("build date: " __DATE__ "\n\n");
} }
@ -365,9 +424,12 @@ int main(int argc, char **argv)
char *bmp_filename = NULL; char *bmp_filename = NULL;
char *id = NULL; char *id = NULL;
int i; int i;
int height, width;
int ascii = false; int ascii = false;
char* bitmap = NULL; 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++) for (i = 1;i < argc;i++)
@ -393,10 +455,27 @@ int main(int argc, char **argv)
} }
break; break;
case 'a': /* Assembly */ case 'a': /* Ascii art */
ascii = true; ascii = true;
break; 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: default:
print_usage(); print_usage();
exit(1); exit(1);
@ -437,12 +516,20 @@ int main(int argc, char **argv)
} }
if (read_bmp_file(bmp_filename, &width, &height, &bitmap)) if (read_bmp_file(bmp_filename, &width, &height, &bitmap))
return 0; exit(1);
if (ascii) if (ascii)
{
generate_ascii(width, height, bitmap); generate_ascii(width, height, bitmap);
}
else else
generate_c_source(id, width, height, bitmap); {
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; return 0;
} }