http://i457.photobucket.com/albums/qq292/landwaster/webpissue1.jpg
There's a screenshot of the issue I'm encountering.
The image was originally a shade of blue, and I figured out it was a
endian swapping mistake. The other problem I noticed that I haven't
nailed down yet is that the image is slightly shifted/wrapping from
left-to-right.
Any ideas? Here's the code:
struct MBUFFER { void *dst; DWORD offset; };
size_t mwrite(void *src, size_t size, size_t count, MBUFFER *mp)
{
size_t length = size * count;
memmove((unsigned char*)mp->dst + mp->offset, src, length);
mp->offset += length;
return count;
}
unsigned char *pixWriteMemoryBmp(size_t &size, PIX *pix)
{
MBUFFER *mp = (MBUFFER*)malloc(sizeof(MBUFFER));
unsigned int offbytes, filebytes, fileimagebytes;
int width, height, depth, d, xres, yres;
unsigned short bfType, bfSize, bfFill1, bfReserved1, bfReserved2;
unsigned short bfOffBits, bfFill2, biPlanes, biBitCount;
unsigned short sval;
unsigned int biSize, biWidth, biHeight, biCompression,
biSizeImage;
unsigned int biXPelsPerMeter, biYPelsPerMeter, biClrUsed,
biClrImportant;
int pixWpl, pixBpl, extrabytes, writeerror;
int fileBpl, fileWpl;
int i, j, k;
int heapcm; // extra copy of cta on the heap ? 1 : 0
unsigned char *data;
unsigned char pel[4];
unsigned int *line, *pword;
PIXCMAP *cmap;
unsigned char *cta; // address of the bmp color table array
int cmaplen; // number of bytes in the bmp colormap
int ncolors, val, stepsize;
RGBA_QUAD *pquad;
if (!pix) {
fprintf(stderr, "%s: pix not defined\n", __FUNCTION__);
if (mp) free(mp);
return NULL;
}
width = pix->w;
height = pix->h;
d = pix->d;
if (d == 2) {
fprintf(stderr, "%s: writing 2 bpp bmp memory; nobody else can
read\n", __FUNCTION__);
}
depth = d;
if (d == 32)
depth = 24;
xres = (int)(39.37 * (float)pix->xres + 0.5); // to ppm
yres = (int)(39.37 * (float)pix->yres + 0.5); // to ppm
pixWpl = pix->wpl;
pixBpl = 4 * pixWpl;
fileWpl = (width * depth + 31) / 32;
fileBpl = 4 * fileWpl;
fileimagebytes = height * fileBpl;
heapcm = 0;
if (d == 32) { // 24 bpp rgb; no colormap
ncolors = 0;
cmaplen = 0;
}
else if ((cmap = pixGetColormap(pix))) { // existing colormap
ncolors = pixcmapGetCount(cmap);
cmaplen = ncolors * sizeof(RGBA_QUAD);
cta = (unsigned char *)cmap->array;
}
else { // no existing colormap; make a binary or gray one
if (d == 1) {
cmaplen = sizeof(bwmap);
ncolors = 2;
cta = (unsigned char *)bwmap;
}
else { // d != 32; output grayscale version
ncolors = 1 << depth;
cmaplen = ncolors * sizeof(RGBA_QUAD);
heapcm = 1;
if ((cta = (unsigned char *)calloc(cmaplen, 1)) == NULL) {
fprintf(stderr, "%s: colormap alloc fail\n",
__FUNCTION__);
if (mp) free(mp);
return NULL;
}
stepsize = 255 / (ncolors - 1);
for (i = 0, val = 0, pquad = (RGBA_QUAD *)cta;
i < ncolors;
i++, val += stepsize, pquad++) {
pquad->blue = pquad->green = pquad->red = val;
}
}
}
#if DEBUG
{unsigned char *pcmptr;
pcmptr = (unsigned char *)pixGetColormap(pix)->array;
fprintf(stderr, "Pix colormap[0] = %c%c%c%d\n",
pcmptr[0], pcmptr[1], pcmptr[2], pcmptr[3]);
fprintf(stderr, "Pix colormap[1] = %c%c%c%d\n",
pcmptr[4], pcmptr[5], pcmptr[6], pcmptr[7]);
}
#endif // DEBUG
// Convert to little-endian and write the file header data
bfType = convertOnBigEnd16(BMP_ID);
offbytes = BMP_FHBYTES + BMP_IHBYTES + cmaplen;
filebytes = offbytes + fileimagebytes;
sval = filebytes & 0x0000ffff;
bfSize = convertOnBigEnd16(sval);
sval = (filebytes >> 16) & 0x0000ffff;
bfFill1 = convertOnBigEnd16(sval);
bfReserved1 = 0;
bfReserved2 = 0;
sval = offbytes & 0x0000ffff;
bfOffBits = convertOnBigEnd16(sval);
sval = (offbytes >> 16) & 0x0000ffff;
bfFill2 = convertOnBigEnd16(sval);
size = filebytes;
unsigned char *mem = NULL;
if ((mem = (unsigned char *)calloc(filebytes, 1)) == NULL) {
fprintf(stderr, "%s: bmp alloc fail\n", __FUNCTION__);
if (mp) free(mp);
return NULL;
}
mp->dst = mem;
mp->offset = 0;
mwrite(&bfType, 1, 2, mp);
mwrite(&bfSize, 1, 2, mp);
mwrite(&bfFill1, 1, 2, mp);
mwrite(&bfReserved1, 1, 2, mp);
mwrite(&bfReserved1, 1, 2, mp);
mwrite(&bfOffBits, 1, 2, mp);
mwrite(&bfFill2, 1, 2, mp);
// Convert to little-endian and write the info header data
biSize = convertOnBigEnd32(BMP_IHBYTES);
biWidth = convertOnBigEnd32(width);
biHeight = convertOnBigEnd32(height);
biPlanes = convertOnBigEnd16(1);
biBitCount = convertOnBigEnd16(depth);
biCompression = 0;
biSizeImage = convertOnBigEnd32(fileimagebytes);
biXPelsPerMeter = convertOnBigEnd32(xres);
biYPelsPerMeter = convertOnBigEnd32(yres);
biClrUsed = convertOnBigEnd32(ncolors);
biClrImportant = convertOnBigEnd32(ncolors);
mwrite(&biSize, 1, 4, mp);
mwrite(&biWidth, 1, 4, mp);
mwrite(&biHeight, 1, 4, mp);
mwrite(&biPlanes, 1, 2, mp);
mwrite(&biBitCount, 1, 2, mp);
mwrite(&biCompression, 1, 4, mp);
mwrite(&biSizeImage, 1, 4, mp);
mwrite(&biXPelsPerMeter, 1, 4, mp);
mwrite(&biYPelsPerMeter, 1, 4, mp);
mwrite(&biClrUsed, 1, 4, mp);
mwrite(&biClrImportant, 1, 4, mp);
// Write the colormap data
if (ncolors > 0) {
if (mwrite(cta, 1, cmaplen, mp) != cmaplen) {
if (heapcm) free(cta);
if (mp && mp->dst) free(mp->dst);
fprintf(stderr, "%s: colormap write fail\n",
__FUNCTION__);
if (mp) free(mp);
return NULL;
}
if (heapcm) free(cta);
}
// When you write a binary image with a colormap
// that sets BLACK to 0, you must invert the data
if (depth == 1 && cmap && ((unsigned char *)(cmap->array))[0] ==
0x0) {
pixInvert(pix, pix);
}
pixEndianByteSwap(pix);
writeerror = 0;
if (depth != 24) { // typ 1 or 8 bpp
data = (unsigned char *)pixGetData(pix) + pixBpl * (height -
1);
for (i = 0; i < height; i++) {
if (mwrite(data, 1, fileBpl, mp) != fileBpl)
writeerror = 1;
data -= pixBpl;
}
}
else {
/* 32 bpp pix; 24 bpp file
* See the comments in pixReadStreamBMP() to
* understand the logic behind the pixel ordering below.
* Note that we have again done an endian swap on
* little endian machines before arriving here, so that
* the bytes are ordered on both platforms as:
Red Green Blue --
|-----------|------------|-----------|-----------|
*/
extrabytes = fileBpl - 3 * width;
line = pixGetData(pix) + pixWpl * (height - 1);
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
pword = line + j;
pel[1] = *((unsigned char *)pword + COLOR_RED);
pel[0] = *((unsigned char *)pword + COLOR_GREEN);
pel[2] = *((unsigned char *)pword + COLOR_BLUE);
if (mwrite(&pel, 1, 3, mp) != 3)
writeerror = 1;
}
if (extrabytes) {
for (k = 0; k < extrabytes; k++)
mwrite(&pel, 1, 1, mp);
}
line -= pixWpl;
}
}
// Restore to original state
pixEndianByteSwap(pix);
if (depth == 1 && cmap && ((unsigned char *)(cmap->array))[0] ==
0x0)
pixInvert(pix, pix);
if (writeerror) {
if (mp && mp->dst) free(mp->dst);
fprintf(stderr, "%s: image write fail\n", __FUNCTION__);
if (mp) free(mp);
return NULL;
}
unsigned char *buf = (unsigned char *)mp->dst;
if (mp) free(mp);
return buf;
}
unsigned char *WebpToMemoryBmp(size_t &size, PIX *pix)
{
if (!pix) {
fprintf(stderr, "%s: pix not defined\n", __FUNCTION__);
return NULL;
}
unsigned char *buf = NULL;
if ((buf = pixWriteMemoryBmp(size, pix)) == NULL) {
fprintf(stderr, "%s: pix not written to mem\n", __FUNCTION__);
return NULL;
}
return buf;
}
int main()
{
struct Pix *pixs;
puts("begin");
pixs = pixReadWebP("beep.webp");
if (pixs == NULL) {
fprintf(stderr, "Failed to read image\n");
return 1;
} else {
puts("read webp");
}
size_t size = 0;
unsigned char *buf = NULL;
if ((buf = WebpToMemoryBmp(size, pixs)) == NULL) {
fprintf(stderr, "Failed to copy image to memory bmp\n");
} else {
puts("converted to memory bmp");
}
pixDestroy(&pixs);
puts("freed");
FILE *fp = fopen("c:\\test.bmp", "wb");
fwrite(buf, size, 1, fp);
fclose(fp);
if (buf) free(buf);
return 0;
}