在纯 C++ 中创建 BMP
Creating BMP in pure C++
感谢您的帮助。这是最终版本。
工作版本
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 can not open the image, because the file is too big or broken".
我不确定问题出在页眉还是像素写入。
这是代码:
#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 can not open the image, because the file is too big or broken".
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();
}
你试过这个更正吗:
ofstream moje_bmp("tworzBMP.bmp", std::ios::binary | std::ios::out);
我相信std::ofstream需要文本输出而不是二进制,所以你必须覆盖它。
另外,你可以参考这个:
而不是使用 'unsigned short int' 之类的东西,尝试像 std::uint16_t 用于 2 字节值,或 std::uint32_t 用于四字节值等。
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 的设置,它是 #pragma pack
in Windows 例如),那么你可以一次写出整个结构。
并且正如@fleebness 已经建议的那样,确保在结构中使用 fixed 类型,因此它们不会根据您正在编译的系统而改变。
感谢您的帮助。这是最终版本。 工作版本
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 can not open the image, because the file is too big or broken".
我不确定问题出在页眉还是像素写入。
这是代码:
#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 can not open the image, because the file is too big or broken".
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();
}
你试过这个更正吗:
ofstream moje_bmp("tworzBMP.bmp", std::ios::binary | std::ios::out);
我相信std::ofstream需要文本输出而不是二进制,所以你必须覆盖它。
另外,你可以参考这个:
而不是使用 'unsigned short int' 之类的东西,尝试像 std::uint16_t 用于 2 字节值,或 std::uint32_t 用于四字节值等。
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 的设置,它是 #pragma pack
in Windows 例如),那么你可以一次写出整个结构。
并且正如@fleebness 已经建议的那样,确保在结构中使用 fixed 类型,因此它们不会根据您正在编译的系统而改变。