栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

索引位图制作、C++读写流程

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

索引位图制作、C++读写流程

和常见的16、24、32位色BMP格式不同,索引位图是一种使用调色板 + 8位色的位图格式,每个像素只占一个字节,像素值为0~255索引,其颜色保存在调色板对应位置数据

使用Photoshop制作索引位图

使用Photoshop打开已有的图片,再选择菜单【图像】、【模式】、【索引颜色…】
随后弹出的对话框中可选择对应的算法进行索引颜色整理,将当前图像的颜色归纳的256色之中
确定之后图像就变成索引位图了,再次通过菜单【图像】、【模式】、【颜色表…】,可以修改调色板内容
然后【存储为…】,保存为8位色BMP图片格式

索引位图文件格式

参考msdn文档:https://docs.microsoft.com/zh-cn/windows/win32/gdi/bitmap-storage,可知位图的存储格式为

BITMAPFILEHEADER格式

在头文件Wingdi.h中声明

成员说明
bfType0x4D42,表示BM
bfSize文件总的大小,包括BITMAPFILEHEADER size
bfReserved10
bfReserved20
bfOffBits图像数据(Color-index array)相对于文件头的起始位置
BITMAPINFOHEADER格式

在头文件Wingdi.h中声明

成员说明
biSize结构体BITMAPINFOHEADER的大小40
biWidth图像宽度
biHeight图像高度
biPlanes1
biBitCount索引位图为8
biCompressionBI_RGB表示未压缩
biSizeImage图像数据大小,通常是pitch x biHeight,
pitch是:biWidth * sizeof(pixel)的4字节对齐版本
biXPelsPerMeterpixels-per-meter
biYPelsPerMeterpixels-per-meter
biClrUsed索引位图为0,表示调色板有256色
biClrImportant0
C++中读取索引位图

假设需要将位图读到二维数组boost::multi_array img中

std::ifstream ifs("aaa.bmp", std::ios::binary);

//-		bfh	{bfType=19778 bfSize=787512 bfReserved1=0 ...}	tagBITMAPFILEHEADER
//		bfType	19778	unsigned short
//		bfSize	787512	unsigned long
//		bfReserved1	0	unsigned short
//		bfReserved2	0	unsigned short
//		bfOffBits	1078	unsigned long
BITMAPFILEHEADER bfh;
ifs.read((char*)&bfh, sizeof(bfh));
if (bfh.bfType != 0x4D42)
	return;

//-		bih	{biSize=40 biWidth=1024 biHeight=768 ...}	tagBITMAPINFOHEADER
//		biSize	40	unsigned long
//		biWidth	1024	long
//		biHeight	768	long
//		biPlanes	1	unsigned short
//		biBitCount	8	unsigned short
//		biCompression	0	unsigned long
//		biSizeImage	786434	unsigned long
//		biXPelsPerMeter	11808	long
//		biYPelsPerMeter	11808	long
//		biClrUsed	0	unsigned long
//		biClrImportant	0	unsigned long
BITMAPINFOHEADER bih;
ifs.read((char*)&bih, sizeof(bih));
if (bih.biCompression != BI_RGB || bih.biBitCount != 8)
	return;

// 位图每一行的数据字节长度是4的倍数
int pitch = (bih.biWidth * bih.biBitCount + 31) / 32 * 4;

// 逐行将数据读入二维数组
boost::multi_array img(boost::extents[bih.biHeight][bih.biWidth]);
for (int i = 0; i < bih.biHeight; i++)
{
	// Windows位图数据从下往上存储,所以需要反着读取
	long offset = bfh.bfOffBits + (bih.biHeight - i - 1) * pitch;
	ifs.seekg(offset, SEEK_SET);

	ifs.read((char*)&img[i][0], bih.biWidth * sizeof(unsigned char));
}
C++中写入索引位图

由于之前读取位图的bfh、bih之后,内存中就已经看到数据,所以依样画葫芦,再把数据写回文件,但由于位图宽度数据需要4的倍数,所以建议将原来的数组进行相应扩大

// boost::multi_array img(...);
// 需要将二维数组img的宽度扩大到4的倍数
img.resize(boost::extents[img.shape()[0]][boost::alignment::align_up(img.shape()[1], 4)]);

std::ofstream ofs(path, std::ios::binary, _SH_DENYRW);

BITMAPFILEHEADER bfh = { 0 };
BITMAPINFOHEADER bih = { 0 };
bfh.bfType = 0x4D42;
bfh.bfOffBits = sizeof(bfh) + sizeof(bih) + sizeof(RGBQUAD) * 256;
bfh.bfSize = bfh.bfOffBits + img.num_elements() * sizeof(unsigned char);
bih.biSize = sizeof(bih);
bih.biWidth = img.shape()[1];
bih.biHeight = img.shape()[0];
bih.biPlanes = 1;
bih.biBitCount = 8;
bih.biCompression = BI_RGB;
bih.biSizeImage = img.num_elements() * sizeof(unsigned char);
bih.biXPelsPerMeter = 11808;
bih.biYPelsPerMeter = 11808;
bih.biClrUsed = 0;
bih.biClrImportant = 0;

ofs.write((char*)&bfh, sizeof(bfh));
ofs.write((char*)&bih, sizeof(bih));

// 这里写入灰度数据到调色板数据,可在Photoshop面板中更改
for (int p = 0; p < 256; p++)
{
	RGBQUAD q = { p, p, p, 0 };
	ofs.write((char*)&q, sizeof(q));
}

for (int i = 0; i < img.shape()[0]; i++)
{
	ofs.write((char*)&img[img.shape()[0] - i - 1][0], img.shape()[1] * sizeof(unsigned char));
}

参考:
https://docs.microsoft.com/zh-cn/windows/win32/gdi/bitmap-storage
https://blog.csdn.net/Wintalen/article/details/1014820
https://sunriver2000.blog.csdn.net/article/details/104251831

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1033195.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号