📄 bitmap.c
字号:
// try and get the width and height
result[0] = sscanf((const char *)data + i,
"#define %79s %d", name_and_type, &value);
if (result[0] == 2)
{
type = strrchr(name_and_type, '_');
type = (type == NULL) ? name_and_type : type + 1;
if (strcmp(type, "width") == 0)
rcbmp->cx = value;
else if (strcmp(type, "height") == 0)
rcbmp->cy = value;
}
// look for the data token (is there data)?
result[0] = sscanf((const char *)data + i,
"static unsigned char %s = {", name_and_type);
result[1] = sscanf((const char *)data + i,
"static char %s = {", name_and_type);
if (result[0] || result[1])
{
type = strrchr(name_and_type, '_');
type = (type == NULL) ? name_and_type : type + 1;
if (strcmp(type, "bits[]") == 0 && rcbmp->cx > 0 && rcbmp->cy > 0)
{
rcbmp->cbRow = ((rcbmp->cx + 15) & ~15) / 8;
rcbmp->cbDst = rcbmp->cbRow * rcbmp->cy;
rcbmp->pbBits = malloc(rcbmp->cbDst);
break; // get out of the loop
}
}
}
if (rcbmp->pbBits == NULL)
ErrorLine("Invalid X11 bitmap");
// read the X11 bitmap data
memset(rcbmp->pbBits, 0, rcbmp->cbDst);
value = 0;
pos = 0;
for (i = BMP_SkipNewLine(data, size, i); i < size; i++)
{
PILRC_BYTE c = tolower(data[i]);
// termination of a byte?
if ((c == ',') || (c == '}'))
{
if (pos < rcbmp->cbDst)
{
rcbmp->pbBits[pos++] = (unsigned char)value;
if (((rcbmp->cx % 16) > 0) && ((rcbmp->cx % 16) < 9) &&
((pos % rcbmp->cbRow) == (rcbmp->cbRow - 1)))
pos++;
}
value = 0;
}
else
// numerical data? - process accordingly (hexagonal)
if ((c >= '0') && (c <= '9'))
value = (value >> 4) + (rev[c - '0'] << 4);
else if ((c >= 'a') && (c <= 'f'))
value = (value >> 4) + (rev[c - 'a' + 10] << 4);
}
}
struct rgb
{
int r, g, b;
};
struct foreign_reader
{
void (*start_row) (struct foreign_reader * self,
int y);
void (*read_pixel) (struct foreign_reader * self,
struct rgb * color);
int maxval;
PILRC_BYTE *pb, *pblim;
void *userdata;
};
static void
default_start_row(struct foreign_reader *self,
int y)
{
}
static void
WriteGreyTbmp(RCBITMAP * rcbmp,
struct foreign_reader *reader)
{
BOOL warnColorLost = fFalse;
int depth = rcbmp->pixelsize;
unsigned long outmaxval = (1UL << depth) - 1;
unsigned char *outp = rcbmp->pbBits;
int *index = malloc((reader->maxval + 1) * sizeof(int));
int i, x, y, ningreys;
for (i = 0; i <= reader->maxval; i++)
index[i] = -1;
for (y = 0; y < rcbmp->cy; y++)
{
unsigned int outword = 0;
int outlen = 0;
reader->start_row(reader, y);
for (x = 0; x < rcbmp->cx; x++)
{
struct rgb c;
unsigned long grey;
reader->read_pixel(reader, &c);
if (c.r == c.g && c.g == c.b)
grey = c.r;
else
{
warnColorLost = fTrue;
/*
* From the colorspace-FAQ. There's _some_ chance I'm
* applying the right formula. It's been a long time
* since graphics class...
*/
grey = (299L * c.r + 587L * c.g + 114L * c.b) / 1000L;
}
if ((int)grey > reader->maxval)
grey = reader->maxval;
if (index[grey] == -1)
{
unsigned long outgrey;
outgrey = (grey * outmaxval + reader->maxval / 2) / reader->maxval;
index[grey] = (outgrey <= outmaxval) ? outmaxval - outgrey : 0;
}
outword <<= depth;
outword |= index[grey];
outlen += depth;
if (outlen >= 16)
{
*outp++ = outword >> 8;
*outp++ = outword & 0xff;
outword = 0;
outlen = 0;
}
}
if (outlen > 0)
{
outword <<= 16 - outlen;
*outp++ = outword >> 8;
*outp++ = outword & 0xff;
}
}
if (warnColorLost)
WarningLine("Some colors saturated in index converted to grey");
ningreys = 0;
for (i = 0; i <= reader->maxval; i++)
if (index[i] != -1)
ningreys++;
free(index);
if (ningreys > (int)outmaxval + 1)
{
char buffer[120];
sprintf(buffer, "%d input grey levels converted to only %ld",
ningreys, outmaxval + 1);
WarningLine(buffer);
}
}
static int
WriteIndexedColorTbmp(RCBITMAP * rcbmp,
struct foreign_reader *reader,
struct rgb *colortable)
{
#define N 937
struct hash_entry
{
struct rgb key;
unsigned char index;
}
table[N];
unsigned char *outp = rcbmp->pbBits;
int x, y, h, nentries, ninputcolors, noutputcolors;
nentries = 0;
for (h = 0; h < N; h++)
table[h].key.r = -1;
ninputcolors = 0;
for (y = 0; y < rcbmp->cy; y++)
{
reader->start_row(reader, y);
for (x = 0; x < rcbmp->cx; x++)
{
struct rgb c;
unsigned char index;
reader->read_pixel(reader, &c);
/*
* This hash function has no basis in theory...
*/
for (h = (((c.r + 37) ^ (c.g << 2)) + c.b) % N;; h = (h + 1) % N)
if (table[h].key.r == -1)
{
struct rgb cs;
cs.r = (c.r * 255UL) / reader->maxval;
cs.g = (c.g * 255UL) / reader->maxval;
cs.b = (c.b * 255UL) / reader->maxval;
if (colortable)
{
if (ninputcolors < 256)
{
colortable[ninputcolors] = cs;
index = ninputcolors;
}
else
index = 0; /* FIXME!!!! */
}
else
index = BMP_RGBToColorIndex(cs.r, cs.g, cs.b,
PalmPalette8bpp, 256);
ninputcolors++;
/*
* Only add the new color if the table isn't already
* over full. This'll slow down for input images with
* lots of distinct colors, but it won't be infinitely
* slow as it would be if we let the table get
* completely full.
*/
if (nentries < N / 2)
{
nentries++;
table[h].key.r = c.r;
table[h].key.g = c.g;
table[h].key.b = c.b;
table[h].index = index;
}
break;
}
else if (table[h].key.r == c.r && table[h].key.g == c.g
&& table[h].key.b == c.b)
{
index = table[h].index;
break;
}
*outp++ = index;
}
if (rcbmp->cbRow > rcbmp->cx)
*outp++ = 0;
}
noutputcolors = (colortable) ? ninputcolors : 0;
if (ninputcolors > 256)
{
char buffer[120];
sprintf(buffer, "%d input colors converted to only 256", ninputcolors);
WarningLine(buffer);
ninputcolors = 256;
}
return ninputcolors;
}
/**
* Write the body of a Palm Computing bitmap resource data (family member).
*
* @param rcbmp a reference to the Palm Computing resource data.
* @param width width of the bitmap
* @param height height of the bitmap
* @param bitmaptype the type of bitmap (B+W, Grey, Grey16 or Color)?
* @param colortable does a color table need to be generated?
* @param reader callbacks and state variables to read the input file
*/
static void
WriteTbmp(RCBITMAP * rcbmp,
int width,
int height,
int bitmaptype,
BOOL colortable,
struct foreign_reader *reader)
{
int depth = 0;
switch (bitmaptype)
{
case rwBitmap:
depth = 1;
break;
case rwBitmapGrey:
depth = 2;
break;
case rwBitmapGrey16:
depth = 4;
break;
case rwBitmapColor256:
depth = 8;
break;
case rwBitmapColor16k:
case rwBitmapColor24k:
case rwBitmapColor32k:
//
// UNSUPPORTED RIGHT NOW
//
break;
default:
Assert(fFalse);
break;
}
rcbmp->cx = width;
rcbmp->cy = height;
rcbmp->pixelsize = depth;
rcbmp->cbRow = ((width * depth + 15) & ~15) >> 3;
rcbmp->cbDst = rcbmp->cbRow * height;
rcbmp->pbBits = malloc(rcbmp->cbDst);
rcbmp->version = (depth >= 8) ? 2 : 1;
/*
* The iterate-over-the-pixels code of these two ought to be unified
* into one function, but because the color conversions inside the
* loops are so different, it seems easier to duplicate the loops.
*/
if (rcbmp->pixelsize < 8)
WriteGreyTbmp(rcbmp, reader);
else
{
if (colortable)
{
struct rgb table[256];
int nentries = WriteIndexedColorTbmp(rcbmp, reader, table);
/*
* Now bolt the color table onto the front of the output bits.
*/
unsigned char *newBits = malloc(2 + 4 * nentries + rcbmp->cbDst);
if (newBits)
{
unsigned char *bits = newBits;
int i;
*bits++ = (nentries & 0xff00) >> 8;
*bits++ = nentries & 0x00ff;
for (i = 0; i < nentries; i++)
{
*bits++ = i;
*bits++ = table[i].r;
*bits++ = table[i].g;
*bits++ = table[i].b;
}
memcpy(bits, rcbmp->pbBits, rcbmp->cbDst);
free(rcbmp->pbBits);
// rcbmp->ff |= 0x4000;
rcbmp->flags.hasColorTable = fTrue;
rcbmp->pbBits = newBits;
rcbmp->cbDst += 2 + 4 * nentries;
}
}
else
(void)WriteIndexedColorTbmp(rcbmp, reader, NULL);
}
}
static void
SkipPNMWhitespace(struct foreign_reader *r)
{
while (r->pb < r->pblim)
if (isspace(*r->pb))
r->pb++;
else if (*r->pb == '#')
while (r->pb < r->pblim && *r->pb != '\n' && *r->pb != '\r')
r->pb++;
else
break;
}
static int
ReadPNMInt(struct foreign_reader *r)
{
int n = 0;
SkipPNMWhitespace(r);
for (; r->pb < r->pblim && isdigit(*r->pb); r->pb++)
n = 10 * n + *r->pb - '0';
return n;
}
/*
* A lot of these depend on PILRC_BYTE being unsigned. Further, if we run
* out of input (i.e., pb >= pblim) these won't infinite loop or anything,
* but they probably will return random colors. But running out of input
* indicates that the input is corrupted, so this doesn't really matter.
*/
static void
ReadP1(struct foreign_reader *r,
struct rgb *c)
{
SkipPNMWhitespace(r);
while (r->pb < r->pblim)
switch (*r->pb++)
{
case '0':
/*
* Yes, PBM color levels really are reversed compared to PGMs!
*/
c->r = c->g = c->b = 1;
return;
case '1':
c->r = c->g = c->b = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -