C++ 图像压缩算法 bmp 哈夫曼树

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35558510/article/details/79346071

Compressor.h

#pragma once
#include"HuffmanTree.h"
#include"HCode.h"
#include<fstream>
#include<iostream>
class Compressor
{
public:
	Compressor();
	~Compressor();
	void compress(string TargetPath, string sourcePath);//压缩
	void decompress(string TargetPath, string sourcePath);//解压

private:
	int colorTypeCount;
	int imageWidth;
	int imageHeight;
	string filePath;
	HuffmanTree *tree;

};

HCode.h

#pragma once
#include<string>
#include<iostream>
using namespace std;
class Color
{
	int color;
	int count;
};


class HCode
{
public:
	HCode();
	~HCode();
	void addColor(unsigned char color);
	int getCodeLen();
	bool getBItAt(int inidx);
	void addBit(bool in, unsigned char color);
	void tranverse();
	HCode& operator<<(int in);
	int getCharPtr();

	int *codeLength;
	string * codeContent;
	unsigned int code[1000][30];//实际要写入内容
	int codeBYTE[256];
	int *colorWeight;

};

HuffmanTree.h

#pragma once
#include"HCode.h"
#include<iostream>
using namespace std;
class HuffmanTreeNode
{
public:
	HuffmanTreeNode();
	char data;//颜色
	int weight;//权重
	HuffmanTreeNode * leftChild;
	HuffmanTreeNode * rightChild;
};

class HuffmanTree
{
public:
	int size;
	void HuffmanTreeCreate();
	HuffmanTree();
	HCode hcode;
	~HuffmanTree();
	void getCodeRecusion(HuffmanTreeNode * root, string code);
	void getCodeMa();
	HuffmanTreeNode *root;
	void deleteTree(HuffmanTreeNode *root);
};

class MinHeap
{
public:
	HuffmanTreeNode ** heapArray;
	int currentSize;
	int maxSize;
	MinHeap(int max);
	bool insert(HuffmanTreeNode * data);
	HuffmanTreeNode * removeMin();
	void shiftDown(int left);
	void shiftUp(int child);
};

Compressor.cpp

#include "Compressor.h"
typedef struct tagBITMAPFILEHEADER//BMP文件头(14字节)
{
	unsigned short bfType; // 位图文件的类型,必须为BM(0-1字节)
	unsigned int bfSize; // 位图文件的大小,以字节为单位(2-5字节)
	unsigned short bfReserved1; // 位图文件保留字,必须为0(6-7字节)
	unsigned short bfReserved2; // 位图文件保留字,必须为0(8-9字节)
	unsigned int bfOffBits; // 位图数据的起始位置,以相对于位图(10-13字节)
					 // 文件头的偏移量表示,以字节为单位
} BITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER  //位图信息头(40字节)
{
	unsigned int biSize; // 本结构所占用字节数(14-17字节)
	unsigned int biWidth; // 位图的宽度,以像素为单位(18-21字节)
	unsigned int biHeight; // 位图的高度,以像素为单位(22-25字节)
	unsigned short biPlanes; // 目标设备的级别,必须为1(26-27字节)
	unsigned short biBitCount;// 每个像素所需的位数,必须是1(双色),(28-29字节)
					// 4(16色),8(256色)或24(真彩色)之一
	unsigned int biCompression; // 位图压缩类型,必须是 0(不压缩),(30-33字节)
						 // 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一
	unsigned int biSizeImage; // 位图的大小,以字节为单位(34-37字节)
	unsigned int biXPelsPerMeter; // 位图水平分辨率,每米像素数(38-41字节)
	unsigned int biYPelsPerMeter; // 位图垂直分辨率,每米像素数(42-45字节)
	unsigned int biClrUsed;// 位图实际使用的颜色表中的颜色数(46-49字节)
	unsigned int biClrImportant;// 位图显示过程中重要的颜色数(50-53字节)
} BITMAPINFOHEADER;

typedef struct tagRGBQUAD
{
	unsigned char Blue;// 蓝色的亮度(值范围为0-255)
	unsigned char Green; // 绿色的亮度(值范围为0-255)
	unsigned char Red; // 红色的亮度(值范围为0-255)
	unsigned char Alpha;//透明度
} RGBA;

Compressor::Compressor()
{
	tree = new HuffmanTree;
}


Compressor::~Compressor()
{
}


void Compressor::compress(string TargetPath,string sourcePath)
{
	ofstream outfile(TargetPath, ios_base::binary);
	ifstream infile(sourcePath, ios_base::binary);
	if (!infile.is_open())
	{
		cout << "未成功打开文件" << endl;
		return;
	}
	if (!outfile.is_open())
	{
		cout << "未成功打开文件" << endl;
		return;
	}

	BITMAPFILEHEADER bmphead;
	tagBITMAPINFOHEADER bmptag;
	infile.read((char *)&bmphead, 14);
	infile.read((char *)&bmptag, 40);
	cout << bmptag.biHeight << " " << bmptag.biWidth << bmptag.biBitCount << endl;
	int max = 4 * bmptag.biWidth*bmptag.biHeight;
	unsigned char * bmpdot = new unsigned char[max];
	cout << max;
	for (int i = 0; i < max; i++)
	{
		infile.read((char *)(bmpdot + i), 1);
		tree->hcode.addColor(bmpdot[i]);
	}

	tree->HuffmanTreeCreate();//建树

	for (int i = 0; i < 256; i++)
	{
		if (tree->hcode.codeLength[i] != 0)
			cout << "第" << i << "色 编码" << tree->hcode.codeContent[i] << "长度" << tree->hcode.codeLength[i] << endl;
	}
	tree->getCodeMa();

	outfile.write((char *)&bmphead, 14);
	outfile.write((char *)&bmptag, 40);
	for (int i = 0; i < 256; i++) //写入颜色编码表
	{
		if (tree->hcode.codeLength[i] != 0)
		{
			outfile.write((char *)&i, 1);
			outfile.write((char *)&(tree->hcode.codeLength[i]), 1);
			for (int p = 0; p<tree->hcode.codeBYTE[i]; p++)
				outfile.write((char *)&(tree->hcode.code[i][p]), 1);
		}
	}
	int i = 0;
	outfile.write((char *)&i, 4);
	unsigned int Buffer = 0;
	int Bufferlen = 0;
	for (int i = 0; i < max; i++) //写颜色
	{
		unsigned char thiscolor = bmpdot[i];
		int thisColorLen = tree->hcode.codeLength[thiscolor];
		for (int k = 0; k < tree->hcode.codeBYTE[thiscolor]; k++)
		{
			int mmm = tree->hcode.codeBYTE[thiscolor];
			if (thisColorLen >= 8)
			{
				Buffer = (Buffer << 8) | tree->hcode.code[thiscolor][k];
				Bufferlen += 8;
				thisColorLen -= 8;
			}
			else
			{
				Buffer = (Buffer << thisColorLen) | (tree->hcode.code[thiscolor][k] >> (8 - thisColorLen));
				Bufferlen += thisColorLen;
				thisColorLen = 0;
			}
			if (Bufferlen >= 8)
			{
				int temp = Buffer >> (Bufferlen - 8);
				outfile.write((char *)&temp, 1);
				Bufferlen -= 8;
			}
		}
	}
	infile.close();
	outfile.close();
}

void Compressor::decompress(string TargetPath, string sourcePath)
{
	ofstream outfile(TargetPath, ios_base::binary);
	ifstream infile(sourcePath, ios_base::binary);
	if (!infile.is_open())
	{
		cout << "未成功打开文件" << endl;
		return;
	}
	if (!outfile.is_open())
	{
		cout << "未成功打开文件" << endl;
		return;
	}

	BITMAPFILEHEADER bmphead;
	tagBITMAPINFOHEADER bmptag;
	infile.read((char *)&bmphead, 14);
	infile.read((char *)&bmptag, 40);
	outfile.write((char *)&bmphead, 14);
	outfile.write((char *)&bmptag, 40);
	cout << bmptag.biHeight << " " << bmptag.biWidth << bmptag.biBitCount << endl;
	int max = 4 * bmptag.biWidth*bmptag.biHeight;
	unsigned char * bmpdot = new unsigned char[max];


	tree->root = new HuffmanTreeNode;
	while (1) //读取编码表,还原哈夫曼树
	{
		HuffmanTreeNode *p=tree->root;
		unsigned char color;
		int length=0;
		infile.read((char *)&color, 1);
		printf("第%d色", color);
		infile.read((char *)&length, 1);
		cout << "  长度 " << length<<"编码";
		if (length == 0)
		{
			infile.read((char *)&length, 2);
			break;
		}
		int BYTENUM = length /8 + (length % 8 == 0 ? 0 : 1);
		int count = 0;
		int Buffer;
		for (int i = 0; i < BYTENUM; i++)
		{
			infile.read((char*)&Buffer, 1);
			for (int m = 1; m <= 8; m++)
			{
				int lead = Buffer >> (8 - m)&0x00000001;
				count++;
				if (lead == 0)
				{
					cout << "0";
					if (p->leftChild == 0)
					{
						p->leftChild = new HuffmanTreeNode;
					}
					p = p->leftChild;
				}
				else
				{
					cout << "1";
					if (p->rightChild == 0)
					{
						p->rightChild = new HuffmanTreeNode;
					}
					p = p->rightChild;
				}
				if (count == length)
				{
					count = 0;
					p->data = color;
					goto XX;
				}

			}
		}

	XX:  cout << endl;
	}
	unsigned int Buffer;
	int bufferLen = 8;
	infile.read((char *)&Buffer, 1);
	HuffmanTreeNode *q=tree->root;
	for (int i = 0; i < max; i++)
	{
		q = tree->root;
		while (1)
		{
			int lead=Buffer >> (bufferLen-1) & 0x00000001;
			bufferLen --;
			if (bufferLen == 0)
			{
				infile.read((char *)&Buffer, 1);
				bufferLen += 8;
			}
			if (lead == 1)
			{
				q = q->rightChild;
			}
			else
			{
				q = q->leftChild;
			}
			if (q->leftChild == NULL||q->rightChild == NULL)
			{
				outfile.write((char *)&(q->data), 1);
				break;
			}
		}
	}
}

HCode.cpp

#include "HCode.h"
#include<iostream>
using namespace std;
HCode::HCode()
{
	codeLength = new int[256];
	codeContent = new string[256];
	colorWeight = new int[256];
	for (int i = 0; i < 256; i++)
	{
		codeLength[i]=0;
		colorWeight[i]=0;
	}
}


HCode::~HCode()
{
}

void HCode::addColor(unsigned char color)
{

	colorWeight[color]++;
}

void HCode::addBit(bool in, unsigned char color)
{
	if (in == 0)
	{
		codeContent[color] += '0';
	}
	else
	{
		codeContent[color] += '1';
	}
	codeLength[color]++;
	//cout << "第" << (int)color << "颜色长度加1,位"<<(int)in <<"  "<< (int)codeLength[color] << endl;
	//printf("%d\n", colorWeight[color]);
}


HuffmanTree.cpp

#include "HuffmanTree.h"

HuffmanTree::~HuffmanTree()
{
}

void HuffmanTree::HuffmanTreeCreate()
{
	MinHeap heap(256);
	HuffmanTreeNode *parent, *firstChild, *secondChild;
	HuffmanTreeNode *newNode;

	for (int i = 0; i < 256; ++i)
	{
		if (hcode.colorWeight[i] != 0)
		{
			size++;
			newNode = new HuffmanTreeNode;
			newNode->weight = hcode.colorWeight[i];
			newNode->data = i; 
			heap.insert(newNode);
		}
	}
	cout << "size==" << size << "maxln=" << heap.currentSize << endl;
	for (int i = 0; i < size-1 ; ++i)
	{
		parent = new HuffmanTreeNode;
		firstChild = heap.removeMin();
		secondChild = heap.removeMin();
		parent->weight = firstChild->weight + secondChild->weight;
		parent->leftChild = firstChild;
		parent->rightChild = secondChild;
		
		heap.insert(parent);
		root = parent;
	}
	root = heap.heapArray[0];
	string ll;
	getCodeRecusion(root, ll);
}

HuffmanTree::HuffmanTree()
{
	size = 0;
}


void HuffmanTree::getCodeRecusion(HuffmanTreeNode * root, string code)
{
	if (root->leftChild == NULL&&root->rightChild == NULL)
	{		for (int i = 0; i < code.length(); i++)
		{
			if (code[i] == '0')
				hcode.addBit(0, root->data);
			else
				hcode.addBit(1, root->data);
		}
	}
	else
	{
		 getCodeRecusion(root->leftChild, code + '0');
		 getCodeRecusion(root->rightChild, code + '1');
	}
}

void HuffmanTree::getCodeMa()
{
	for (int i = 0; i < 256; i++)//计算编码表
	{
		if (hcode.codeLength[i] != 0)
		{
			int lenth = hcode.codeLength[i];
			unsigned int temp = 0;//缓冲区
			int count = 0;
			int zijiecount = 0;
			for (int j = 0; j <hcode.codeContent[i].length(); j++)
			{
				if (count == 8) 
				{
					hcode.code[i][zijiecount] = temp;
					temp = 0;
					count = 0;
					zijiecount++;
				}
				if (hcode.codeContent[i][j] == '1')
				{
					//cout << "1";
					temp = (temp << 1) | 0x00000001;
				}
				else
				{
					//cout << "0";
					temp = (temp << 1) & 0xFFFFFFFE;
				}
				count++;
			}
			if (count != 0)
			{
				hcode.code[i][zijiecount] = temp << (8 - count);//************
				zijiecount++;
			}
			hcode.codeBYTE[i] = zijiecount;
		}
	}
}






MinHeap::MinHeap(int max)
{
	heapArray = new HuffmanTreeNode *[max];
	maxSize = max;
	currentSize = 0;
}

bool MinHeap::insert(HuffmanTreeNode * data)
{
	if (currentSize == 0)
	{
		heapArray[0] = data;
		currentSize++;
		return 1;
	}
	heapArray[currentSize] = data;
	shiftUp(currentSize );
	currentSize++;
	return true;
}

void MinHeap::shiftUp(int child)
{
	while (child > 0)
	{
		int parent = (child - 1) / 2;
		if (heapArray[child]->weight <= heapArray[parent]->weight)
		{
			HuffmanTreeNode *temp = heapArray[parent];
			heapArray[parent] = heapArray[child];
			heapArray[child] = temp;
			child = parent;
		}
		else break;
	}
}

HuffmanTreeNode * MinHeap::removeMin()
{
	if (currentSize == 1)
	{
		currentSize--;
		return heapArray[0];;
	}
	HuffmanTreeNode * temp = heapArray[0];
	heapArray[0] = heapArray[currentSize - 1];
	currentSize--;
	shiftDown(0);
	return temp;
}

void MinHeap::shiftDown(int left)
{
	int i = left;
	int j = 2 * i + 1;
	HuffmanTreeNode *temp = heapArray[i];
	while (j < currentSize)
	{
		if ((j < currentSize - 1) && heapArray[j]->weight > heapArray[j + 1]->weight)
			j++;
		if (temp->weight > heapArray[j]->weight)
		{
			heapArray[i] = heapArray[j];
			i = j;
			j = 2 * j + 1;
		}
		else break;
	}
	heapArray[i] = temp;
}

HuffmanTreeNode::HuffmanTreeNode()
{
	leftChild = rightChild = NULL;
	weight = 0;
}


 
  
 
 
 


猜你喜欢

转载自blog.csdn.net/qq_35558510/article/details/79346071