?? 數據壓縮dlg.cpp
字號:
m_Time.SetWindowText(gmsg);
sprintf(gmsg,"");
m_Ratio.SetWindowText(gmsg);
//設置存儲空間
BYTE *output,*outputmemp;
outputmemp = (BYTE *)GlobalAlloc(GMEM_MOVEABLE,length);
output = (BYTE *)GlobalLock(outputmemp);
//創建Huffman樹,并初始化
TREE Tree;
InitializeTree(&Tree);
outlength = 0;//輸出壓縮比特長度
for(unsigned long i=0;i<length;i++)
{//逐個字符進行壓縮
jc = i;
EncodeSymbol(&Tree,buf[i],output);//對字符進行編碼,新字符加入樹
UpdateWeight(&Tree,buf[i]);//更新碼重,并調整樹
}
CString savename = CurrentFileName + ".lcg";
CurrentFileName = FileName + ".lcg";
FileHeader *fileheader = new FileHeader;
fileheader->namelength = FileName.GetLength()+1;
fileheader->oldlength = length;
fileheader->newlength = outlength;
//寫文件頭信息(被壓縮文件名,壓縮前長度,壓縮后長度(比特))
CFile savefile;
savefile.Open(savename,CFile::modeCreate | CFile::modeReadWrite | CFile::shareDenyNone);
savefile.WriteHuge(fileheader,sizeof(FileHeader));
savefile.Close();
savefile.Open(savename,CFile::modeReadWrite | CFile::shareDenyNone);
savefile.Seek(sizeof(FileHeader),CFile::begin);
savefile.WriteHuge(FileName,fileheader->namelength);
savefile.Close();
//寫文件壓縮數據
savefile.Open(savename,CFile::modeReadWrite | CFile::shareDenyNone);
savefile.Seek(sizeof(FileHeader) + fileheader->namelength,CFile::begin);
savefile.WriteHuge(output,(outlength+7)/8);
savefile.Close();
//釋放內存
delete(fileheader);
GlobalUnlock(filebuf);
GlobalFree(filememp);
GlobalUnlock(output);
GlobalFree(outputmemp);
//壓縮后文件長度
sprintf(gmsg,"%d",outlength/8/1024);
m_FileLength2.SetWindowText(gmsg);
//計算壓縮比
sprintf(gmsg,"%2.2f",(double)(outlength)/(length*8)*100);
m_Ratio.SetWindowText(gmsg);
//設置工作狀態
m_ProgBar.SetPos(100);
workflag = false;
}
void CMyDlg::Decode()
{//解壓
char gmsg[300];
BYTE tmp[300];
workflag = true;
timenum = 0;
SetTimer(1,100,NULL);
outlength = 0;
CurrentFileName = FileList[0];
//讀入文件
CFile openfile;
openfile.Open(CurrentFileName,CFile::modeRead | CFile::shareDenyNone);
length = openfile.GetLength();
BYTE *filebuf,*filememp;
filememp = (BYTE *)GlobalAlloc(GMEM_MOVEABLE,length);
filebuf = (BYTE *)GlobalLock(filememp);
length = openfile.ReadHuge(filebuf,length);
openfile.Close();
FileHeader *fileheader = (FileHeader *)filebuf;
memcpy(tmp,&filebuf[sizeof(FileHeader)],fileheader->namelength);
BYTE *buf = &filebuf[sizeof(FileHeader) + fileheader->namelength];
sprintf(gmsg,"解壓前長度:");
m_L1.SetWindowText(gmsg);
sprintf(gmsg,"解壓后長度:");
m_L2.SetWindowText(gmsg);
sprintf(gmsg,"解壓比:");
m_R1.SetWindowText(gmsg);
sprintf(gmsg,"解壓時間:");
m_T1.SetWindowText(gmsg);
sprintf(gmsg,"%d",length/1024);
m_FileLength.SetWindowText(gmsg);
sprintf(gmsg,"%d",fileheader->oldlength/1024);
m_FileLength2.SetWindowText(gmsg);
sprintf(gmsg,"%02d時%02d分%02d秒",timenum/36000,timenum/600,timenum/10);
m_Time.SetWindowText(gmsg);
sprintf(gmsg,"");
m_Ratio.SetWindowText(gmsg);
BYTE *output,*outputmemp;
outputmemp = (BYTE *)GlobalAlloc(GMEM_MOVEABLE,length*5);
output = (BYTE *)GlobalLock(outputmemp);
TREE Tree;
InitializeTree(&Tree);
outlength = 0;
BYTE ch = 0;
unsigned long j = 0;
for(;outlength<fileheader->newlength;)
{
jc = outlength/8;
output[j++] = ch = DecodeSymbol(&Tree,buf);
UpdateWeight(&Tree,ch);
}
CString str,savename ;
str.Format("%s",tmp);
savename = "LCG_" + str;
CurrentFileName = savename;
CFile savefile;
savefile.Open(savename,CFile::modeCreate | CFile::modeReadWrite | CFile::shareDenyNone);
savefile.WriteHuge(output,j);
savefile.Close();
GlobalUnlock(filebuf);
GlobalFree(filememp);
GlobalUnlock(output);
GlobalFree(outputmemp);
sprintf(gmsg,"%2.2f",(double)(outlength)/(j*8)*100);
m_Ratio.SetWindowText(gmsg);
m_ProgBar.SetPos(100);
workflag = false;
}
void CMyDlg::InitializeTree(TREE *tree)
{
//初始化Huffman樹,設置根節點 = NYT
tree->nodes[ROOT_NODE].child = NYT;
tree->nodes[ROOT_NODE].child_is_leaf = true;
tree->nodes[ROOT_NODE].weight = 0;
tree->nodes[ROOT_NODE].parent = -1;
tree->leaf[NYT] = ROOT_NODE;
for(int i = 0;i < NYT; i++)
{//每個字符所在節點位置,初值 -1,當發現此字符節點位置 = -1時,說明是新字符
tree->leaf[i] = -1;
}
}
void CMyDlg::EncodeSymbol(TREE *tree, BYTE ch, BYTE *output)
{//對字符進行編碼,新字符加入樹
long int current_node;
current_node = tree->leaf[ch];
BYTE tabletmp[8] = {0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe};//兩個臨時碼表,用于計算
BYTE tabletmp2[8] = {0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
int x,y,n;
char chartmp[256],tmp;//臨時記錄字符編碼,然后**倒序**輸出
x = outlength/8; //獲得輸出位置
y = outlength%8; //獲得非整字節剩余比特數
if(current_node == -1)
{//字符是第一次出現,把位置指到NYT所在節點位置
current_node = tree->leaf[NYT];
}
n = 0;//記錄字符編碼長度
while(current_node !=ROOT_NODE)
{//從葉節點向父節點查詢,直到根節點結束
chartmp[n++] = (current_node%2);
//如果節點是偶數,說明在左邊,用0編碼
//如果節點是奇數,說明在右邊,用1編碼
current_node = tree->nodes[current_node].parent;
}
if(y == 0) //如果是整字節
tmp = 0;
else
tmp = output[x];//否則,提取最后一字節信息部分
for(n--;n>=0;n--)
{//倒序輸出編碼
if(chartmp[n])//在相應的位置上加 1
tmp += tabletmp2[y++];
else
y++;
if(y == 8)
{//當tmp裝滿,輸出到output
output[x++] = tmp;
tmp = 0;
y = 0;
}
}
output[x] = tmp;//輸出剩余比特
outlength = x * 8 + y;//記錄編碼長度
if(tree->leaf[ch] == -1)
{//字符是第一次出現,輸出源碼,8比特
x = outlength/8;
y = outlength%8;
if(y == 0)
{//整字節,直接裝入
output[x] = ch;
}
else
{//非整字節,需移位
output[x] = (output[x]&tabletmp[y]) + (ch>>y);
output[x + 1] = (ch<<(8-y));
}
outlength += 8;//記錄編碼長度
add_new_node(tree,ch);//把新字符裝到Huffman樹中
}
}
int CMyDlg::DecodeSymbol(TREE *tree, BYTE *intput)
{//對壓縮編碼解碼
long int current_node;
int ch;
int x,y;
BYTE tabletmp2[8] = {0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
WORD tmp;
current_node = ROOT_NODE ;
while(!tree->nodes[current_node].child_is_leaf)
{//從根節點向子節點查詢,直到葉節點結束
current_node = tree->nodes[current_node].child - 1;
x = outlength/8;
y = outlength%8;
if((intput[x] & tabletmp2[y]) == 0)//根據編碼判斷向左走,還是向右走
current_node += 1;//如果是1向右走,0向左走
outlength++;//壓縮編碼計數
}
ch = tree->nodes[current_node].child;//獲得葉節點字符
if(ch == NYT)
{//如果字符是NYT,輸出后面8比特源碼
x = outlength/8;
y = outlength%8;
if(y == 0)
ch = intput[x];
else
{
tmp = (intput[x]<<8) +intput[x+1];
ch = (tmp>>(8-y))&0xff;
}
outlength += 8;//壓縮編碼計數
add_new_node(tree,ch);//把新字符裝到Huffman樹中
}
return(ch);//返回解碼字符
}
void CMyDlg::UpdateWeight(TREE *tree, WORD ch)
{//更新碼重,并調整樹
long int current_node;
long int new_node;
current_node = tree->leaf[ch];
while(current_node != -1)
{//從當前節點向上比較,
for(new_node = current_node; new_node > ROOT_NODE ;new_node--)
{//從當前節點到根節點
if(tree->nodes[new_node -1 ].weight > tree->nodes[current_node].weight)
break;//如果有比它權重大的,跳出
}
if(tree->nodes[current_node].parent != new_node && current_node != new_node)
{//如果比它大的節點的前一個節點不是他的父親,也不是他自己,交換節點
swap_nodes(tree,current_node,new_node);//交換節點
current_node = new_node;
}
tree->nodes[current_node].weight++;//當前節點權重加1
current_node = tree->nodes[current_node].parent;//繼續向父親查詢
}
}
void CMyDlg::swap_nodes(TREE *tree, long int current_node, long int new_node)
{//交換節點
CMyDlg::tree::node temp;
if(tree->nodes[current_node].child_is_leaf)//是葉節點,更新孩子(字符)的位置
tree->leaf[tree->nodes[current_node].child] = new_node;
else
{//不是葉節點,更新兩個孩子的父節點位置
tree->nodes[tree->nodes[current_node].child].parent = new_node;
tree->nodes[tree->nodes[current_node].child - 1].parent = new_node;
}
if(tree->nodes[new_node].child_is_leaf)
tree->leaf[tree->nodes[new_node].child] = current_node;
else
{
tree->nodes[tree->nodes[new_node].child].parent = current_node;
tree->nodes[tree->nodes[new_node].child - 1].parent = current_node;
}
temp = tree->nodes[current_node];
tree->nodes[current_node] = tree->nodes[new_node];
tree->nodes[current_node].parent = temp.parent;
temp.parent = tree->nodes[new_node].parent;
tree->nodes[new_node] = temp;
}
void CMyDlg::add_new_node(TREE *tree, WORD ch)
{//添加新字符到Huffman樹
long int old_node;//原節點
long int new_node;//新字符節點
long int NYT_node;//
old_node = tree->leaf[NYT];
new_node = tree->leaf[NYT] + 1;
NYT_node = tree->leaf[NYT] + 2;
tree->nodes[old_node].child = new_node + 1;
tree->nodes[old_node].child_is_leaf = false;
tree->nodes[new_node].child = ch;
tree->nodes[new_node].parent = old_node;
tree->nodes[new_node].child_is_leaf = true;
tree->nodes[new_node].weight = 0;
tree->nodes[NYT_node].child = NYT;
tree->nodes[NYT_node].child_is_leaf = true;
tree->nodes[NYT_node].weight = 0;
tree->nodes[NYT_node].parent = old_node;
tree->leaf[ch] = new_node;
tree->leaf[NYT] = NYT_node;
}
void CMyDlg::OnBtnhelp()
{
CHelp dlg;
dlg.DoModal();
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -