0

我正在编写一个程序来为我的化学实验室的一些数据创建图像。我们正在研究元素等的排放,并编写数据以包括通过光谱仪显示频带的示例。我认为编写一个程序来为我做这件事会很整洁,而不是彩色铅笔,所以一切都很整洁。另外,我没有彩色铅笔。

我将图像数据作为 RGB 值存储在一个 int 数组中,长度为我想要的图像的宽度 * 高度,宽度为 320,高度为 50。最后我将它们作为 24 位 BGR 排序写入文件像素。

在将数据写入文件之前,我当然会尝试写入 BMP 标头。MSDN 有一个图表来显示文件部分的一般顺序,其中包括一些关于 RBGQuads 的内容,但在段落解释中没有描述如何使用它们。我认为它们是可选的?我发现这张图表显示了我所期望的标题的唯一强制性部分:http: //www.fastgraph.com/help/bmp_header_format.html,所以我认为我在正确的轨道上。

因此,我开始使用字节顺序,因为在尝试使用 Paint 或在 Windows 图像查看器中打开时,我的文件总是“损坏或损坏”。

所有消息来源都说 BMP 标头是小端的。我尝试在写入时双向交换字节顺序,但仍然无法打开文件。自制损坏文件还有其他常见的罪魁祸首吗?

这是我存储标题信息的地方:

typedef struct
{
  char type[2];
  unsigned int fsize;
  unsigned short res1;
  unsigned short res2;
  unsigned int data_offset;
} BMPFILEHEADER;

typedef struct
{
  unsigned int sizebytes;
  int  width_pix;
  int  height_pix;                   // negative for top down.
  unsigned short  planes;            // must be 1
  unsigned short  bits_per_pix;
  unsigned int compression;          // zero for BI_RGB (uncompressed)
  unsigned int SizeImage;            // may be set to 0 for BI_RGB images.
  int  pix_per_meter_x;
  int  pix_per_meter_y;
  unsigned int color_used;           // set to 0
  unsigned int color_important;      // set to 0
} BMPINFOHEADER;

当然,我是按这个顺序写的。-- 类型是 char[] 因为无论如何它必须是值 'B' 'M'。

首先我尝试用 fwrite() 编写它们:

  fwrite ( &header , 1 , 14 , fhandle );
  fwrite ( &headerext , 1 , 40 , fhandle );

然后我试着像这样写它们:

  fputc ( 'B' , fhandle );
  fputc ( 'M' , fhandle );
  fw_little_end ( fhandle , &header.fsize , 4 );
  fw_little_end ( fhandle , &header.res1 , 2);
  fw_little_end ( fhandle , &header.res2 , 2);
  fw_little_end ( fhandle , &header.data_offset , 4);

其中 fw_little_end() 看起来像这样:

void fw_little_end ( FILE * fhandle , void * data , int size )
{
  int i;
  char * cdata = data;
  for ( i = size; i > 0; i-- )
  {
    fputc ( *(cdata+i-1) , fhandle );
  }
}

可能是最初它被写入文件小端并且我的fw_()函数命名错误,但为了确定,我也从 size-0 和 0-size 尝试过它。

如果听起来相关,这就是写入数据的地方:

  int shift1 = 256;
  int shift2 = 256*256;
  for ( i = 0; i < img_size; i++)
  {
    fputc ( (unsigned char) (data[i]%256) , fhandle ); // B
    fputc ( (unsigned char) (data[i]/shift1)%256 , fhandle ); // G
    fputc ( (unsigned char) (data[i]/shift2)%256 , fhandle ); // R
  } // theoretically B only needs the typecast, not the %256 but oh well lol.

这篇文章已经很长了,希望我已经包含了足够多的相关代码。我很抱歉,因为我知道那里有很多信息,除此之外对我来说没有任何意义。如果有更好的方式来做这些事情,我很乐意指出正确的方向。

因此,我感谢您的所有意见。

4

1 回答 1

0

我发布了一个直接的答案:

/* ======================================================================================== */
BOOL SaveBitmap24(LPCTSTR pszFilename, LPBYTE pPixelColorTriplets, INT nWidth, INT nHeight)
{
    BOOL bState = FALSE;
    // sizes
    INT nOfsetToPixel = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPCOREHEADER);
    INT nPixelSize = nWidth * nHeight * 3;
    INT nFileSize = nOfsetToPixel + nPixelSize;
    // setup bitmap file header --------------
    BITMAPFILEHEADER bmFileHeader = { 0 };
    // "BM" signature
    bmFileHeader.bfType = 0x4D42;
    bmFileHeader.bfOffBits = nOfsetToPixel;
    bmFileHeader.bfSize = nFileSize;
    // setup bitmap info header --------------
    BITMAPCOREHEADER bmCoreHeader = { 0 };
    bmCoreHeader.bcSize = sizeof(BITMAPCOREHEADER);
    bmCoreHeader.bcWidth = nWidth;
    bmCoreHeader.bcHeight = nHeight;
    bmCoreHeader.bcBitCount = 24;
    bmCoreHeader.bcPlanes = 1;
    // write file -----------------------
    FILE *fileBitmap = fopen(pszFilename, _T("wb"));
    if (fileBitmap)
    {   fwrite(&bmFileHeader, sizeof(BITMAPFILEHEADER), 1, fileBitmap);
        fwrite(&bmCoreHeader, sizeof(bmCoreHeader), 1, fileBitmap);
        fwrite(pPixelColorTriplets, nPixelSize, 1, fileBitmap);
        fclose(fileBitmap);
        bState = TRUE;
    }
    return bState;
}
于 2013-02-11T16:09:11.490 回答