1

私は過去数日間この問題を検討しているn00bであり、私はただ立ち往生しています。私はOpenSuseLinuxで、Cairoグラフィックライブラリを使用して表示するWindowsビットマップイメージを解釈しようとしています。簡単に言えば、各ピクセルの色情報を配列に取得し、それをCairoにフィードする必要があります(例:pixeldata [i] = someColor)、画像内のすべてのピクセルについて。これまでのところ、ビットマップヘッダーを解析する方法を理解し、24ビットビットマップを表示するためにうまく機能するようにしました。

しかし、今は8ビットのビットマップも表示するのに苦労しており、扱いにくく、直感的ではない獣でした。画像を表示することはできますが、表示される色が間違っています...それだけでなく、プログラムを実行するたびに色が変わります!:PIは、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以外の環境で作業しているため、C++で動作するように多くのWindows中心の関数を変換する必要があることに注意してください。どんな助けでもありがたいです、ありがとう!

更新:

cbranchの推奨のおかげで、RGBQUADを4バイト構造のままにするために、long/intではなくchar属性を持つように変更しました。これにより、色が絶えず変化する問題が修正されました。しかし、不思議なことに色はまだずれています。現時点では、黒の背景に緑のひし形の単純な画像を表示しようとしていますが、何らかの理由でひし形が黄色で表示されています。何か案は?

また、元の投稿の構造体の周りから誤って「#pragma pack()」ディレクティブを省略してしまったことに気づき、それらを投稿に追加しました。

4

1 に答える 1

3

RGBQuadは4バイトである必要があります。

このマクロ:

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

問題があります。おそらく符号拡張を取得しています。完全な緑色のピクセルはg==0xFFになります。これを(符号付き)shortにキャストするので、おそらく符号拡張(0xFFFF)を取得してから、シフトします。これで、赤と緑が完全な値に設定されたため、黄色に見えます。

ビット単位の操作を行うときは、ほとんどの場合、符号なしの値を使用する必要があります。

于 2013-02-11T20:38:50.873 に答える