【问题标题】:Creating BMP in pure C++在纯 C++ 中创建 BMP
【发布时间】:2016-04-15 03:18:39
【问题描述】:

感谢您的帮助。这是最终版本。 工作版本

BMPHead.znak1='B';
BMPHead.znak2='M';
BMPHead.bfSize=40;
BMPHead.bfReserved1 = 0;
BMPHead.bfReserved1 = 0;
BMPHead.bfOffBits=54;
BMPHead.biSize=40;
BMPHead.biWidth=CSVHead.depth_pxsize ;
BMPHead.biHeight=CSVHead.lateral_pxsize;
BMPHead.biPlanes=1;
BMPHead.biBitCount=32;
BMPHead.biCompression = 0;
BMPHead.biSizeImage = ((CSVHead.lateral_pxsize * CSVHead.depth_pxsize)*4);
BMPHead.biXPelsPerMeter = 0;
BMPHead.biYPelsPerMeter = 0;
BMPHead.biClrUsed = 0;
BMPHead.biClrImportant =0;



void zamiana_danych(int &EndOfHead, float line[], csvh &CSVHead, bmph BMPHead, float &max, float &min)
{   unsigned char bit_empty=0;
    float tmp[500];
    ifstream obraz;
    fstream bitmapa("POP_OCT.bmp");
    obraz.open("POP_OCT.csv", ios::binary);
    obraz.seekg(EndOfHead, ios_base::beg);
    bitmapa.seekg(BMPHead.bfOffBits, ios_base::beg); // this part was missing
    for( int numb=0; numb < CSVHead.depth_pxsize; numb++ )
        {
        //wczytanie jednego wiersza dancyh
        for(int i=0; i<CSVHead.lateral_pxsize; i++)
            { //wczytanie komorki danych
                obraz>>line[i];
                obraz.seekg(+1, ios_base::cur);
                tmp[i]=((max-min) / 255) * line[i] - min;
                unsigned char pixel[4]={tmp[i],tmp[i],tmp[i],0};
                bitmapa.write((char*)&pixel, sizeof(pixel));
            }
        }
      bitmapa.close();
      obraz.close();

问题 我需要在不使用非标准库的情况下在 C++ 中创建 BMP,但我仍然有一些错误。我知道有一些类似的主题,但我仍然不清楚如何使这件事发挥作用。

文件已创建,但当我尝试打开它时,照片浏览器显示:

“Windows Image Viewer 无法打开图像,因为文件太大或损坏”。

我不确定问题出在标题还是像素写入中。

代码如下:

#include<iostream>
#include<fstream>
#include<cstring>
#include <stdlib.h>
using namespace std;


struct bmph{
unsigned short int bfType; // instead of this I use znak1 and znak2
unsigned long int bfSize;
unsigned short int bfReserved1;
unsigned short int bfReserved2;
unsigned long int bfOffBits;
unsigned long int biSize;
unsigned long int biWidth;
unsigned long int biHeight;
unsigned short int biPlanes;
unsigned short int biBitCount;
unsigned long int biCompression;
unsigned long int biSizeImage;
unsigned long int biXPelsPerMeter;
unsigned long int biYPelsPerMeter;
unsigned long int biClrUsed;
unsigned long int biClrImportant;
};


int main()
{
unsigned char pixel[4]={255,255,255,0};
char znak1='B';
char znak2='M';
bmph bmpheader;

ofstream moje_bmp("tworzBMP.bmp");

bmpheader.bfSize=40 + (500*999)*4;
bmpheader.bfReserved1 = 0;
bmpheader.bfReserved1 = 0;
bmpheader.bfOffBits=54;
bmpheader.biSize=40;
bmpheader.biWidth=500;
bmpheader.biHeight=999;
bmpheader.biPlanes=1;
bmpheader.biBitCount=4;
bmpheader.biCompression = 0;
bmpheader.biSizeImage = (500*999)*4;
bmpheader.biXPelsPerMeter = 0;
bmpheader.biYPelsPerMeter = 0;
bmpheader.biClrUsed = 0;
bmpheader.biClrImportant =0;


moje_bmp << znak1 <<znak2;
moje_bmp.write((char*)&bmpheader.bfSize, sizeof(bmpheader.bfSize));
moje_bmp.write((char*)&bmpheader.bfReserved1, sizeof(bmpheader.bfReserved1));
moje_bmp.write((char*)&bmpheader.bfReserved1, sizeof(bmpheader.bfReserved1));
moje_bmp.write((char*)&bmpheader.bfOffBits, sizeof(bmpheader.bfOffBits));
moje_bmp.write((char*)&bmpheader.bfSize, sizeof(bmpheader.bfSize));
moje_bmp.write((char*)&bmpheader.biWidth, sizeof(bmpheader.biWidth));
moje_bmp.write((char*)&bmpheader.biHeight, sizeof(bmpheader.biHeight));
moje_bmp.write((char*)&bmpheader.biPlanes, sizeof(bmpheader.biPlanes));
moje_bmp.write((char*)&bmpheader.biBitCount, sizeof(bmpheader.biBitCount));
moje_bmp.write((char*)&bmpheader.biCompression, sizeof(bmpheader.biCompression));
moje_bmp.write((char*)&bmpheader.biSizeImage, sizeof(bmpheader.biSizeImage));
moje_bmp.write((char*)&bmpheader.biXPelsPerMeter, sizeof(bmpheader.biXPelsPerMeter));
moje_bmp.write((char*)&bmpheader.biYPelsPerMeter, sizeof(bmpheader.biYPelsPerMeter));
moje_bmp.write((char*)&bmpheader.biClrUsed, sizeof(bmpheader.biClrUsed));
moje_bmp.write((char*)&bmpheader.biClrImportant, sizeof(bmpheader.biClrImportant));

   for(int tx=0; tx<500;tx++)
        {
                for(int ty=0; ty<999;ty++)
                {
                   moje_bmp.write((char*)&pixel, sizeof(pixel));
                }
        }
moje_bmp.close();
return 0;
}

在上面的示例中所有这些都有效,但在我的主项目中却没有。以下是主项目中的功能和相同的结果: “Windows Image Viewer 无法打开图像,因为文件太大或损坏”。

void glowa_bmp(bmph &BMPHead, csvh &CSVHead)
{
ofstream bitmapa("bitmapa.bmp", ios::binary);

//przypisanie wartosci naglowka
BMPHead.znak1='B';
BMPHead.znak2='M';
BMPHead.bfSize=54;
BMPHead.bfReserved1 = 0;
BMPHead.bfReserved1 = 0;
BMPHead.bfOffBits=54;
BMPHead.biSize=40;
BMPHead.biWidth=CSVHead.depth_pxsize ;
BMPHead.biHeight=CSVHead.lateral_pxsize;
BMPHead.biPlanes=1;
BMPHead.biBitCount=32;
BMPHead.biCompression = 0;
BMPHead.biSizeImage = ((CSVHead.lateral_pxsize * CSVHead.depth_pxsize)*4);
BMPHead.biXPelsPerMeter = 0;
BMPHead.biYPelsPerMeter = 0;
BMPHead.biClrUsed = 0;
BMPHead.biClrImportant =0;

//zapisanie naglowka w pliku
bitmapa << BMPHead.znak1 << BMPHead.znak2;
bitmapa.write((char*)&BMPHead.bfSize, sizeof(BMPHead.bfSize));
bitmapa.write((char*)&BMPHead.bfReserved1, sizeof(BMPHead.bfReserved1));
bitmapa.write((char*)&BMPHead.bfReserved1, sizeof(BMPHead.bfReserved1));
bitmapa.write((char*)&BMPHead.bfOffBits, sizeof(BMPHead.bfOffBits));
bitmapa.write((char*)&BMPHead.bfSize, sizeof(BMPHead.bfSize));
bitmapa.write((char*)&BMPHead.biWidth, sizeof(BMPHead.biWidth));
bitmapa.write((char*)&BMPHead.biHeight, sizeof(BMPHead.biHeight));
bitmapa.write((char*)&BMPHead.biPlanes, sizeof(BMPHead.biPlanes));
bitmapa.write((char*)&BMPHead.biBitCount, sizeof(BMPHead.biBitCount));
bitmapa.write((char*)&BMPHead.biCompression, sizeof(BMPHead.biCompression));
bitmapa.write((char*)&BMPHead.biSizeImage, sizeof(BMPHead.biSizeImage));
bitmapa.write((char*)&BMPHead.biXPelsPerMeter,      sizeof(BMPHead.biXPelsPerMeter));
bitmapa.write((char*)&BMPHead.biYPelsPerMeter, sizeof(BMPHead.biYPelsPerMeter));
bitmapa.write((char*)&BMPHead.biClrUsed, sizeof(BMPHead.biClrUsed));
bitmapa.write((char*)&BMPHead.biClrImportant, sizeof(BMPHead.biClrImportant));

bitmapa.close();
}




void zamiana_danych(int &EndOfHead, float line[], csvh &CSVHead, float &max, float &min)
{   unsigned char bit_empty=0;
    float tmp[500];
    ifstream obraz;
    ofstream bitmapa("bitmapa.bmp", ios::binary);
    obraz.open("POP_OCT.csv", ios::binary);
    obraz.seekg(EndOfHead, ios_base::beg);
    for( int numb=0; numb < CSVHead.depth_pxsize; numb++ )
        {
        //wczytanie jednego wiersza dancyh
        for(int i=0; i<CSVHead.lateral_pxsize; i++)
            { //wczytanie komorki danych
                obraz>>line[i];
                obraz.seekg(+1, ios_base::cur);
                tmp[i]=((max-min) / 255) * line[i] - min;
                unsigned char pixel[4]={tmp[i],tmp[i],tmp[i],0};
                bitmapa.write((char*)&pixel, sizeof(pixel));
            }
        }
      bitmapa.close();
      obraz.close();
}

【问题讨论】:

  • 你没有设置,也没有写bfReserved2。这可能不是问题,因为您要写两次bfReserved1。但这是“错误的”。你的编译器中的sizeof(long) 是什么?
  • BMPHead.bfSize=54; 仍然是错误的。请参阅我的答案 + cmets :) - 它必须是文件的总大小。
  • @Danny_ds 应该是这样,但它是这样工作的......不知道如何
  • @Artur - 可能取决于软件(例如,某些软件可以使用文件长度而不是此字段,但值应该是正确的)。但是我的评论是针对您编辑的答案:在上面的示例中所有这些都有效,但在我的主项目中却没有。

标签: c++ bmp


【解决方案1】:

您是否尝试过这种更正:

ofstream moje_bmp("tworzBMP.bmp", std::ios::binary | std::ios::out);

我相信 std::ofstream 需要文本输出而不是二进制,所以你必须覆盖它。

另外,你可以参考这个:

https://web.archive.org/web/20080912171714/http://www.fortunecity.com/skyscraper/windows/364/bmpffrmt.html

而不是使用 'unsigned short int' 之类的,尝试使用 std::uint16_t 获取 2 字节值,或使用 std::uint32_t 获取四字节值等。

【讨论】:

  • 是的,我自己试了一下,发现不行,这意味着你的结构体成员的实际大小可能有问题。
【解决方案2】:
bmpheader.bfSize=40 + (500*999)*4;

您需要添加 54 而不是 40:

  • 位图文件头:14
  • BITMAPINFOHEADER:40

你们俩在struct bmph中合并。

因此:54 + (500*999)*4;,即生成文件的总大小。

bmpheader.biBitCount=4;

bmpheader.biBitCount 应为 32(RGB 为 24,RGBA 为 32)。


另外,如果您可以确保struct bmph 的填充是好的(即没有填充 - 不确定 Linux 的设置,例如 Windows 中的 #pragma pack),那么您可以将整个结构写在一个去吧。

正如@fleebness 已经建议的那样,请确保在您的结构中使用 fixed 类型,这样它们就不会根据您正在编译的系统而改变。

【讨论】:

  • biBitCount=32 在这种情况下,因为它每个像素有四个字节。 4 表示每像素四位,读者显然会发现像素大小和数量以及对象之间的差异。
  • @MatsPetersson - 是的,如果当然 - 在这里查看错误的数据。 4不会做。
  • 我设置了bmpheader.bfSize=40;bmpheader.biBitCount=32; 现在图像正确,非常感谢!
  • @Artur - 很高兴它成功了 :) - 但我想你的意思是 54?
  • 不,严重的是 40 :D 所以 bfSizebiSize 是一样的
猜你喜欢
  • 1970-01-01
  • 2012-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多