2013-02-11 3 views
1

저는 지난 며칠 동안이 문제를보고있는 사람이고 전적으로 당황 스럽습니다. OpenSuse Linux에서 Cairo 그래픽 라이브러리를 사용하여 디스플레이 할 Windows 비트 맵 이미지를 해석하려고합니다. 간단히 말해, 각 픽셀의 색상 정보를 배열로 가져와 카이로 (Cairo)에 공급하면됩니다. pixeldata [i] = someColor, 이미지의 모든 픽셀에 적용됩니다. 지금까지 비트 맵 헤더를 파싱하는 방법을 알아 냈고 24 비트 비트 맵을 표시하는 데 효과적이었습니다.8 비트 비트 맵에서 픽셀 데이터를 작성하고 bmiColor 테이블 정보에 액세스하는 중

하지만 지금은 8 비트 비트 맵을 표시하는 데 어려움을 겪고 있으며 다루기 힘든 비 직관적 인 짐승입니다. 이미지를 표시 할 수는 있지만 표시되는 색상이 잘못되었습니다 ... 단지 프로그램을 실행할 때마다 변경됩니다! : P 필자는 bmiColors 팔레트 배열을 잘못 읽고 해석하고 있다고 생각합니다. 다음은 픽셀 배열을 만드는 나의 오랜 인터넷 연구에서 함께 만든 관련 코드입니다 (이 시점에서 헤더 정보는 이미 구문 분석되었으며 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 and 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; /* Important colors */ 
    RGBQUAD bmiColors [1]; 
} BITMAPINFOHEADER; 
#pragma pack() 

// Function sets up and returns color index for 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; 
    } 
    return 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 to contain the whole file: 
    buffer = (char*) malloc (sizeof(char) * lSize); 
    if (buffer == NULL) {fputs ("Memory error", stderr); exit (2);} 

    // copy the file into the 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; 

    for (iy = 0; iy < bmi->height; ++iy) 
    { 
    for (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); 
} 

아이디어가 있으십니까? Windows가 아닌 환경에서 작업 중이므로 많은 Windows 중심 함수를 C++에서 작동하도록 변환해야합니다. 어떤 도움을 주셔서 감사합니다, 감사합니다!

업데이트 : cbranch의 추천에

덕분에, 나는 숯불는 4 바이트의 구조를 유지하려면, 대신 긴/INT의 특성을 가지도록 RGBQUAD를 수정했습니다. 이렇게하면 색상이 계속 변경되어 문제가 해결되었습니다. 그러나, 이상하게 색상은 여전히 ​​꺼져 있습니다. 지금은 검정색 배경에 녹색 다이아몬드의 간단한 이미지를 표시하려고하지만 어떤 이유로 다이아몬드가 노란색으로 표시됩니다. 어떤 아이디어?

또한 실수로 원래 게시물의 구조체 주변에서 "#pragma pack()"지시문을 남겨두고 게시물에 추가했습니다.

+2

RGBQUAD의 멤버는 'longs'이 아닌 단일 바이트입니다. 전체 RGBQUAD 구조체는 4 바이트입니다. – cbranch

+0

@cbranch - 감사합니다. 이제 문제가 해결되어 프로그램을 실행할 때마다 색상이 바뀌지 않습니다. 그러나 표시된 색상은 여전히 ​​꺼져 있습니다. ATM 검정색 배경에 작고 간단한 녹색 다이아몬드 이미지를 표시하려하지만 녹색 다이아몬드가 노란색으로 나옵니다. 어떤 아이디어? – user1930581

+0

RGBQUAD 구조와 같은 사운드는 거꾸로입니다. –

답변

3

RGBQuad는 4 바이트 여야합니다.

이 매크로 :

#define RGB(r, g, b) ((long)(((char)(r) | ((char)((short)(g)) << 8)) | (((char)(b)) << 16))) 

는 문제가있다. 아마 사인 연장이 될거야. 완전한 초록 픽셀은 g == 0xFF가됩니다. 당신은 그것을 (서명 된) 짧은 것으로 형변환 했으므로 아마도 부호 확장 (0xFFFF)을 얻고 그 다음으로 이동합니다. 이제 빨간색과 초록색을 전체 값으로 설정 했으므로 노란색으로 보입니다.

비트 조작을 할 때 거의 항상 부호없는 값을 사용하려고합니다.

+0

이것은 내 자신의 역전 된 RGB 구조에 비해 훨씬 더 그럴듯 해 보입니다. 나는 부호없는 값을 자동으로 사용하므로 오랫동안이 작업을 해왔다. –

+0

@ Adrian - 그게 다야, 많이 고마워! : D Gah, 코드의 수정본을 여러 번 보았습니다. 실제로 RGB 함수에서 "unsigned"라는 캐스트를 사용 했었지만 아무 것도 변경하지 않은 것처럼 보였습니다. 어쨌든 그들은 코드 개발 과정에서이 시점에서 차이를 만들고 있습니다. 감사합니다 여러분! – user1930581