⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 compressdlg.cpp

📁 实现对任意文件的霍夫曼编码压缩
💻 CPP
字号:
// compressDlg.cpp : implementation file
//

#include "Stdafx.h"
#include "Compress.h"
#include "CompressDlg.h"
#include "stdio.h"



#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CCompressDlg dialog

CCompressDlg::CCompressDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CCompressDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CCompressDlg)
	m_InputFileName = _T("");
	m_OutFileName = _T("");
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CCompressDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CCompressDlg)
	DDX_Text(pDX, IDC_EDIT_FileIn, m_InputFileName);
	DDX_Text(pDX, IDC_EDIT_FileOut, m_OutFileName);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CCompressDlg, CDialog)
	//{{AFX_MSG_MAP(CCompressDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON1, OnBUTTONBrowse)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CCompressDlg message handlers

BOOL CCompressDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here
	
	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CCompressDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CCompressDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CCompressDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

void CCompressDlg::OnBUTTONBrowse() 
{
    CFileDialog fDlg(TRUE,NULL,"c:\\*.*");

	UpdateData(TRUE);
	if(fDlg.DoModal() == IDOK){
		m_InputFileName = fDlg.GetPathName();
		fname = fDlg.GetFileName();
		ftitle = fDlg.GetFileTitle();
		fext = fDlg.GetFileExt();
		m_OutFileName=m_InputFileName;
	    int l1=m_InputFileName.GetLength();
		int l2=fname.GetLength();
		int l3=l1-l2;
		m_OutFileName.Delete(l3,l2);
	}
	UpdateData(FALSE);			
}

void CCompressDlg::OnOK() 
{
	if(fext=="hfm")
	{
		MessageBox("文件已经被压缩过了   ","不重复劳动",MB_ICONWARNING);
		return;
	}
	if(m_InputFileName.IsEmpty() == 1)
	{
		MessageBox("请选择文件    ","提示",MB_ICONWARNING);
		return;
	}
	if((fp = fopen(m_InputFileName,"rb")) == NULL)
	{
		MessageBox("没有打开文件","错误",MB_ICONERROR);
		return;
	}
	WeightCount();
	HuffmanCoding();
	if((fclose(fp)!=0))
	{
		MessageBox("出错","错误",MB_ICONERROR);
		return;
	}

    UpdateData(true);
		m_OutFileName=m_OutFileName+ftitle+".hfm";
	UpdateData(false);
	fp = fopen(m_InputFileName,"rb");
	if((fout = fopen(m_OutFileName,"wb")) == NULL)
	{
		MessageBox("不能保存","错误",MB_ICONERROR);
		return;
	}
    FileCompress();
    fclose(fp);
	fclose(fout);

    char infor[20];
	sprintf(infor,"压缩率:  %f",f_head.hfSize/(all_count/2.0));

	MessageBox("\n输出文件:  "+m_OutFileName+"   \n\n\n"+infor,"信息");

}


/* ///////WeightCount()获得每个字符对应的个数///////*/
void CCompressDlg::WeightCount()
{
	int i;
	unsigned char buffer[2];
	for(i=0;i<16;i++)
		count[i]=0;
	all_count=0;
    while(!feof(fp))
	{
		buffer[0]=fgetc(fp);
		buffer[1]=buffer[0]&0x0F;
		buffer[0]>>=4;
        for(i=0;i<2;i++)
		{
			count[buffer[i]]++;//buffer[i]恰好是count[i]的下标
			all_count++;
		}
	}
}



void CCompressDlg::HuffmanCoding()
{
	int i,j=1,LeafNum=0;/*叶结点的个数*/
	int total;//总节点数
	int s1,s2;
	for (i=0;i<16;i++)
	{   
		if(count[i]>0) 
	       LeafNum++;
	}
    f_head.SourceSignalNum = (unsigned char)(LeafNum);
	total=2*LeafNum-1;
    HT=(HTNode*)calloc((total+1),sizeof(HTNode));
/////////////////////节点初始化////////////////////////
	for(i=1;i<=16;i++)
	{
		if(count[i-1]>0)
		{
		   HT[j].Weight=count[i-1];
		   HT[j].Parent=0;
		   HT[j].lChild=0;
		   HT[j].rChild=0;
		   HT[j].source=(unsigned char)(i-1);
		   j++;
		}
	}

	for(i=LeafNum+1;i<=total;i++)
    {
        HT[i].Weight=0;
        HT[i].Parent=0;
        HT[i].lChild=0;
        HT[i].rChild=0; 
    }
/*///////////////////Create HuffmanTree////////////////*/
    for(i=LeafNum+1;i<=total;++i)
    {
        SelectSmall(i-1,&s1,&s2);
        HT[s1].Parent=i;
        HT[s2].Parent=i;
		HT[s1].code='0';
		HT[s2].code='1';
        HT[i].lChild=s1;
        HT[i].rChild=s2;
        HT[i].Weight=HT[s1].Weight+HT[s2].Weight;
    }
/*///////////////填充临时码表///////////////////*/
	for(i=0;i<16;i++)
	{	
		temp_table[i].length=0;
		temp_table[i].HCode=0;
	}

	for(i=1;i<=LeafNum;i++)
	{
		int f=i;
		j=(int)HT[f].source;
		while(f!=total)
		{//get temp_table[i].HCode
			switch(HT[f].code)
			{
			case '0':
				 {
					 temp_table[j].HCode<<=1;
					 temp_table[j].length++;
					 break;
				 }
			case '1':
				 {
					 temp_table[j].HCode<<=1;
					 temp_table[j].HCode|=0x01;
					 temp_table[j].length++;
					 break;
				 }
			}//end of switch
			f=HT[f].Parent;
		}
        temp_table[j].HCode<<=(16-temp_table[j].length);
	}
/*///////////////////////填充文件码表////////////////////////*/
	j=0;
	for(i=0;i<16;i++)
	{
		if(temp_table[i].length!=0)
		{
			f_table[j].SourceSignal_CodeLength = (unsigned char)(i);
			f_table[j].SourceSignal_CodeLength <<= 4;
			f_table[j].SourceSignal_CodeLength |= temp_table[i].length;
			f_table[j].CodeBits=temp_table[i].HCode;
			j++;
		}
	}
}




void CCompressDlg::SelectSmall(int cnt, int *s1, int *s2)
/*////////(*s1) is smallest,(*s2) is smaller.///////*/
{
     int i;
     unsigned int temp1=0;
     unsigned int temp2=0;
     unsigned int temp3;
     for(i=1;i<=cnt;i++)
     {
         if(HT[i].Parent==0)
         {
             if(temp1==0)
             {
                 temp1=HT[i].Weight;
                 (*s1)=i;
             }
             else
             {
                 if(temp2==0)
                 {
                     temp2=HT[i].Weight;
                     (*s2)=i;
                     if(temp2<temp1)
                     {
                         temp3=temp2;
                         temp2=temp1;
                         temp1=temp3;
 
                         temp3=(*s2);
                         (*s2)=(*s1);
                         (*s1)=temp3;
                     }
                 }
                 else
                 {
                     if(HT[i].Weight<temp1)
                    {
                         temp2=temp1;
                         temp1=HT[i].Weight;
 
                         (*s2)=(*s1);
                         (*s1)=i;
                     }
                     if(HT[i].Weight>temp1&&HT[i].Weight<temp2)
                     {
                         temp2=HT[i].Weight;
                         (*s2)=i;
                     }
                 }
             }
         }
     }
}

void CCompressDlg::FileCompress()
{
	int i,j;
	BYTE ch=0,buffer[2];
	unsigned char vanl[3],tch,R_van=0;
	WORD *p1;
	int remain=0,byte_num=0;
	fseek(fout,12L,0);//预留表头空间
	for(i=0;i<f_head.SourceSignalNum;i++)//fwrite()函数有Bug不能整体输出一个结构体
	{
		fwrite(&f_table[i].SourceSignal_CodeLength,1,1,fout);//写入码表
		fwrite(&f_table[i].CodeBits,2,1,fout);
	}
	f_head.hfSize=12;
	while(!feof(fp))
	{
		//读原始文件
		//编码写文件
		p1=(WORD*)(&vanl[0]);
		buffer[0]=fgetc(fp);
		buffer[1]=buffer[0]&0x0F;//buffer[1] lower 4 bits
		buffer[0]>>=4;//buffer[0] higher 4 bits
		for(i=0;i<2;i++)
		{
			ch=buffer[i];
			*p1 = temp_table[ch].HCode;
			byte_num=((int)temp_table[ch].length+remain)/8;
			tch=vanl[1];
			*p1=*p1<<(8-remain);
            tch=tch>>remain;
            vanl[2]=tch|R_van;
			for(j=0;j<byte_num;j++)
			{
			    fwrite(&vanl[2-j],1,1,fout);
				f_head.hfSize++;
			}
			R_van=vanl[2-j];
			remain=(temp_table[ch].length+remain) % 8;

		}
	}
	if(remain!=0)
		fwrite(&R_van,1,1,fout);
	f_head.hfType=0x4648;
	f_head.hfSize++;
	f_head.hfOffBits=f_head.SourceSignalNum*3+12;
	f_head.ValidDataBitsNum=remain;
	f_head.FileNameLength=fname.GetLength();
	rewind(fout);                             //输出表头
	fwrite(&f_head.hfType,2,1,fout);
	fwrite(&f_head.hfSize,4,1,fout);
	fwrite(&f_head.FileNameLength,2,1,fout);
	fwrite(&f_head.SourceSignalNum,1,1,fout);
	fwrite(&f_head.hfOffBits,2,1,fout);
	fwrite(&f_head.ValidDataBitsNum,1,1,fout);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -