开发一个控制台程序,使用Huffnan压缩算法对bmp格式图片文件进行压缩
项目结构
运行结果
Huffman.h
#pragma once
#include
using namespace std;
struct HTNode
{
int weight=0;
int parent=0;
int lchild=0;
int rchild=0;
};
typedef HTNode *Huffmantree;
typedef char** HuffmanCode;
int HuffmanTree(Huffmantree &pHT, int* w, int n);
int Select(Huffmantree pHT, int nSize);
void TestHuffmanTree(Huffmantree pHT);
int HuffmanCoding(HuffmanCode& pHC, Huffmantree& pHT);
void TestHuffmanCode(int root, Huffmantree pHT, HuffmanCode pHC);
Compress.h
#pragma once
#include"Huffman.h"
#define SIZE 256
struct HEAD {
char type[8];
int length;
int weight[256];
};
typedef char* BUFFER;
int InitHead(const char* pFilename, HEAD& sHead);
int Compress(const char* pFilename);
int Str2byte(const char* pBinStr);
int Encode(const char* pFilename, const HuffmanCode pHC, char* pBuffer, const int nSize);
int WriteFile(const char* pFilename, const HEAD sHead, const BUFFER pBuffer,const int nSize);
Huffman.cpp
#include"Huffman.h"
int HuffmanTree(Huffmantree &pHT,int* w, int n) {
for (int i = 0; i < n * 2; i++)
pHT[i] = { 0,0,0,0 };
for (int i = 0; i < n; i++) {
pHT[i + 1].weight = w[i];
}
for (int i = n; i < n * 2; i++) {
pHT[i + 1].lchild = Select(pHT, i);
pHT[i + 1].weight += pHT[Select(pHT, i)].weight;
pHT[Select(pHT, i)].parent = i + 1;
pHT[i + 1].rchild = Select(pHT, i);
pHT[i + 1].weight += pHT[Select(pHT, i)].weight;
pHT[Select(pHT, i)].parent = i + 1;
}
return 0;
}
int Select(Huffmantree pHT, int nSize) {
int minValue = 0x7FFFFFFF;
int min = 0;
for (int i = 1; i <= nSize; i++) {
if (pHT[i].parent == 0 && pHT[i].weight < minValue) {
minValue = pHT[i].weight;
min = i;
}
}
return min;
}
void TestHuffmanTree(Huffmantree pHT) {
for (int i = 1; i < 512; i++) {
printf("pHT[%d] \t %d \t %d \t %d \t %d \n", i, pHT[i].weight, pHT[i].parent, pHT[i].lchild, pHT[i].rchild);
}
}
int HuffmanCoding(HuffmanCode& pHC, Huffmantree& pHT) {
char cd[256] = { '\0' };
int cdlen = 0;
for (int i = 1; i < 512; i++) {
pHT[i].weight = 0;
}
int p = 511;
while (p != 0) {
if (pHT[p].weight == 0) {
pHT[p].weight = 1;
if (pHT[p].lchild != 0) {
p = pHT[p].lchild;
cd[cdlen++] = '0';
}
else if (pHT[p].rchild == 0)
{
pHC[p] = (char*)malloc((cdlen + 1) * sizeof(char));
cd[cdlen] = '\0';
strcpy(pHC[p], cd);
}
}
else if (pHT[p].weight == 1) {
pHT[p].weight = 2;
if (pHT[p].rchild != 0)
{
p = pHT[p].rchild;
cd[cdlen++] = '1';
}
}
else
{
pHT[p].weight = 0;
p = pHT[p].parent;
--cdlen;
}
}
return 0;
}
void TestHuffmanCode(int root, Huffmantree pHT, HuffmanCode pHC) {
if (pHT[root].lchild == 0 && pHT[root].rchild == 0) {
printf("0x%02X %s\n", root - 1, pHC[root]);
}
if (pHT[root].lchild)
{
TestHuffmanCode(pHT[root].lchild, pHT, pHC);
}
if (pHT[root].rchild)
{
TestHuffmanCode(pHT[root].rchild, pHT, pHC);
}
}
Compress.cpp
#include"Compress.h"
#include"Huffman.h"
int Compress(const char* pFilename) {
int weight[256] = { 0 };
FILE* in = fopen(pFilename, "rb");
int ch;
while ((ch = getc(in)) != EOF) {
weight[ch]++;
}
fclose(in);
HTNode* pHT = (HTNode*)malloc(512 * sizeof(HTNode));
HuffmanCode pHC = (char**)malloc(257 * sizeof(char*));
HuffmanTree(pHT, weight, 256);
HuffmanCoding(pHC, pHT);
int nSize = 0;
for (int i = 0; i < 256; i++) {
nSize += weight[i] * strlen(pHC[i+1]);
}
nSize = (nSize % 8) ? nSize / 8 + 1 : nSize / 8;
char* pBuffer = NULL;
Encode(pFilename, pHC, pBuffer, nSize);
return 0;
}
int Str2byte(const char* pBinStr) {
char b = 0x00;
for (int i = 0; i < 8; i++) {
b = b << 1;
if (pBinStr[i] == '1'){
b=b|0x01;
}
}
return b;
}
int strlen2(char* x) {
int i = 0;
while (x[i] == '0' || x[i] == '1') {
i++;
}
return i;
}
int Encode(const char* pFilename, const HuffmanCode pHC, char* pBuffer, const int nSize) {
FILE* in = fopen(pFilename, "rb");
pBuffer = (char*)malloc(nSize * sizeof(char));
if (!pBuffer) {
cerr << "开辟缓冲区失败" << endl;
return 0;
}
char cd[SIZE] = { 0 };
int pos = 0;
int ch;
while ((ch = fgetc(in)) != EOF)
{
strcat(cd, pHC[ch+1]);
while (strlen2(cd) >= 8) {
pBuffer[pos++] = Str2byte(cd);
for (int i = 0; i < SIZE - 8; i++) {
cd[i] = cd[8 + i];
}
}
}
if (strlen(cd) > 0) {
pBuffer[pos++] = Str2byte(cd);
}
fclose(in);
HEAD sHead;
InitHead(pFilename, sHead);
WriteFile(pFilename, sHead, pBuffer, nSize);
}
int InitHead(const char* pFilename, HEAD& sHead) {
strcpy(sHead.type, "HUF");
sHead.length = 0;
for (int i = 0; i < SIZE; i++) {
sHead.weight[i] = 0;
}
FILE* in = fopen(pFilename, "rb");
int ch;
while ((ch = getc(in)) != EOF) {
sHead.weight[ch]++;
sHead.length++;
}
fclose(in);
in = NULL;
return 0;
}
int WriteFile(const char* pFilename, const HEAD sHead, const BUFFER pBuffer,const int nSize) {
char filename[SIZE] = { 0 };
strcpy(filename, pFilename);
strcat(filename, ".huf");
FILE* out = fopen(filename, "wb");
fwrite(&sHead, sizeof(HEAD), 1, out);
fwrite(pBuffer, sizeof(char),nSize, out);
fclose(out);
out = NULL;
cout << sHead.length<<" 字节"<<endl;
cout << "生成压缩文件: " << filename << endl;
int len = sizeof(HEAD) + strlen(pFilename) + 1 + nSize;
cout << len << " 字节" << endl;
cout << "压缩比率: " << len * 1.0 / (sHead.length * 1.0) * 100 << "%"<<endl;
return len;
}
Main.cpp
#include"Compress.h"
using namespace std;
int main() {
cout << "==========Huffman文件压缩==========" << endl;
char name[100];
cout << "请输入文件名: ";
cin >> name;
Compress(name);
return 0;
}