IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> c++将24位bmp转8位bmp灰度 8位bmp灰度反色,24位转3张8位bmp灰度图 -> 正文阅读

[C++知识库]c++将24位bmp转8位bmp灰度 8位bmp灰度反色,24位转3张8位bmp灰度图

首先我们需要定义组成bmp的四部分的结构体
?
#pragma once

using BYTE = unsigned char;//1
using WORD  = unsigned short;//2
using DWORD = unsigned int;//4
using LONG  = unsigned long;//4

#pragma pack(push)
#pragma pack(2) //每次读取两个字节,以确保为结构体创建的内存刚刚好是我们想要的
struct BITMAPFILEHEADER {//定义bitmap文件头结构
	WORD  bfType;//记录文件标识符,BM
	DWORD bfSize;//记录文件的大小:文件头,信息头,颜色表,颜色数据
	WORD  bfReserved1;//保留字 0
	WORD  bfReserved2;//保留字 0
	DWORD bfOffBits;//颜色数据距文件头的偏移量
};

//定义位图信息头结构
struct BITMAPINFOHEADER {
	DWORD biSize;//本结构体的大小
	LONG  biWidth;//位图的宽:像素
	LONG  biHeight;//位图的高:像素
	WORD  biPlanes;//为平面数(一般为1)
	WORD  biBitCount;//每个像素所需的位数:1,4,8,16,24,32
	DWORD biCompression;//位图压缩类型(一般不压缩,取0)
	DWORD biSizeImage;//位图的大小
	LONG  biXPelsPerMeter;//水平分辨率 0代表取标准值
	LONG  biYPelsPerMeter;//垂直分辨率 0代表取标准值
	DWORD biClrUsed;//颜色数 标准取0 计算方法为2的biBitCount次方
	DWORD biClrImportant;//重要颜色数 标准取0
};

//颜色表
struct RGBQUAD {
	BYTE rgbBlue;//蓝
	BYTE rgbGreen;//绿
	BYTE rgbRED;//红
	BYTE rgbReserved;//保留字 0
};
#pragma pack(pop)

?构建可以读取bmp的类bitmap

#pragma once
#include "bitmapQuad.h"
#include <iostream>
#include <fstream>

class bitmap {
private:
	FILE* m_rfp;//读入文件指针
	FILE* m_wfp;//写入文件指针
	FILE* m_wfp1;//写入文件指针
	FILE* m_wfp2;//写入文件指针
	BITMAPFILEHEADER* m_pbfHeader;//文件头指针
	BITMAPINFOHEADER* m_pbiHeader;//位图信息头指针
	RGBQUAD* m_prgbQuad;//颜色表指针
	BYTE* m_pImgData;//位图数据指针
	DWORD m_imgSize;//位图数据大小

private:
	inline void readFileHeader(BITMAPFILEHEADER* bmFileHeader);//读取文件头数据
	inline void readInfoHeader(BITMAPINFOHEADER* bmInfoHeader);//读取信息头数据
	inline void readRgbQuad(RGBQUAD* rgbQuad, const int& rgbQuadSize);//读取颜色表数据
	inline void readImgData(BYTE* pImgData, const DWORD& imgSize);//读取位图数据

private:
	inline void writeFileHeader(BITMAPFILEHEADER* pbfHeader);//读取文件头数据
	inline void writeInfoHeader(BITMAPINFOHEADER* pbiHeader);//读取信息头数据
	inline void writeRgbQuad(RGBQUAD* prgbQuad, const int& rgbQuadSize);//读取颜色表数据
	inline void writeImgData(BYTE* pImgData, const DWORD& imgSize);//读取位图数据

private:
	void createGrey_8();//创建8位灰度颜色表

public:
	bitmap(const char* readFilePath, const char* writeFilePath);
	bitmap(const char* readFilePath, const char* writeFilePath0, const char* writeFilePath1, const char* writeFilePath2);
	~bitmap();
	void rgb24_to_grey8();//24位图转为8位灰度图
	void grey8_to_antiGrey8();//8位图反色
	void rgb24_to_3grey8();//24位图分离为3个8位灰度图

};

?实现

#include "bitmap.h"

#pragma region bmp文件四部分的读入
/*读取文件头*/
inline
void bitmap::readFileHeader(BITMAPFILEHEADER* bmFileHeader) {
	fread(bmFileHeader, sizeof(BITMAPFILEHEADER), 1, m_rfp);
}

/*读取信息头*/
inline
void bitmap::readInfoHeader(BITMAPINFOHEADER* bmInfoHeader) {
	fread(bmInfoHeader, sizeof(BITMAPINFOHEADER), 1, m_rfp);
}

/*读取颜色表*/
inline
void bitmap::readRgbQuad(RGBQUAD* rgbQuad, const int& rgbQuadSize) {
	fread(rgbQuad, rgbQuadSize, 1, m_rfp);
}

/*读取位图数据*/
inline
void bitmap::readImgData(BYTE* pImgData, const DWORD& imgSize) {
	fread(pImgData, imgSize, 1, m_rfp);
}
#pragma endregion


#pragma region bmp文件四部分的写入
/*写入文件头*/
inline
void bitmap::writeFileHeader(BITMAPFILEHEADER* bmFileHeader) {
	fwrite(bmFileHeader, sizeof(BITMAPFILEHEADER), 1, m_wfp);
}

/*写入信息头*/
inline
void bitmap::writeInfoHeader(BITMAPINFOHEADER* bmInfoHeader) {
	fwrite(bmInfoHeader, sizeof(BITMAPINFOHEADER), 1, m_wfp);
}

/*写入颜色表*/
inline
void bitmap::writeRgbQuad(RGBQUAD* rgbQuad, const int& rgbQuadSize) {
	fwrite(rgbQuad, rgbQuadSize, 1, m_wfp);
}

/*写入位图数据*/
inline
void bitmap::writeImgData(BYTE* pImgData, const DWORD& imgSize) {
	fwrite(pImgData, imgSize, 1, m_wfp);
}
#pragma endregion


#pragma region 构造和析构函数

bitmap::bitmap(const char* readFilePath, const char* writeFilePath) {
	m_rfp = fopen(readFilePath, "rb");//只读二进制文件
	m_wfp = fopen(writeFilePath, "wb");//只写二进制文件

	m_pbfHeader = new BITMAPFILEHEADER;//为文件头分配存储空间
	readFileHeader(m_pbfHeader);//将图片的文件头读入

	if (m_pbfHeader->bfType == 0x4d42/*检查是否为bm图片*/) {
		m_pbiHeader = new BITMAPINFOHEADER;//为信息头分配内存空间
		readInfoHeader(m_pbiHeader);//将图片的信息头读入

		//24位
		if (m_pbiHeader->biBitCount == 24) {
			m_imgSize = m_pbiHeader->biSizeImage;//获取位图数据大小
			m_pImgData = new BYTE[m_imgSize];//为位图数据分配内存
			readImgData(m_pImgData, m_imgSize);//将图片数据读入

			fclose(m_rfp);//结束读入
		}

		//8位
		if (m_pbiHeader->biBitCount == 8) {
			m_prgbQuad = new RGBQUAD[256];//位颜色表分配内存空间
			readRgbQuad(m_prgbQuad, sizeof(RGBQUAD) * 256);//读取颜色表

			m_imgSize = m_pbiHeader->biSizeImage;//获取位图数据大小
			m_pImgData = new BYTE[m_imgSize];//为位图数据分配内存
			readImgData(m_pImgData, m_imgSize);//将图片数据读入

			fclose(m_rfp);//结束读入
		}

	}
	
}

bitmap::bitmap(const char* readFilePath, const char* writeFilePath0, const char* writeFilePath1, const char* writeFilePath2) {
	m_rfp = fopen(readFilePath, "rb");//只读二进制文件
	m_wfp = fopen(writeFilePath0, "wb");//只写二进制文件
	m_wfp1 = fopen(writeFilePath1, "wb");//只写二进制文件
	m_wfp2 = fopen(writeFilePath2, "wb");//只写二进制文件

	m_pbfHeader = new BITMAPFILEHEADER;//为文件头分配存储空间
	readFileHeader(m_pbfHeader);//将图片的文件头读入

	if (m_pbfHeader->bfType == 0x4d42/*检查是否为bm图片*/) {
		m_pbiHeader = new BITMAPINFOHEADER;//为信息头分配内存空间
		readInfoHeader(m_pbiHeader);//将图片的信息头读入

		//24位
		if (m_pbiHeader->biBitCount == 24) {
			m_imgSize = m_pbiHeader->biSizeImage;//获取位图数据大小
			m_pImgData = new BYTE[m_imgSize];//为位图数据分配内存
			readImgData(m_pImgData, m_imgSize);//将图片数据读入

			fclose(m_rfp);//结束读入
		}
	}
}

//析构函数
bitmap::~bitmap() {
	fclose(m_wfp);//结束写入
	if(m_pbfHeader != nullptr)
		delete m_pbfHeader;
	if (m_pbiHeader != nullptr)
		delete m_pbiHeader;
	if (m_prgbQuad != nullptr)
		delete m_prgbQuad;
	if (m_pImgData != nullptr)
		delete m_pImgData;
}
#pragma endregion


#pragma region 创建颜色表
//创建灰度8位颜色表
void bitmap::createGrey_8() {
	BYTE rgb = 0;
	BYTE rgbReserved = 0;

	m_prgbQuad = new RGBQUAD[256];//256色颜色分配内存
	for (int i = 0; i < 256; ++i) {
		m_prgbQuad[i].rgbBlue = rgb;
		m_prgbQuad[i].rgbGreen = rgb;
		m_prgbQuad[i].rgbRED = rgb;
		m_prgbQuad[i].rgbReserved = rgbReserved;
		++rgb;
	}
}
#pragma endregion


#pragma region 处理图片的方法
//将24位转为8位灰图
void bitmap::rgb24_to_grey8() {
	DWORD imgSize = m_pbiHeader->biHeight * (m_pbiHeader->biWidth / 4 + 1) * 4;//新图片的数据大小
	BYTE* imgData = new BYTE[imgSize]{};//为其分配内存

	//处理文件头
	m_pbfHeader->bfOffBits = 54 + 1024;//多加了一个颜色表256*4
	m_pbfHeader->bfSize = m_pbfHeader->bfOffBits + imgSize;//得出8位灰度时该分辨率的数据大小
	
	//处理信息头
	m_pbiHeader->biBitCount = 8;//每个像素现在8位
	m_pbiHeader->biSizeImage = imgSize;//更新数据大小
	m_pbiHeader->biClrUsed = 256;//将颜色表索引数改为256
	
	//创建颜色表
	createGrey_8();
	
	//将24位数据转换位8位数据
	int tmp;
	for (unsigned int i = 0; i < m_imgSize; i += 3) {
		tmp = (float)m_pImgData[i] * 0.114f + (float)m_pImgData[i + 1] * 0.587f + (float)m_pImgData[i + 2] * 0.299f;
		imgData[i / 3] = BYTE(tmp);
	}

	//写入数据
	writeFileHeader(m_pbfHeader);//写入文件头
	writeInfoHeader(m_pbiHeader);
	writeRgbQuad(m_prgbQuad, 256 * sizeof(RGBQUAD));
	writeImgData(imgData, imgSize);
}

//将8位灰度图反色
void bitmap::grey8_to_antiGrey8() {
	//数据区反色
	for (unsigned int i = 0; i < m_imgSize; ++i) {
		m_pImgData[i] = abs(m_pImgData[i] - 255);
	}

	//写入
	writeFileHeader(m_pbfHeader);
	writeInfoHeader(m_pbiHeader);
	writeRgbQuad(m_prgbQuad, sizeof(RGBQUAD) * 256);
	writeImgData(m_pImgData, m_imgSize);
}

//将24位分离成3个8位图
void bitmap::rgb24_to_3grey8() {
	DWORD imgSize = m_pbiHeader->biHeight * (m_pbiHeader->biWidth / 4 + 1) * 4;//新图片数据大小
	BYTE* imgData0 = new BYTE[imgSize]{};//为其1分配内存
	BYTE* imgData1 = new BYTE[imgSize]{};//为其2分配内存
	BYTE* imgData2 = new BYTE[imgSize]{};//为其3分配内存

	#pragma region 生成第一张图片
	//生成第一张图片
		//处理文件头
	m_pbfHeader->bfOffBits = 54 + 1024;//多加了一个颜色表256*4
	m_pbfHeader->bfSize = m_pbfHeader->bfOffBits + imgSize;//得出8位灰度时该分辨率的数据大小

		//处理信息头
	m_pbiHeader->biBitCount = 8;//每个像素现在8位
	m_pbiHeader->biSizeImage = imgSize;//更新数据大小
	m_pbiHeader->biClrUsed = 256;//将颜色表索引数改为256

		//处理颜色表
	createGrey_8();

	//分离数据
	for (unsigned int i = 0; i < m_imgSize; i += 3) {
		imgData0[i / 3] = m_pImgData[i];
	}

	//写入数据
	writeFileHeader(m_pbfHeader);//写入文件头
	writeInfoHeader(m_pbiHeader);
	writeRgbQuad(m_prgbQuad, 256 * sizeof(RGBQUAD));
	writeImgData(imgData0, imgSize);

	//关闭
	fclose(m_wfp);
	m_wfp = m_wfp1;
	#pragma endregion

	#pragma region 生成第二张图片
	//生成第二张图片
		//分离数据
	for (unsigned int i = 0; i < m_imgSize; i += 3) {
		imgData0[i / 3] = m_pImgData[i + 1];
	}
		//写入数据
	writeFileHeader(m_pbfHeader);
	writeInfoHeader(m_pbiHeader);
	writeRgbQuad(m_prgbQuad, 256 * sizeof(RGBQUAD));
	writeImgData(imgData0, imgSize);

		//关闭
	fclose(m_wfp);
	m_wfp = m_wfp2;
	#pragma endregion

	#pragma region 生成第三张图片
	//生成第三张图片
		//分离数据
	for (unsigned int i = 0; i < m_imgSize; i += 3) {
		imgData0[i / 3] = m_pImgData[i + 2];
	}
	//写入数据
	writeFileHeader(m_pbfHeader);
	writeInfoHeader(m_pbiHeader);
	writeRgbQuad(m_prgbQuad, 256 * sizeof(RGBQUAD));
	writeImgData(imgData0, imgSize);
	#pragma endregion

}
#pragma endregion

?效果展示

?

?

?

?

?

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-08 22:10:02  更:2022-03-08 22:13:04 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 5:41:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码