关闭

程设作业:文件操作作业 解题报告&弱弱的代码

标签: 作业byteclassios文档cmd
556人阅读 评论(0) 收藏 举报

解题报告:

做这道题要仔细阅读老师提供的文档,熟悉了24位位图的数据规模后再读入。

数据读入:对于图像数据分行读入,设置一个后移块,用于跳过每一行的补0位。

数据交换:a(width - i - 1,j) = b(j,i)

这里为了迎合题意,在main函数里加入两个参数int argc和char * argv[],这样可以直接从命令提示符cmd.exe中用如下图方式使用转换程序:

另外,代码里用到的template模板的思想来自thoar大牛的代码

大家可以去他的博客看到更多的代码:

http://blog.csdn.net/xranthoar

注意:老师提供的文档前面那篇文章可能有点问题,在图像描述信息块的最后一部分数据应该是002E-0035!

接下来贴代码:

因为手头没有32位位图,我不知道能不能旋转32位位图…

#include <iostream>
#include <fstream>
#pragma pack(1)

using namespace std;

const int CON_SIZE = 31;  //公式中的大小。DataSizePerLine= (biWidth* biBitCount+31)/8;为一个扫描行所占的字节数
const int BYTE_SIZE = 8;  //一个字节=8位。

typedef char BYTE;  //1字节
typedef short DBYTE;  //2字节
typedef int WORD;  //4字节
typedef long LONG;  //4字节

class FileHead  //文件头信息块
{
public:
	DBYTE bfType;  //文件标识,为字母ASCII码“BM”
	WORD bfSize;  //文件大小
	WORD bfReserved;  //保留,每字节以“00”填写
	WORD bfOffBits;  //记录图像数据区的起始位置。各字节的信息依次含义为:文件头信息块大小,图像描述信息块的大小,图像颜色表的大小,保留(为01)
};

class InfoHead  //图像描述信息块
{
public:
	WORD biSize;  //图像描述信息块的大小,常为28H
	LONG biWidth;  //图像宽度
	LONG biHight;  //图像高度
	DBYTE biPlane;  //图像的plane总数(恒为1)
	DBYTE biBitCount;  //记录像素的位数,很重要的数值,图像的颜色数由该值决定
	WORD biCompression;  //数据压缩方式(数值位0:不压缩;1:8位压缩;2:4位压缩)
	WORD biSizeImage;  //图像区数据的大小
	LONG biXPelsPerMeter;  //水平每米有多少像素,在设备无关位图(.DIB)中,每字节以00H填写
	LONG biYPelsPerMeter;  //垂直每米有多少像素,在设备无关位图(.DIB)中,每字节以00H填写
	WORD biClrUsed;  //此图像所用的颜色数
	WORD biCleImportance;  //颜色重要性,若为0,则表示颜色一样重要
	//这里要注意!老师提供的文档前面那篇文章这里有错误,他说“002E-0031:此图像所用的颜色数,如值为0,表示所有颜色一样重要。”
	//但实际上:这里应该是两个长为4字节的数据!(即biClrUsed和biCleImportance)
};

class RGBQuad_24 //24位位图图像数据
{
public:
	RGBQuad_24() : rgbBlue(0), rgbGreen(0), rgbRed(0) { };  //补0用
	BYTE rgbBlue;  //蓝
	BYTE rgbGreen;  //绿
	BYTE rgbRed;  //红
};

class RGBQuad_32 //32位位图图像数据
{
public:
	RGBQuad_32() : rgbBlue(0), rgbGreen(0), rgbRed(0), rgbAlpha(0) { };  //补0用
	BYTE rgbBlue;  //蓝
	BYTE rgbGreen;  //绿
	BYTE rgbRed;  //红
	BYTE rgbAlpha; //透明度
};

FileHead Head;
InfoHead Info;

template <typename RGBQuad>
bool Deal(ifstream &fin, ofstream &fout)
{
	RGBQuad *Quad;
	int LineSize = (Info.biWidth * Info.biBitCount + CON_SIZE) / BYTE_SIZE;
	LineSize -= LineSize % 4;  //计算每一行的真实长度,在下面输入的时候用于过滤补0的数据
	int DifPtr = LineSize - Info.biWidth * sizeof(RGBQuad);  //用于跳过补0数据
	int Scale = Info.biHight * Info.biWidth;  //真实有用的数据规模
	Quad = new RGBQuad [Scale];  //生成图片数据包
	for(int i = 0; i != Info.biHight; ++i)
	{
		fin.read((char*) (Quad + i * Info.biWidth), Info.biWidth * sizeof(RGBQuad));  //读入有效数据
		fin.seekg(DifPtr, ios::cur);  //跳过补0位
	}
	FileHead DestHead = Head;
	InfoHead DestInfo = Info;
	DestInfo.biHight = Info.biWidth;
	DestInfo.biWidth = Info.biHight;
	int DestLineSize = (DestInfo.biWidth * DestInfo.biBitCount + CON_SIZE) / BYTE_SIZE;
	DestLineSize -= DestLineSize % 4;
	DifPtr = DestLineSize - DestInfo.biWidth * sizeof(RGBQuad); 
	Scale = DestInfo.biWidth * DestInfo.biHight;
	DestHead.bfSize = DestInfo.biHight * DestLineSize + sizeof(FileHead) + sizeof(InfoHead);
	DestInfo.biSizeImage = DestHead.bfSize - sizeof(FileHead) + sizeof(InfoHead);
	RGBQuad *DestQuad = new RGBQuad [Scale];
	for(int i = 0; i != DestInfo.biHight; ++i)
	{
		for(int j = 0; j != DestInfo.biWidth; ++j)
		{
			DestQuad[(DestInfo.biHight - i - 1) * DestInfo.biWidth + j] = 
				Quad[j * Info.biWidth + i];
		}
	}  //交换数据
	fout.write((char *) &DestHead, sizeof(FileHead));
	fout.write((char *) &DestInfo, sizeof(InfoHead));
	char *Temp = new char[DifPtr + 1];
	memset(Temp, 0, DifPtr + 1);
	for(int i = 0; i != DestInfo.biHight; ++i)
	{
		fout.write((char*) (DestQuad + DestInfo.biWidth * i), DestInfo.biWidth * sizeof(RGBQuad));
		fout.write((char*) Temp, DifPtr);
	}
	cout << "处理完成!" << endl;
	cout << "处理前文件大小 = " << Head.bfSize << endl;
	cout << "处理后文件大小 = " << DestHead.bfSize << endl;
	return true;
}

int main(int argc, char * argv[])  //传入控制台参数,在cmd里可以直接用rotatebmp src.bmp dest.bmp
{
	if(argc == 1)
	{
		argv[1] = "src.bmp";
		argv[2] = "dest.bmp";  //默认的图片文件名,缺省用
	}
	ifstream fin(argv[1], ios::in | ios::binary);
	ofstream fout(argv[2], ios::out | ios::binary);
	if(!fin)
	{
		cout << "找不到 " << argv[1] << " !" << endl;
		return -1;
	}
	if(!fout)
	{
		cout << "无法打开 " << argv[2] << " !" << endl;
		return -1;
	}
	fin.read((char *) &Head, sizeof(FileHead));
	fin.read((char *) &Info, sizeof(InfoHead));  //2进制读入两个文件信息头
	if(Info.biBitCount == 24)
	{
		Deal<RGBQuad_24>(fin, fout);
	}
	if(Info.biBitCount == 32)
	{
		Deal<RGBQuad_32>(fin, fout);
	}
	return 0;
}




这里提供几张24位bmp给诸位试试。





0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:49653次
    • 积分:853
    • 等级:
    • 排名:千里之外
    • 原创:33篇
    • 转载:0篇
    • 译文:1篇
    • 评论:15条
    博客专栏
    最新评论