windows - C++ building pixel data from 8-bit bitmap and getting access to bmiColor table information -
i'm n00b who's been looking @ problem past few days , i'm plain stuck. i'm working in opensuse linux trying interpret windows bitmap images display using cairo graphics library. put, need color info each pixel array , feed cairo, e.g. pixeldata[i] = somecolor, pixels in image. far i've figured out how parse through bitmap headers , got working great displaying 24-bit bitmaps.
but, i'm struggling 8-bit bitmaps display well, , it's been unwieldy, unintuitive beast wrangle. i'm able image display, colors displayed wrong... , not that, alter every time run program! :p think i'm accessing , interpreting bmicolors palette array incorrectly. here's relevant code i've pieced lengthy net research builds pixel array (note, point in code, header info has been parsed , available in objects m_bmpinfoheader , m_bmpheader):
#define rgb(r, g, b) ((long)(((char)(r) | ((char)((short)(g)) << 8)) | (((char)(b)) << 16 ))) #pragma pack (2) typedef struct tagrgbquad { long rgbblue; long rgbgreen; long rgbred; int rgbreserved; } rgbquad; typedef struct { char verifier[2]; unsigned int size; unsigned short int reserved1, reserved2; unsigned int offset; } bitmapheader; typedef struct { unsigned int size; /* header size in bytes */ signed int width, height; /* width , height of image */ unsigned short int planes; /* number of colour planes */ unsigned short int bits; /* bits per pixel */ unsigned int compression; /* compression type */ unsigned int imagesize; /* image size in bytes */ int xresolution,yresolution; /* pixels per meter */ unsigned int ncolors; /* number of colors */ unsigned int importantcolors; /* of import colors */ rgbquad bmicolors [1]; } bitmapinfoheader; #pragma pack() // function sets , returns color index bitmap. long bitmapdef::getcolorinx (int numbits, char* data, long offset) { long inx; switch (numbits) { case 1: inx = data[offset >> 3]; offset &= 7; inx >>= offset; inx &= 0x01; break; case 2: inx = data[offset >> 2]; offset &= 3; offset <<= 1; inx >>= offset; inx &= 0x03; break; case 4: inx = data[offset >> 1]; if (!(offset & 1)) { inx >>= 4; } inx &= 0x0f; break; case 24: { offset *= 3; inx = *((long*) &data[offset]); char r = getbvalue(inx); char g = getgvalue(inx); char b = getrvalue(inx); inx = ((r << 16) + (g << 8) + b); break; } case 8: default: inx = data[offset] & 0xff; break; } homecoming inx; } void bitmapdef::build8bitpixeldata() { m_pixeldata = new unsigned int[m_bmpinfoheader.width * m_bmpinfoheader.height]; file * pfile; long lsize; char * buffer; size_t result; pfile = fopen ((const char *)m_filename, "rb" ); if (pfile==null) { fputs ("file error", stderr); exit (1); } // obtain file size: fseek (pfile , 0 , seek_end); lsize = ftell (pfile); rewind (pfile); // allocate memory contain whole file: buffer = (char*) malloc (sizeof(char) * lsize); if (buffer == null) {fputs ("memory error", stderr); exit (2);} // re-create file buffer: result = fread (buffer, 1, lsize, pfile); if (result != lsize) {fputs ("reading error",stderr); exit (3);} bitmapheader* bmfh = (bitmapheader*) (&(buffer[0])); char* bmp = (char*) &buffer[m_bmpheader.offset]; bitmapinfoheader * bmi = (bitmapinfoheader*) &buffer[sizeof(*bmfh)]; std::cout<<"\nsize: "<<bmi->size<<std::endl; std::cout<<"width: "<<bmi->width<<std::endl; std::cout<<"height: "<<bmi->height<<std::endl; std::cout<<"planes: "<<bmi->planes<<std::endl; std::cout<<"bits: "<<bmi->bits<<std::endl; std::cout<<"annnd compression: "<<bmi->planes<<std::endl; int ix, iy; int position = 0; (iy = 0; iy < bmi->height; ++iy) { (ix = 0; ix < bmi->width; ++ix) { int offset = (m_bmpinfoheader.height - 1 - iy) * m_bmpinfoheader.width; offset += ix; //std::cout<<"offset: "<<offset<<" bmp[offset]: "<<bmp[offset] << " " ; long inx = getcolorinx (m_bmpinfoheader.bits, databuf, offset); //std::cout<<inx<<" "; m_pixeldata[position] = rgb(bmi->bmicolors[inx].rgbred, bmi->bmicolors[inx].rgbgreen, bmi->bmicolors[inx].rgbblue); position++; } } fclose (pfile); free (buffer); }
any ideas? please note i'm working in non-windows environment, i've had translate many windows-centric functions work in c++. help appreciated, thanks!
updates:
thanks cbranch's recommendation, modified rgbquad have char attributes instead of long/int, in order remains 4-byte structure. fixed issue colors changing. however, strangely colors still off. @ moment i'm trying display simple image of greenish diamond on black background, reason diamond displaying yellow. ideas?
also, noticed accidentally left "#pragma pack()" directives out around structs in original post, , added them post.
rgbquad should 4 bytes.
this macro:
#define rgb(r, g, b) ((long)(((char)(r) | ((char)((short)(g)) << 8)) | (((char)(b)) << 16 )))
is problematic. you're getting sign extension. total greenish pixel have g == 0xff. cast (signed) short, sign extension (0xffff), , shift. you've got reddish , greenish set total values , looks yellow.
when doing bitwise manipulation, want utilize unsigned values.
c++ windows bitmap opensuse
No comments:
Post a Comment