江苏科技大学电子信息学院
毕业论文
游程长度编码算法研究
蒋 伟
(设计者)
系 电子信息 专业 电子信息工程
班级 02403023 学号 0240302314
指导教师 田雨波 职称 副教授
2006 年 6 月
摘要
游程长度编码非常简单,编码、解码速度快,应用广泛。本文主要介绍了游程长度编码的原理和实现技术,对游程长度编码技术做了较为全面地研究。包括游程压缩模型、数据压缩、解压缩过程,并给出了流程图和相应的程序。
关键词:编码;解码;游程长度编码;压缩;解压缩。
RLC is very simple,and its speed of coding and decoding is quick So it has a wide application.This paper gives a brief introduction to the principles and realization technology of RLC Researching the RLC technology is in a relatively comprehensive way,including the RLC compression models,the processes of data compression and uncompression ,and giving the flow diagrams and relevant programs.
Keywords:code;decode;RLC;compression;uncompression
目录
2.1 Microsoft Visual C++ 6.0 中文版.... 9
绪论
信息时代人们对使用计算机获取信息、处理信息的依赖性越来越高。多媒体计算机系统面临的是数值、文字、语言、音乐、图形、动画、静图像、电视视频图像等多种媒体承载的由模拟量转化成数字量信息的吞吐、存储和传输的问题。数字化了的视频和音频信号的数量之大是惊人的,与硬件技术所能提供的计算机存储资源和网络带宽之间有很大差距。这样,对多媒体信息的存储和传输造成了很大困难,成为阻碍人们有效获取和利用信息的一个瓶颈问题。多媒体信息使用的前提是进行有效的压缩。例如一段时间长度为1 min,图像尺寸为640×480 pixete,每秒播放30帧的非压缩彩色24位真彩色视频的信息量为:640×480×3×30×60:1658880000Bytes,约为1.6GB(未含音频信息的容量),如果用650 MB的CD-R来存放,需要3张。由此可见,在视频信息的处理及应用过程中压缩及解压缩技术是十分必要的。
数据压缩技术主要采用两种方法:一种是“保真率”较高的无损压缩法;另一种是以损失信息细节而换取较高压缩比的有损压缩法。无损压缩虽然压缩比不是很高,但还原后的文件与原数据文件完全相同,从而保证了信息细节的不失真,常用的方法有统计式压缩法和字典式压缩法,统计式压缩法的编码方案主要是霍夫曼(Hufman)编码、算术编码(AC)和游程长度编码(RLC)。其中,游程长度编码是一种十分简单的压缩方法,编码/解码的速度也非常快,因此得到了广泛的应用。许多图形和视频文件,如.BMP,.TIF及.AVI等,都采用了这种压缩方法,尤其适用于文本(文件)数据压缩,它主要是去除文本中的冗余字符或字节中的冗余位以达到减少数据文件所占的存储空间的目的。
飞速发展的数据压缩和图像编码技术,给多媒体数据传输和数据存储带来极大的快捷和便利。但在某些数据安全性要求比较苛刻的领域,现在比较流行和压缩效果好的压缩算法几乎都属于有损范畴,对原始数据压缩处理后有不同程度的损伤,无法完全恢复,以至于不能满足技术要求,现有的无损压缩方法,如Huffman、LZ 系列、算术编码等压缩方法尽管在某些方面各有优点,但压缩效果比较差或者算法实现比较困难,因此十分有必要对无损压缩算法进行研究。通过对游程编码(Run LengthEncoding,RLE)进行研究,最后提出一种实现相对简单、压缩效果比较好的算法,采用该算法可以收到比较理想的效果,基本克服由于RLE自身特点而引起的数据扩张的现象。
第一章 游程长度编码算法概述
飞速发展的数据压缩和图像编码技术,给多媒体数据传输和数据存储带来极大的快捷和便利。但在某些数据安全性要求比较苛刻的领域,现在比较流行和压缩效果好的压缩算法几乎都属于有损范畴,对原始数据压缩处理后有不同程度的损伤,无法完全恢复,以至于不能满足技术要求。现有的无损压缩方法,如Huffman、LZ 系列、算术编码等压缩方法尽管在某些方面各有优点,但压缩效果比较差或者算法实现比较困难,因此十分有必要对无损压缩算法进行研究。
1.1 信源编码原理[1][2][5][7]
定义一象元的M层,其灰度值 的平均信息量或熵为:
(1.1)
其中 为每一个灰度等级 出现的概率,熵值可以在0~ 之间变化,即编码后的码长平均起来不得少于熵值 。对于游程编码,设定一个象元出现边缘的概率为P,而象元间是相对独立的,则边缘间游程长度Z的概率分布可用下式表示:
(1.2)
式中 。当游程长度 时,表示两个相邻边缘的情况。在这种简单的统计假设条件下,边缘长度的均值 为:
(1.3)
而边缘间游程长度Z的熵为:
(1.4)
假如游程的最大长度为M个象元,则对应的边缘间的熵,可近似得出:
(1.5)
把对应边缘间游程的熵除以游程长度的均值,就可以得到每个象元的熵为:
(1.6)
以上各式的推导参见[1]。由以上公式可以得出对于黑白灰度的二值图象,使用二维游程编码,可以使压缩比达到10:1。
1.2 游程长度
游程长度RL(Run-Length),简称游程或游长,指的是由字符(或信号取样值)构成的数据流中各个字符重复出现而形成的字符的长度。如果给出了形成串的字符,串的长度以及串的位置,就能恢复出原来的数据流,游程长度编码(RLC)就是用二进制码字给出这些信息的一类方法。
1.3 游程长度编码的基本原理[5][9]
在二元序列中,只有两种符号,即“0”和“1”,这些符号可连续出现,连“0”这一段称为“0”游程,连“1”这一段称为“1”游程。它们的长度分别称为游程长度L(0)和L(l)。“0”游程和“l”游程总是交替出现的。如果规定二元序列是以“0”开始,第一个游程是“0”游程,第二个必为“1”游程,第三个又是“0”游程等等。对于随机的二元序列,各游程长度将是随机变量,其取值可为1,2,3,…,直到无限。
将任何(二元)序列变换成一一对应的游程长度序列,再按哈夫曼编码或其他方法处理以达到压缩码率的目的 。
游程长度编码的主要思想是将一个相同值的连续申用其值和申长(重复的个数)的数对二元组来替代.例如,在图像编码中,可以定义沿特定方向上具有相同灰度值的相邻像素为一轮,其延续的长度称之为延续的行程,即游程.游程终点位置由前一游程终点的相对距离确定,这样就可以由灰度游程串来表示图像数据.例如,若沿水平方向有一串M 个像素具有相同的灰度N,则按游程长度编码后,只传递两个值(N,M)就可以代替这M 个像素的M个灰度值NJ简单来说,游程长度编码的主要任务是统计连续相同字符的个数,解码时要根据字符及连续相同字符的个数,恢复原来的数据。
1.3.1 文本游程压缩的原理
对重复字段采用3符号标识法:
(1) 重复提示符,比如@,#等;
(2) 游程长度参数或重复次数,若用一个字节表示,最大长度可为255个重复字;
(3) 重复字符。以上三部分合称为重复因子。可见要获得压缩效益,重复字符应在3个以上。
对于非重复字段则直接拷贝字段,不做任何处理。
1.3.2 图象游程压缩的原理
对于二值图像,原始数据为零一矩阵,压缩时逐行处理该矩阵:
(1) 连续n个1,表示为+n;
(2) 连续n个0,表示为-n。
在游程长度编码(RLC)中用3个字节表示一个字符申:第一个字节是压缩指示字符,第二个字节记录连续出现的字符,第三个字节记录重复字符出现的次数。可见,只有当RL>3时进行数据压缩才有意义,因此,编码时首先要判断RL值,然后再决定是否进行游程长度编码(RLC);解码时则需根据每一字符后是否为,再决定其下一字符的含义,如下图所示:
例如:设一幅二维黑白图像F(i,j)的各像素的灰度值如下所示,规定沿水平方向从左到右扫描,则扫描后得到的游程为右边的13个二元数组。
图表 1.1
图表 2.2
由上例可见:
(1)该图像是由8行、8列共64个像素组成;
(2)像素的灰度值变化范围是:0~8;
由于是黑白图,颜色过渡只是黑一灰一白,按人眼分辨率,用8 bit即得 。
(3)第一行8个像素灰度值相同,只传(8,8);第二行只传(8,4) (7,4);第三行只传(7,8);第四行只传(6,4)(5,4);第五行时只传(5,5) (3,3);第六行只传(3,8);第七行只传(3,3) (2,5);第八行只传(1,4)(0,4)。这样,64个像素只需传13个数据对即可, 比一个个像素传送要节省很多时间.
一般情况下,编码时间为2~4倍的解码时间。
第二章 开发环境
2.1 Microsoft Visual C++ 6.0 中文版[3]
2.1.1 简介
Microsoft Visual C++是一种从C语言的基础上逐步发展和完善起来的,而C是吸收了其他语言的一些优点逐步成为实用性很强的一种语言。
C++并不是对C语言的简单的改进和扩充,而是一种本质性革新。C++是C语言的一个超集,大多书的C程序代码略做修改和不做修改就可以在C++的集成环境下调试。C++是面向对象的程序设计语言,它似的程序的各个模块的独立性更强,程序可读性和可理解性更好。C++的扩充性强,具有封装性,继承派生性,重载性和多态性。
Microsoft Visual C++ 6.0 中文版为用户开放C++程序提供了一个集成的环境,而这个集成环境包括:源程序的输入,编辑和修改,源程序的编译和连接,程序运行间的调试和跟踪,项目的自动管理,为程序的开放提供工具,窗口管理,联机帮助。正是由于这个继承的环境功能齐全,故选择了Microsoft Visual C++ 6.0 中文版作为界面,图象文本压缩的开放工具。
2.1.2 主要特点
在Windows 98或XP下启动VC++的集成环境,则产生下图所示的组合窗口。
窗口的最上面部分为标题。第二部分为菜单条,其中包括“文件(File)编辑(edit)”等菜单。第三部分是功能按钮,类同于Word,有“打开”文件等等按扭。
当要建立一个新的源程序文件时,选择“file”菜单中的“new”命令,这时弹出一个子窗口,在子窗口中选择“file”按扭,在弹出的信息窗口中再选择“c++ source file”,这时光标进入源程序编辑子窗口,就可以输入源程序了。
当正确输入源程序文件后,可以选择“file”菜单中的“open”命令,然后按照提示的信息,选择相应的源程序文件名。由系统将指定的源程序文件调入源程序编辑子窗口,就可以对源程序文件进行编辑。
当正确地输入源程序文件后,先存盘,然后可选择“build”菜单中的“build”命令来编译源程序和连接目标程序,最后选择“build”菜单中的“execute”来执行程序。
图表 2.1 Microsoft Visual C++ 6.0界面
第三章 实现算法
3.1 数据压缩算法流程[1]
用游程长度编码压缩数据时,首先要计算每次连续相同字符的个数,然后将每次连续相同的字符及个数保存起来。这种压缩数据的方法,连续相同的字符及出现连续相同的次数越多,压缩比就越大,反之,压缩比就越小。
(1)打开源数据文件和压缩后的数据文件;
(2)从源数据文件中读取字符,并把它放人一个寄存器中,然后再循环读取后面的字符,并与寄存器中的字符相比较。如果相等,则计数器加1,否则,把寄存器中的字符和计数器中数写入压缩数据文件中,然后再把寄存器中字符不相等的字符放入寄存器中,并把计数器置1。
图表 3.1 RLC数据压缩算法流程图
3.2 数据解压算法流程
(1)打开压缩数据文件和恢复文件;
(2)从压缩文件中循环读出字符和该字符连续的个数,在恢复文件中连续写入从压缩文件中读出的字符,写的次数等于该字符连续的个数。
图表 3.2 RLC数据解压缩算法流程图
3.3 文本游程压缩的算法
3.3.1 文本压缩部分
初始化计数变量(已读字符数C,重复字符数R);
如果待压缩文本m_cOriginalText没有结束{
读取当前字符CH;
如果当前字符是第一个字符,将比较字符SH设为当前字符,continue;
如果当前字符等于比较字符,重复次数加一,continue;
如果重复次数小于3,将比较字符写入压缩流m_cCompressText:R+1次,重复次
数置零,将比较字符设为当前字符,continue;
将重复字符,以三字节格式写入压缩流m_cCompressText;重复次数置零,将比较字符设为当前字符,continue;
}
注:continue表示结束本次循环,并转下次循环的入口点。
3.3.2 文本解压部分
如果压缩文本m_cCompressText中还有字符{
读取当前字符cCur;
如果当前字符等于'@',读取重复字符cR以及重复次数iNum,将重复字符写入解压流m_cUncompressText:iNum次,continue;
将当前字符写入解压流m_cUncompressText;
}
3.4 图象游程压缩的算法
3.4.1 图象压缩部分
对于二值矩阵Original的每一行{
重复计数iNum赋值为1;
对于该行的第一列~倒数第二列中的每一列{
如果当前列的值=下一列的值{
重复计数iNum加一;
如果当前列是倒数第二列{
如果当前列的值=1,将iNum写入压缩数据链pCompress,否则将-iNum写入压缩数据链pCompress;
}
}
否则{ //如果当前列的值不等于下一列的值
如果当前列的值=1,将iNum写入压缩数据链pCompress,否则将-iNum写入压缩数据链pCompress;
置重复计数iNum为1;
如果当前列是倒数第二列{
如果下一列的值=1,将+1写入压缩数据链pCompress,否则将-1写入压缩数据链pCompress;
}
}
}
}
3.4.2 图象解压部分
如果压缩数据链pCompress上的数据已处理完,结束解压;
从压缩数据链上取一个数据;
如果数据值val>0,则向解压结果数组Uncompress中写入val个1,否则写入-val个0(也可写-1);
准备取下一个数据;
}
第四章 系统原理
4.1 程序运行主界面[4]
本实验的程序采用VC6.0编制,程序类型为MFC,实验的主界面如图1。点击菜单“RLEText”,将弹出“文本的游程压缩”对话框,如图。点击菜单“RLEBmp”,将弹出“图像的游程压缩”对话框,如图4.1。
图表 4.1 程序主界面
4.2 文本游程压缩的界面与程序
点击“压缩”按钮,压缩结果将出现在相应的文本框中,如图4.2。压缩代码如下。
//【获取原文本】
CString sOriginalText,s;
this->GetDlgItemText(IDC_EDIT_Original,sOriginalText);
strcpy( m_cOriginalText,(LPSTR)(LPCTSTR)sOriginalText );
//【压缩文本】
//初始化计数变量
int R=0; //重复字符数
int C=0; //已读字符数
int CC=0;
char CH; //当前字符
char SH; //比较字符
//如果文本没有结束{
do{
//读取当前字符
CH=m_cOriginalText[C];
C++;
//如果当前字符是第一个字符,将比较字符设为当前字符,continue
if (C==1){
SH=CH;
continue;
}
//如果当前字符等于比较字符,重复次数加一,continue
if (CH==SH){
R++;
continue;
}
//如果重复次数小于3,将比较字符写入压缩流:R+1次; 重复次数置零,将比较字符设为当前字符,continue
if (R<3){
for(int i=0; i<=R; i++){
m_cCompressText[CC]=SH;
CC++;
}
R=0;
SH=CH;
continue;
}
//将重复字符,以三字节格式写入压缩流;重复次数置零,将比较字符设为当前字符,continue
m_cCompressText[CC++]='@';
char cNum=(char)(R+1);
m_cCompressText[CC++]=cNum;
m_cCompressText[CC++]=SH;
R=0;
SH=CH;
//}
} while( CH!='/0' );
C--;
m_cCompressText[CC]='/0';
s.Format(" 原字符数=%d/n 压缩字符数=%d/n 压缩比=%f",C,CC,(C+0.0)/CC);
::AfxMessageBox(s);
//【设置压缩文本,激活解压按钮】
this->SetDlgItemText(IDC_EDIT_Compress,CString(this->m_cCompressText));
CButton *pBtn;
pBtn=(CButton*)GetDlgItem(IDC_BUTTON_Uncompress);
pBtn->EnableWindow(TRUE);
pBtn=(CButton*)GetDlgItem(IDC_BUTTON_Compress2);
pBtn->EnableWindow(TRUE);
图表 4.2 文本压缩界面
图表 4.3文本的游程压缩结果(将字节计数转换为字符串)
我们发现压缩结果中,重复因子的第二个字符,即用于计数的字符无法显示。要显示计数,需获取重复因子的第二个字符的ASCII码对应的字符串,处理结果如图4.3。代码如下。
//将压缩文本中的@后的一字节计数用数字串替换
int iAt,iStart=0;
char cNum;
CString csCompressText,csNum;
csCompressText.Format("%s",m_cCompressText);
while( (iAt=csCompressText.Find('@',iStart))>=0 ){
cNum=csCompressText.GetAt(iAt+1);
csNum.Format("[%d]",int(cNum));
csCompressText.Delete(iAt+1);
csCompressText.Insert(iAt+1,csNum);
iStart=iAt+1;
}
this->SetDlgItemText(IDC_EDIT_Compress,csCompressText);
我们对压缩的文本进行解压,得到的还原文本与原文本一样,处理结果如图4.4。代码如下。
int iC=0/*压缩文本字符计数*/,iU=0/*解压结果文本字符计数*/;
int iNum/*重复次数*/;
char cCur/*当前字符*/,cR/*重复字符*/;
//如果压缩文本中还有字符{
while( m_cCompressText[iC]!='/0' ){
//读取当前字符;
cCur=m_cCompressText[iC];
iC++;
//如果当前字符等于'@',读取重复字符cR以及计数iNum,将重复字符写入解压流:iNum次,continue;
if (cCur=='@'){
cR=m_cCompressText[iC+1];
iNum=(int)m_cCompressText[iC];
for(int i=0; i<iNum; i++){
m_cUncompressText[iU++]=cR;
}
iC+=2;
continue;
}
//将当前字符写入解压流;
m_cUncompressText[iU++]=cCur;
//}
}
m_cUncompressText[iU]='/0';
this->SetDlgItemText(IDC_EDIT_Uncompress,CString(this->m_cUncompressText));
图表 4.4文本的游程压缩-解压
4.3 图象压缩的界面和程序
图像游程压缩的原始数据为二值数组,我们用方格阵列来模拟该二值数组,方格填充对应的数值为1,否则为-1。通过绘制方格阵列,我们可获得原始数据,如图4.5
图表 4.5图像的游程压缩-绘制图像
点击“压缩”按钮,得到的压缩结果如图7,代码如下。
//对于二值矩阵Original的每一行{
for(int i=0; i<PANES_Row; i++){
//重复计数iNum赋值为1;
iNum=1;
//对于该行的第一列~倒数第二列中的每一列{
for(int j=0; j< (PANES_Col-1); j++){
//如果当前列的值=下一列的值{
if( Original[PANES_Col*i+j]==Original[PANES_Col*i+j+1] ){
//重复计数iNum加一;
iNum++;
//如果当前列是倒数第二列{
if( j==(PANES_Col-2) ){
pNext=new CompressNode;
//如果当前列的值=1,将iNum写入压缩数据链pCompress,否则将-iNum写入压缩数据链pCompress;
pNext->val=(Original[PANES_Col*i+j]==1)? iNum:(-iNum);
pNext->next=NULL;
pPre->next=pNext;
pPre=pNext;
iNum=1;
}
}
//否则{ //如果当前列的值不等于下一列的值
else{
pNext=new CompressNode;
//如果当前列的值=1,将iNum写入压缩数据链pCompress,否则将-iNum写入压缩数据链pCompress;
pNext->val=(Original[PANES_Col*i+j]==1)? iNum:(-iNum);
pNext->next=NULL;
pPre->next=pNext;
pPre=pNext;
//置重复计数iNum为1;
iNum=1;
//如果当前列是倒数第二列{
if( j==(PANES_Col-2) ){
pNext=new CompressNode;
//如果下一列的值=1,将+1写入压缩数据链pCompress,否则将-1写入压缩数据链pCompress;
pNext->val=(Original[PANES_Col*i+j+1]==1)? 1:(-1);
pNext->next=NULL;
pPre->next=pNext;
pPre=pNext;
iNum=1;
//}
}
//}
}
//}
}
//}
}
//显示压缩结果,激活解压按钮
pPre=pCompress->next;
CString csCompress="",cs;
int iSum=0;
while(pPre!=NULL){
cs.Format("%6d",pPre->val);
csCompress+=cs;
if(pPre->val>0)
iSum+=pPre->val;
else
iSum-=pPre->val;
if(iSum%PANES_Col==0)
csCompress+="/r/n";
pPre=pPre->next;
}
this->SetDlgItemText(IDC_EDIT_Compress,csCompress);
CButton *pBtn;
pBtn=(CButton*)GetDlgItem(IDC_BUTTON_Uncompress);
pBtn->EnableWindow(TRUE);
图表 4.6图像的游程压缩-压缩
点击“解压”,将在还原图像区显示解压结果,如图8,代码如下。
//如果解压的结果数组Uncompress没有填满{
while( k<(PANES_Row*PANES_Col) ){
//如果压缩数据链pCompress上的数据已处理完,结束解压;
if(p==NULL)
break;
//从压缩数据链上取一个数据;如果数据值val>0,则向解压结果数组Uncompress中写入val个1,
if(p->val>0){
for(int i=0; i<p->val; i++)
Uncompress[k++]=1;
}
//否则写入val个-1;
else{
for(int i=0; i<(-p->val); i++)
Uncompress[k++]=-1;
}
//准备取下一个数据;
p=p->next;
}
//显示图像
pTable2->Fill(Uncompress);
第五章 游程长度编码压缩算法的讨论
游程长度编码压缩方法的压缩比与文本中字符重复出现的概率及长度有关。表5.1给出了对长度均为1000Bytes的不同文件,使用游程长度编码进行压缩后,压缩比、字符出现次数及重复字符串平均长度之间的统计和对比情况。根据表5.1的统计来看,在文本中字符重复出现次数相同的情况下,重复字符串的平均长度越长,压缩比就越高;在重复字符串的平均长度相同的情况下,字符重复出现的次数越多,压缩比也越高。
出现重复字符次数 | 重复字符串的平均长度 | 压缩比(%) |
10 10 10 20 20 20 30 30 30 50 50 50 | 4 6 10 4 6 10 4 6 10 4 6 10 | 1.33 3.01 6.89 1.96 6.02 14.12 3.01 9.02 21.01 5.03 14.96 34.98 |
结 束 语
转眼之间,两个半月的毕业设计即将结束,我们也将离开学校,踏上工作岗位。经过这段时间的学习与实践,我对游程长度编码与信号编码的发展及现状有了更深刻的认识,意识到数据压缩与解压对社会生活的巨大影响及其潜在经济效益,并对Microsoft Visual C++ 6.0软件有了一定程度的了解,学习了信源编码的相关知识及如何利用Microsoft Visual C++ 6.0编译程序。经过这段短暂时间的学习,我想我对于知识的猎取是有限的,关键是我学会了如何用认真、严谨的学习态度去面对工作,如何用自学的方法来处理问题,如何以积极的团队协作精神去相处同组同学。
我们这次主要涉及的是C++,图象压缩编码相关领域的课题,由于以前没有系统地学习过这方面的知识,所以肯定有一定的缺陷,恳请老师们耐心批评与指正。
游程长度编码RLC一般不直接应用于多灰度图像,但是比较适台于二值图像的编码,例如传真图像的编码等.为了达到较好的压缩效果。有时游程长度编码和其它一些编码方法混台使用.例如,在JPEG中,游程长度编码和离散余弦变换DCT(Discrete Cosine Transform)及霍夫曼(Huffman)编码一起使用,对分块做完DCT及量化后的频域图像数据做z形扫描,然后做游程长度编码,对游程长度编码的结果再做霍夫曼编码.
游程压缩作为数据压缩技术的一个分支,理论浅显,压缩比之高已经让人刮目相看,这不由令人对数据压缩技术肃然起敬。走过半个多世纪的离散余弦变换理论在数据压缩领域至今不衰;新兴的神经网络理论将数据压缩推向了一个新的高度;近来,小波变换理论更使数据压缩技术登峰造极,图像压缩的JPEG2000标准使小波理论傲视群雄。可以预见,新的数学理论将不断为数据压缩技术输入新鲜血液,因此数学理论决不可偏废。
致 谢
本篇论文的选题、收集资料和撰写工作都是在 田雨波 老师的指导下完成的。在毕业设计期间, 田雨波 老师在工作繁忙的情况下,不辞辛苦,多次为我们查找、提供资料。田雨波治学严谨、待人亲切的态度,深深的影响了我们。为此,我 向田 老师表示深深的谢意,感 谢田 老师在毕业设计期间对我们的关怀和指导。
在此期间,信号与系统实验室的老师们也为我们提供了许多帮助,在此对他们也表示深深的感谢。在此期间,给老师们带来的种种不便,请老师们谅解。对那些曾经帮助过我的同学们也表示衷心的谢意。
参考文献
[1] 刘冰, 游程长度编码算法的研究, 天津理工学院学报, 10(6): 77~81.
[2] 王辉, 王晓群, 多媒体应用基础, 清华大学出版社, 1999年.
[3] 洪小达,《多媒体计算机与数据压缩技术》 中国国际广播出版社 1999年6月
[4] 黄国胜 刘珠 饶一梅,《多媒体速成与应用》 天津科学技术出版社 1997年3月
[5] 翟屺,《数字图象处理技术与应用》 电子工业出版社 1997年5月
[6] Steve Rimmer,木杉,《Windows图象处理实用技术和范例》 学苑出版社 1994年11月
[7] 《精通Visual C++ 图象编程》电子工业出版社 2003年1月
[8] 朱志刚,《数字图象处理》清华大学出版社1998年1月
[9] J. Oliver, M. P. Malumbres, A simple picture coding algorithm with fast run-length mode.
附录3
头文件(1) Compress.h
// Compress.cpp : Defines the class behaviors for the application.
//
#include "stdafx.h"
#include "Compress.h"
#include "MainFrm.h"
#include "CompressDoc.h"
#include "CompressView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CCompressApp
BEGIN_MESSAGE_MAP(CCompressApp, CWinApp)
//{{AFX_MSG_MAP(CCompressApp)
ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
// Standard file based document commands
ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
// Standard print setup command
ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CCompressApp construction
CCompressApp::CCompressApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
/////////////////////////////////////////////////////////////////////////////
// The one and only CCompressApp object
CCompressApp theApp;
/////////////////////////////////////////////////////////////////////////////
// CCompressApp initialization
BOOL CCompressApp::InitInstance()
{
AfxEnableControlContainer();
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need.
#ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif
// Change the registry key under which our settings are stored.
// TODO: You should modify this string to be something appropriate
// such as the name of your company or organization.
SetRegistryKey(_T("Local AppWizard-Generated Applications"));
LoadStdProfileSettings(); // Load standard INI file options (including MRU)
// Register the application's document templates. Document templates
// serve as the connection between documents, frame windows and views.
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CCompressDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CCompressView));
AddDocTemplate(pDocTemplate);
// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
// Dispatch commands specified on the command line
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// The one and only window has been initialized, so show and update it.
m_pMainWnd->SetWindowText("数据压缩"); //设置初始时的窗口标题
m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED); //设置初始时的窗口大小
m_pMainWnd->UpdateWindow();
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// 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)
// No message handlers
//}}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()
// App command to run the dialog
void CCompressApp::OnAppAbout()
{
CAboutDlg aboutDlg;
aboutDlg.DoModal();
}
/////////////////////////////////////////////////////////////////////////////
// CCompressApp message handlers
头文件(2)CompressDoc.h
// CompressDoc.h : interface of the CCompressDoc class
//
/////////////////////////////////////////////////////////////////////////////
#if !defined(AFX_COMPRESSDOC_H__91FCBE6D_0066_4427_ 95A 7_ 6149A 9C 1CD58__INCLUDED_)
#define AFX_COMPRESSDOC_H__91FCBE6D_0066_4427_ 95A 7_ 6149A 9C 1CD58__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CCompressDoc : public CDocument
{
protected: // create from serialization only
CCompressDoc();
DECLARE_DYNCREATE(CCompressDoc)
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CCompressDoc)
public:
virtual BOOL OnNewDocument();
virtual void Serialize(CArchive& ar);
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CCompressDoc();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Generated message map functions
protected:
//{{AFX_MSG(CCompressDoc)
// NOTE - the ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_COMPRESSDOC_H__91FCBE6D_0066_4427_ 95A 7_ 6149A 9C 1CD58__INCLUDED_)
头文件(3)CompressView.h
// CompressView.h : interface of the CCompressView class
//
/////////////////////////////////////////////////////////////////////////////
#if !defined(AFX_COMPRESSVIEW_H__3B 0A 0725_FEB9_4412_B3BB_39BA8711770B__INCLUDED_)
#define AFX_COMPRESSVIEW_H__3B 0A 0725_FEB9_4412_B3BB_39BA8711770B__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CCompressView : public CView
{
protected: // create from serialization only
CCompressView();
DECLARE_DYNCREATE(CCompressView)
// Attributes
public:
CCompressDoc* GetDocument();
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CCompressView)
public:
virtual void OnDraw(CDC* pDC); // overridden to draw this view
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CCompressView();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Generated message map functions
protected:
//{{AFX_MSG(CCompressView)
// NOTE - the ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
#ifndef _DEBUG // debug version in CompressView.cpp
inline CCompressDoc* CCompressView::GetDocument()
{ return (CCompressDoc*)m_pDocument; }
#endif
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_COMPRESSVIEW_H__3B 0A 0725_FEB9_4412_B3BB_39BA8711770B__INCLUDED_)
头文件(4)DlgRLEBmp.h
#if !defined(AFX_DLGRLEBMP_H__822593EA_1ABF_4FC0_B8D2_ 3A 9F 211A 0ECE__INCLUDED_)
#define AFX_DLGRLEBMP_H__822593EA_1ABF_4FC0_B8D2_ 3A 9F 211A 0ECE__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// DlgRLEBmp.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// CDlgRLEBmp dialog
class CDlgRLEBmp : public CDialog
{
// Construction
public:
CDlgRLEBmp(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CDlgRLEBmp)
enum { IDD = IDD_DIALOG_RLEBmp };
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CDlgRLEBmp)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
// Generated message map functions
//{{AFX_MSG(CDlgRLEBmp)
virtual BOOL OnInitDialog();
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnPaint();
afx_msg void OnBUTTONClear();
afx_msg void OnBUTTONCompress();
afx_msg void OnBUTTONUncompress();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
CPanes *pTable1;
CPanes *pTable2;
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_DLGRLEBMP_H__822593EA_1ABF_4FC0_B8D2_ 3A 9F 211A 0ECE__INCLUDED_)
头文件(5)DlgRLEText.h
#if !defined(AFX_DLGRLETEXT_H__F5ECC590_8E6B_ 4A 1C _A495_501025CCF 9F 3__INCLUDED_)
#define AFX_DLGRLETEXT_H__F5ECC590_8E6B_ 4A 1C _A495_501025CCF 9F 3__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// DlgRLEText.h : header file
//
#define MAX 4096
/////////////////////////////////////////////////////////////////////////////
// CDlgRLEText dialog
class CDlgRLEText : public CDialog
{
// Construction
public:
CDlgRLEText(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CDlgRLEText)
enum { IDD = IDD_DIALOG_RLEText };
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CDlgRLEText)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
char m_cOriginalText[MAX];
char m_cCompressText[MAX];
char m_cUncompressText[MAX];
// Generated message map functions
//{{AFX_MSG(CDlgRLEText)
afx_msg void OnBUTTONCompress();
afx_msg void OnBUTTONUncompress();
afx_msg void OnBUTTONCompress2();
afx_msg void OnChangeEDITOriginal();
virtual BOOL OnInitDialog();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_DLGRLETEXT_H__F5ECC590_8E6B_ 4A 1C _A495_501025CCF 9F 3__INCLUDED_)
头文件(6)MainFrm.h
// MainFrm.h : interface of the CMainFrame class
//
/////////////////////////////////////////////////////////////////////////////
#if !defined(AFX_MAINFRM_H__ 2A 00E727_ 68F 6_404D_9DA7_6423DFD1DF81__INCLUDED_)
#define AFX_MAINFRM_H__ 2A 00E727_ 68F 6_404D_9DA7_6423DFD1DF81__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CMainFrame : public CFrameWnd
{
protected: // create from serialization only
CMainFrame();
DECLARE_DYNCREATE(CMainFrame)
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMainFrame)
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CMainFrame();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected: // control bar embedded members
CStatusBar m_wndStatusBar;
CToolBar m_wndToolBar;
// Generated message map functions
protected:
//{{AFX_MSG(CMainFrame)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnMENUITEMRLEText();
afx_msg void OnMENUITEMRLEBmp();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_MAINFRM_H__ 2A 00E727_ 68F 6_404D_9DA7_6423DFD1DF81__INCLUDED_)
头文件(7)Panes.h
// Panes.h: interface for the CPanes class.
//
//////////////////////////////////////////////////////////////////////
/*****************************************************************
* 名称:CDialog中的栅格画板类
* 作者:江苏科技大学电子信息工程学院 蒋伟 kof2003@126.com
* 时间: 2005-05-20
* 功能:
1、画有边界的方格组成的表格,能够设定
1)表格的位置(x0,y0)、行列数(row,col),方格的高宽(height=,width=);
2)表格的背景色(panesBkColor=);
3)边界(borderColor=);
4)方格的填充色与空白色(paneFillColor=,paneNullColor=);
5)方格与方格边界(表格线)的距离(ppDistance=1)。
2、表格给出文字标题,能够设定
1)标题的位置(titleX0=,titleY0=);
2)标题文字的字体(titleFont="宋体",titleLfheight,titleLfwidth);
3)标题文字的背景色与颜色(titleBkColor=,titleColor=)。
3、能够采集某一等比矩形框内的象素。
1)并填充表格;
2)象素表格存为文件。
3) 另外外来象素数据也可以填充表格;
4、能够相应鼠标的绘图操作
1)鼠标左键在表格区按下,进入填充方格状态;
2)填充状态下,鼠标在表格区移动,则填充所在位置的方格,
一旦移出表格,则取消填充状态;
3)鼠标左键抬起,则取消填充状态。
5、自绘。
table[row][col]:表格状态;
title:表格标题。
******************************************************************/
#if !defined(AFX_PANES_H__8251D377_E89E_4FFE_8AF7_8E8BA 35F 6BAD__INCLUDED_)
#define AFX_PANES_H__8251D377_E89E_4FFE_8AF7_8E8BA 35F 6BAD__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CPanes
{
private:
CPanes();
public:
virtual ~CPanes();
CPanes(CDialog * pDlg,int x0, int y0, int row,int col,int height,int width,
COLORREF panesBkColor=RGB(255,255,255),
COLORREF borderColor=RGB(0x0,0x4d,0x99),
COLORREF paneFillColor=RGB(0,125,0),
COLORREF paneNullColor=RGB(255,255,255),
int ppDistance=1,CString title=""
);
private:
int x0,y0,x1,y1;
int row,col;
int height,width;
COLORREF panesBkColor;
COLORREF borderColor;
COLORREF paneFillColor,paneNullColor;
int ppDistance;
/****************************/
CString title;
int titleX0,titleY0;
CString titleFont;
int titleLfheight,titleLfwidth;
COLORREF titleBkColor,titleColor;
/****************************/
CString sample;
int sampleX0,sampleY0;
CString sampleFont;
int sampleLfheight,sampleLfwidth;
COLORREF sampleBkColor,sampleColor;
/****************************/
static int DRAW_SAMPLE;
CDialog *pDlg;
CDC *pDC;
CBrush *pBrushPanes,*pBrushPaneFill,*pBrushPaneNull,*pBrush;
CPen penBorder,*pPen;
CFont font,*pFont;
int bDrawing;
int **samplePixels;
void GetSample(int x,int y);
int **table;
public:
void ToFile(CString fileName, CString sBlank="");
void Fill(int p[]);
void Fill(int **p);
void Get(int p[]);
void Get(int **p);
//void Get(int p[][]);
void DoLButtonDown(CPoint point);
void DoMouseMove(CPoint point);
void DoLButtonUp(CPoint point);
void Draw(int drawPart=0);
void Draw(int r,int c,int bin);
void Clear();
void FillSample(int x,int y);
void SetSample( CString sample,
int sampleX0,int sampleY0,
CString sampleFont,
COLORREF sampleBkColor,COLORREF sampleColor);
void useFuncPoint( void (*pFunc)()=NULL);
//函数指针作函数参数,参数函数不论参数多少定义格式一样。P-243
};
#endif // !defined(AFX_PANES_H__8251D377_E89E_4FFE_8AF7_8E8BA 35F 6BAD__INCLUDED_)
头文件(8) Resource.h
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by Compress.rc
//
#define IDC_BUTTON_Compress 3
#define IDC_BUTTON_Compress2 4
#define IDC_BUTTON_Uncompress 6
#define IDD_ABOUTBOX 100
#define IDR_MAINFRAME 128
#define IDR_COMPRETYPE 129
#define IDD_DIALOG_RLEText 130
#define IDD_DIALOG_RLEBmp 131
#define IDC_EDIT_Uncompress 1001
#define IDC_EDIT_Compress 1002
#define IDC_EDIT_Original 1003
#define IDC_BUTTON_Clear 1007
#define ID_MENUITEM_RLEText 32771
#define ID_MENUITEM_RLEBmp 32772
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_3D_CONTROLS 1
#define _APS_NEXT_RESOURCE_VALUE 132
#define _APS_NEXT_COMMAND_VALUE 32773
#define _APS_NEXT_CONTROL_VALUE 1009
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
头文件(9)StdAfx.h
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#if !defined(AFX_STDAFX_H__ 585AC 80A _ 848F _45FD_B40B_9ACB5DD1EA9D__INCLUDED_)
#define AFX_STDAFX_H__ 585AC 80A _ 848F _45FD_B40B_9ACB5DD1EA9D__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
#include <afxwin.h> // MFC core and standard components
#include <afxext.h> // MFC extensions
#include <afxdisp.h> // MFC Automation classes
#include <afxdtctl.h> // MFC support for Internet Explorer 4 Common Controls
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h> // MFC support for Windows Common Controls
#endif // _AFX_NO_AFXCMN_SUPPORT
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_STDAFX_H__ 585AC 80A _ 848F _45FD_B40B_9ACB5DD1EA9D__INCLUDED_)
主函数(1) Compress.cpp
// Compress.cpp : Defines the class behaviors for the application.
//
#include "stdafx.h"
#include "Compress.h"
#include "MainFrm.h"
#include "CompressDoc.h"
#include "CompressView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CCompressApp
BEGIN_MESSAGE_MAP(CCompressApp, CWinApp)
//{{AFX_MSG_MAP(CCompressApp)
ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
// Standard file based document commands
ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
// Standard print setup command
ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CCompressApp construction
CCompressApp::CCompressApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
/////////////////////////////////////////////////////////////////////////////
// The one and only CCompressApp object
CCompressApp theApp;
/////////////////////////////////////////////////////////////////////////////
// CCompressApp initialization
BOOL CCompressApp::InitInstance()
{
AfxEnableControlContainer();
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need.
#ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif
// Change the registry key under which our settings are stored.
// TODO: You should modify this string to be something appropriate
// such as the name of your company or organization.
SetRegistryKey(_T("Local AppWizard-Generated Applications"));
LoadStdProfileSettings(); // Load standard INI file options (including MRU)
// Register the application's document templates. Document templates
// serve as the connection between documents, frame windows and views.
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CCompressDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CCompressView));
AddDocTemplate(pDocTemplate);
// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
// Dispatch commands specified on the command line
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// The one and only window has been initialized, so show and update it.
m_pMainWnd->SetWindowText("数据压缩"); //设置初始时的窗口标题
m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED); //设置初始时的窗口大小
m_pMainWnd->UpdateWindow();
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// 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)
// No message handlers
//}}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()
// App command to run the dialog
void CCompressApp::OnAppAbout()
{
CAboutDlg aboutDlg;
aboutDlg.DoModal();
}
/////////////////////////////////////////////////////////////////////////////
// CCompressApp message handlers
主函数 (2) CompressDoc.cpp
// CompressDoc.cpp : implementation of the CCompressDoc class
//
#include "stdafx.h"
#include "Compress.h"
#include "CompressDoc.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CCompressDoc
IMPLEMENT_DYNCREATE(CCompressDoc, CDocument)
BEGIN_MESSAGE_MAP(CCompressDoc, CDocument)
//{{AFX_MSG_MAP(CCompressDoc)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CCompressDoc construction/destruction
CCompressDoc::CCompressDoc()
{
// TODO: add one-time construction code here
}
CCompressDoc::~CCompressDoc()
{
}
BOOL CCompressDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
// TODO: add reinitialization code here
// (SDI documents will reuse this document)
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CCompressDoc serialization
void CCompressDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
// TODO: add storing code here
}
else
{
// TODO: add loading code here
}
}
/////////////////////////////////////////////////////////////////////////////
// CCompressDoc diagnostics
#ifdef _DEBUG
void CCompressDoc::AssertValid() const
{
CDocument::AssertValid();
}
void CCompressDoc::Dump(CDumpContext& dc) const
{
CDocument::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CCompressDoc commands
主函数(3)CompressView.cpp
// CompressView.cpp : implementation of the CCompressView class
//
#include "stdafx.h"
#include "Compress.h"
#include "CompressDoc.h"
#include "CompressView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CCompressView
IMPLEMENT_DYNCREATE(CCompressView, CView)
BEGIN_MESSAGE_MAP(CCompressView, CView)
//{{AFX_MSG_MAP(CCompressView)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CCompressView construction/destruction
CCompressView::CCompressView()
{
// TODO: add construction code here
}
CCompressView::~CCompressView()
{
}
BOOL CCompressView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return CView::PreCreateWindow(cs);
}
/////////////////////////////////////////////////////////////////////////////
// CCompressView drawing
void CCompressView::OnDraw(CDC* pDC)
{
CCompressDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
CPen Pen,*ptrPen;
Pen.CreatePen(PS_COSMETIC,1,RGB(255,0,0));
pDC->SetBkColor(RGB(255,255,255));
ptrPen=pDC->SelectObject(&Pen);
pDC->SetTextColor(RGB(255,0,0));
int x0=10,y0=10,detaY=20;
pDC->TextOut(x0,y0,"专业:电子信息工程");
pDC->TextOut(x0,y0+detaY*1,"姓名:蒋伟 ");
pDC->TextOut(x0,y0+detaY*2,"学号:0240302314");
pDC->TextOut(x0,y0+detaY*3,"Email: kof2003@126.com");
pDC->SelectObject(ptrPen);
}
/////////////////////////////////////////////////////////////////////////////
// CCompressView printing
BOOL CCompressView::OnPreparePrinting(CPrintInfo* pInfo)
{
// default preparation
return DoPreparePrinting(pInfo);
}
void CCompressView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add extra initialization before printing
}
void CCompressView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add cleanup after printing
}
/////////////////////////////////////////////////////////////////////////////
// CCompressView diagnostics
#ifdef _DEBUG
void CCompressView::AssertValid() const
{
CView::AssertValid();
}
void CCompressView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
CCompressDoc* CCompressView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CCompressDoc)));
return (CCompressDoc*)m_pDocument;
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CCompressView message handlers
主函数(4) DlgRLEBmp.cpp
// DlgRLEBmp.cpp : implementation file
//
#include "stdafx.h"
#include "Compress.h"
#include "DlgRLEBmp.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
struct CompressNode{
int val;
CompressNode *next;
};
const int PANES_Row=12;
const int PANES_Col=14;
const int PANE_Height=12;
const int PANE_Width=12;
const COLORREF PANES_BkColor=RGB(255,255,255);//RGB(0xd4,0xd0,0xc8);
const COLORREF PANES_BorderColor=RGB(0x0,0x4d,0x99);
const COLORREF PANE_FillColor=RGB(0,125,0);//RGB(0,0,0);
const COLORREF PANE_NullColor=PANES_BkColor;//RGB(255,255,0);
const int PANES_x10=60;
const int PANES_y10=40;
const int PANES_x11=PANES_x10+PANE_Width*PANES_Col;
const int PANES_y11=PANES_y10+PANE_Height*PANES_Row;
const int PANES_x20=PANES_x11+PANE_Width*9;
const int PANES_y20=PANES_y10;
const int PANES_x21=PANES_x20+PANE_Width*PANES_Col;
const int PANES_y21=PANES_y20+PANE_Height*PANES_Row;
int Original[PANES_Row*PANES_Col];
struct CompressNode *pCompress=new CompressNode;
int Uncompress[PANES_Row*PANES_Col];
/////////////////////////////////////////////////////////////////////////////
// CDlgRLEBmp dialog
CDlgRLEBmp::CDlgRLEBmp(CWnd* pParent /*=NULL*/)
: CDialog(CDlgRLEBmp::IDD, pParent)
{
//{{AFX_DATA_INIT(CDlgRLEBmp)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
}
void CDlgRLEBmp::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CDlgRLEBmp)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CDlgRLEBmp, CDialog)
//{{AFX_MSG_MAP(CDlgRLEBmp)
ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
ON_WM_PAINT()
ON_BN_CLICKED(IDC_BUTTON_Clear, OnBUTTONClear)
ON_BN_CLICKED(IDC_BUTTON_Compress, OnBUTTONCompress)
ON_BN_CLICKED(IDC_BUTTON_Uncompress, OnBUTTONUncompress)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CDlgRLEBmp message handlers
BOOL CDlgRLEBmp::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
pTable1=new CPanes(this,PANES_x10,PANES_y10,PANES_Row,PANES_Col,PANE_Height,PANE_Width,RGB(0,0,0),RGB(0,150,0),RGB(0,230,0),RGB(0,0,0),1,"绘制图像");
pTable2=new CPanes(this,PANES_x20,PANES_y20,PANES_Row,PANES_Col,PANE_Height,PANE_Width,RGB(0,0,0),RGB(0,150,0),RGB(0,230,0),RGB(0,0,0),1,"还原图像");
pTable1->Clear();
pTable2->Clear();
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void CDlgRLEBmp::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
pTable1->DoLButtonDown(point);
pTable2->DoLButtonDown(point);
CDialog::OnLButtonDown(nFlags, point);
}
void CDlgRLEBmp::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
pTable1->DoMouseMove(point);
pTable2->DoMouseMove(point);
CDialog::OnMouseMove(nFlags, point);
}
void CDlgRLEBmp::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
pTable1->DoLButtonUp(point);
pTable2->DoLButtonUp(point);
CDialog::OnLButtonUp(nFlags, point);
}
void CDlgRLEBmp::OnPaint()
{
CPaintDC dc(this); // device context for painting
pTable1->Draw();
pTable2->Draw();
// TODO: Add your message handler code here
// Do not call CDialog::OnPaint() for painting messages
}
void CDlgRLEBmp::OnBUTTONClear()
{
// TODO: Add your control notification handler code here
pTable1->Clear();
pTable2->Clear();
}
void CDlgRLEBmp::OnBUTTONCompress()
{
// TODO: Add your control notification handler code here
/*
int Original[PANES_Row][PANES_Col];
struct CompressNode *pCompress;
int Uncompress[PANES_Row][PANES_Col];
*/
pTable1->Get(Original);
int iNum;
CString s;
struct CompressNode *pPre,*pNext;
pPre=pCompress; pPre->next=NULL;
/**********************************************************
对于二值矩阵Original的每一行{
重复计数iNum赋值为1;
对于该行的第一列~倒数第二列中的每一列{
如果当前列的值=下一列的值{
重复计数iNum加一;
如果当前列是倒数第二列{
如果当前列的值=1,将iNum写入压缩数据链pCompress,否则将-iNum写入压缩数据链pCompress;
}
}
否则{ //如果当前列的值不等于下一列的值
如果当前列的值=1,将iNum写入压缩数据链pCompress,否则将-iNum写入压缩数据链pCompress;
置重复计数iNum为1;
如果当前列是倒数第二列{
如果下一列的值=1,将+1写入压缩数据链pCompress,否则将-1写入压缩数据链pCompress;
}
}
}
}
**********************************************************/
//对于二值矩阵Original的每一行{
for(int i=0; i<PANES_Row; i++){
//重复计数iNum赋值为1;
iNum=1;
//对于该行的第一列~倒数第二列中的每一列{
for(int j=0; j< (PANES_Col-1); j++){
//如果当前列的值=下一列的值{
if( Original[PANES_Col*i+j]==Original[PANES_Col*i+j+1] ){
//重复计数iNum加一;
iNum++;
//如果当前列是倒数第二列{
if( j==(PANES_Col-2) ){
pNext=new CompressNode;
//如果当前列的值=1,将iNum写入压缩数据链pCompress,否则将-iNum写入压缩数据链pCompress;
pNext->val=(Original[PANES_Col*i+j]==1)? iNum:(-iNum);
pNext->next=NULL;
pPre->next=pNext;
pPre=pNext;
iNum=1;
}
}
//否则{ //如果当前列的值不等于下一列的值
else{
pNext=new CompressNode;
//如果当前列的值=1,将iNum写入压缩数据链pCompress,否则将-iNum写入压缩数据链pCompress;
pNext->val=(Original[PANES_Col*i+j]==1)? iNum:(-iNum);
pNext->next=NULL;
pPre->next=pNext;
pPre=pNext;
//置重复计数iNum为1;
iNum=1;
//如果当前列是倒数第二列{
if( j==(PANES_Col-2) ){
pNext=new CompressNode;
//如果下一列的值=1,将+1写入压缩数据链pCompress,否则将-1写入压缩数据链pCompress;
pNext->val=(Original[PANES_Col*i+j+1]==1)? 1:(-1);
pNext->next=NULL;
pPre->next=pNext;
pPre=pNext;
iNum=1;
//}
}
//}
}
//}
}
//}
}
//显示压缩结果,激活解压按钮
pPre=pCompress->next;
CString csCompress="",cs;
int iSum=0;
while(pPre!=NULL){
cs.Format("%6d",pPre->val);
csCompress+=cs;
if(pPre->val>0)
iSum+=pPre->val;
else
iSum-=pPre->val;
if(iSum%PANES_Col==0)
csCompress+="/r/n";
pPre=pPre->next;
}
this->SetDlgItemText(IDC_EDIT_Compress,csCompress);
CButton *pBtn;
pBtn=(CButton*)GetDlgItem(IDC_BUTTON_Uncompress);
pBtn->EnableWindow(TRUE);
}
void CDlgRLEBmp::OnBUTTONUncompress()
{
// TODO: Add your control notification handler code here
struct CompressNode *p;
p=pCompress->next;
int k=0;
/***************************************************
如果解压的结果数组Uncompress没有填满{
如果压缩数据链pCompress上的数据已处理完,结束解压;
从压缩数据链上取一个数据;
如果数据值val>0,则向解压结果数组Uncompress中写入val个1,否则写入val个0;
准备取下一个数据;
}
***************************************************/
//如果解压的结果数组Uncompress没有填满{
while( k<(PANES_Row*PANES_Col) ){
//如果压缩数据链pCompress上的数据已处理完,结束解压;
if(p==NULL)
break;
//从压缩数据链上取一个数据;如果数据值val>0,则向解压结果数组Uncompress中写入val个1,
if(p->val>0){
for(int i=0; i<p->val; i++)
Uncompress[k++]=1;
}
//否则写入val个-1;
else{
for(int i=0; i<(-p->val); i++)
Uncompress[k++]=-1;
}
//准备取下一个数据;
p=p->next;
}
//显示图像
pTable2->Fill(Uncompress);
/*
struct CompressNode *pPre,*p;
pPre=pCompress->next;
while(pPre!=NULL){
p=pPre;
pPre=pPre->next;
delete p;
}
*/
CButton *pBtn;
pBtn=(CButton*)GetDlgItem(IDC_BUTTON_Uncompress);
pBtn->EnableWindow(FALSE); //bAble为TRUE或FALSE
}
主函数(5)DlgRLEText.cpp
// DlgRLEText.cpp : implementation file
//
#include "stdafx.h"
#include "Compress.h"
#include "DlgRLEText.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
CString Replace(const CString csOriginalWord,const CString csWordDead,const CString csWordLive);
CString Replace(const CString csOriginalWord,const CString csWordDead,const CString csWordLive){
int iDeadLength=csWordDead.GetLength();
int iLiveLength=csWordLive.GetLength();
int iBegin,iStart=0;
CString csResultWord;
csResultWord.Format("%s",csOriginalWord);
while( (iBegin=csResultWord.Find(csWordDead,iStart))>=0 ){
csResultWord.Delete(iBegin,iDeadLength);
csResultWord.Insert(iBegin,csWordLive);
iStart=iBegin+iLiveLength;
}
return csResultWord;
}
/////////////////////////////////////////////////////////////////////////////
// CDlgRLEText dialog
CDlgRLEText::CDlgRLEText(CWnd* pParent /*=NULL*/)
: CDialog(CDlgRLEText::IDD, pParent)
{
//{{AFX_DATA_INIT(CDlgRLEText)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
}
void CDlgRLEText::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CDlgRLEText)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CDlgRLEText, CDialog)
//{{AFX_MSG_MAP(CDlgRLEText)
ON_BN_CLICKED(IDC_BUTTON_Compress, OnBUTTONCompress)
ON_BN_CLICKED(IDC_BUTTON_Uncompress, OnBUTTONUncompress)
ON_BN_CLICKED(IDC_BUTTON_Compress2, OnBUTTONCompress2)
ON_EN_CHANGE(IDC_EDIT_Original, OnChangeEDITOriginal)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CDlgRLEText message handlers
BOOL CDlgRLEText::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
this->SetDlgItemText(IDC_EDIT_Original,"1/r/n22/r/n333/r/n4444/r/n55555/r/n666666AAAAAAA Wish you a good luck! IIIIIIII");
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void CDlgRLEText::OnBUTTONCompress()
{
// TODO: Add your control notification handler code here
/*************************************************************
//【获取原文本】
//【压缩文本】
//初始化计数变量
//如果文本没有结束{
//读取当前字符
//如果当前字符是第一个字符,将比较字符设为当前字符,continue
//如果当前字符等于比较字符,重复次数加一,continue
//如果重复次数小于3,将比较字符写入压缩流:R+1次; 重复次数置零,将比较字符设为当前字符,continue
//将重复字符,以三字节格式写入压缩流;重复次数置零,将比较字符设为当前字符,continue
//}
//【设置压缩文本,激活解压按钮】
**************************************************************/
//【获取原文本】
CString sOriginalText,s;
this->GetDlgItemText(IDC_EDIT_Original,sOriginalText);
strcpy( m_cOriginalText,(LPSTR)(LPCTSTR)sOriginalText );
//【压缩文本】
//初始化计数变量
int R=0; //重复字符数
int C=0; //已读字符数
int CC=0;
char CH; //当前字符
char SH; //比较字符
//如果文本没有结束{
do{
s.Format("%c",m_cOriginalText[C]);
//::AfxMessageBox(s);
//读取当前字符
CH=m_cOriginalText[C];
C++;
//如果当前字符是第一个字符,将比较字符设为当前字符,continue
if (C==1){
SH=CH;
continue;
}
//如果当前字符等于比较字符,重复次数加一,continue
if (CH==SH){
R++;
continue;
}
//如果重复次数小于3,将比较字符写入压缩流:R+1次; 重复次数置零,将比较字符设为当前字符,continue
if (R<3){
for(int i=0; i<=R; i++){
m_cCompressText[CC]=SH;
CC++;
}
R=0;
SH=CH;
continue;
}
//将重复字符,以三字节格式写入压缩流;重复次数置零,将比较字符设为当前字符,continue
m_cCompressText[CC++]='@';
char cNum=(char)(R+1);
m_cCompressText[CC++]=cNum;
m_cCompressText[CC++]=SH;
R=0;
SH=CH;
//}
} while( CH!='/0' );
C--;
m_cCompressText[CC]='/0';
s.Format(" 原字符数=%d/n 压缩字符数=%d/n 压缩比=%f",C,CC,(C+0.0)/CC);
::AfxMessageBox(s);
//【设置压缩文本,激活解压按钮】
this->SetDlgItemText(IDC_EDIT_Compress,CString(this->m_cCompressText));
CButton *pBtn;
pBtn=(CButton*)GetDlgItem(IDC_BUTTON_Uncompress);
pBtn->EnableWindow(TRUE); //bAble为TRUE或FALSE
pBtn=(CButton*)GetDlgItem(IDC_BUTTON_Compress2);
pBtn->EnableWindow(TRUE); //bAble为TRUE或FALSE
}
void CDlgRLEText::OnBUTTONCompress2()
{
// TODO: Add your control notification handler code here
//将压缩文本中的@后的一字节计数用数字串替换
int iAt,iStart=0;
char cNum;
CString csCompressText,csNum;
csCompressText.Format("%s",m_cCompressText);
while( (iAt=csCompressText.Find('@',iStart))>=0 ){
cNum=csCompressText.GetAt(iAt+1);
csNum.Format("[%d]",int(cNum));
csCompressText.Delete(iAt+1);
csCompressText.Insert(iAt+1,csNum);
iStart=iAt+1;
}
//csCompressText=Replace(csCompressText,"@","@#$@");
this->SetDlgItemText(IDC_EDIT_Compress,csCompressText);
}
void CDlgRLEText::OnChangeEDITOriginal()
{
// TODO: If this is a RICHEDIT control, the control will not
// send this notification unless you override the CDialog::OnInitDialog()
// function and call CRichEditCtrl().SetEventMask()
// with the ENM_CHANGE flag ORed into the mask.
// TODO: Add your control notification handler code here
CButton *pBtn;
pBtn=(CButton*)GetDlgItem(IDC_BUTTON_Compress2);
pBtn->EnableWindow(FALSE); //bAble为TRUE或FALSE
pBtn=(CButton*)GetDlgItem(IDC_BUTTON_Uncompress);
pBtn->EnableWindow(FALSE); //bAble为TRUE或FALSE
}
void CDlgRLEText::OnBUTTONUncompress()
{
// TODO: Add your control notification handler code here
/*****************************************************************
如果压缩文本中还有字符{
读取当前字符;
如果当前字符等于'@',读取重复字符RC以及计数N,将重复字符写入解压流:N次,continue;
将当前字符写入解压流;
}
*****************************************************************/
int iC=0/*压缩文本字符计数*/,iU=0/*解压结果文本字符计数*/;
int iNum/*重复次数*/;
char cCur/*当前字符*/,cR/*重复字符*/;
//如果压缩文本中还有字符{
while( m_cCompressText[iC]!='/0' ){
//读取当前字符;
cCur=m_cCompressText[iC];
iC++;
//如果当前字符等于'@',读取重复字符cR以及计数iNum,将重复字符写入解压流:iNum次,continue;
if (cCur=='@'){
cR=m_cCompressText[iC+1];
iNum=(int)m_cCompressText[iC];
for(int i=0; i<iNum; i++){
m_cUncompressText[iU++]=cR;
}
iC+=2;
continue;
}
//将当前字符写入解压流;
m_cUncompressText[iU++]=cCur;
//}
}
m_cUncompressText[iU]='/0';
this->SetDlgItemText(IDC_EDIT_Uncompress,CString(this->m_cUncompressText));
}
主函数 (6) MainFrm.cpp
// MainFrm.cpp : implementation of the CMainFrame class
//
#include "stdafx.h"
#include "Compress.h"
#include "MainFrm.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//=================================================
#include "DlgRLEText.h"
#include "DlgRLEBmp.h"
/////////////////////////////////////////////////////////////////////////////
// CMainFrame
IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
ON_WM_CREATE()
ON_COMMAND(ID_MENUITEM_RLEText, OnMENUITEMRLEText)
ON_COMMAND(ID_MENUITEM_RLEBmp, OnMENUITEMRLEBmp)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
static UINT indicators[] =
{
ID_SEPARATOR, // status line indicator
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};
/////////////////////////////////////////////////////////////////////////////
// CMainFrame construction/destruction
CMainFrame::CMainFrame()
{
// TODO: add member initialization code here
}
CMainFrame::~CMainFrame()
{
}
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("Failed to create toolbar/n");
return -1; // fail to create
}
if (!m_wndStatusBar.Create(this) ||
!m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)))
{
TRACE0("Failed to create status bar/n");
return -1; // fail to create
}
// TODO: Delete these three lines if you don't want the toolbar to
// be dockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
return 0;
}
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CMainFrame diagnostics
#ifdef _DEBUG
void CMainFrame::AssertValid() const
{
CFrameWnd::AssertValid();
}
void CMainFrame::Dump(CDumpContext& dc) const
{
CFrameWnd::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CMainFrame message handlers
void CMainFrame::OnMENUITEMRLEText()
{
// TODO: Add your command handler code here
CDlgRLEText dlg;
dlg.DoModal();
}
void CMainFrame::OnMENUITEMRLEBmp()
{
// TODO: Add your command handler code here
CDlgRLEBmp dlg;
dlg.DoModal();
}
主函数 (7)Panes.cpp
// Panes.cpp: implementation of the CPanes class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
//【】#include "Test.h"
#include "Panes.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CPanes::~CPanes()
{
}
CPanes::CPanes()
{
}
CPanes::CPanes(CDialog *pDlg,int x0, int y0, int row,int col,int height,int width,
COLORREF panesBkColor,COLORREF borderColor,COLORREF paneFillColor,COLORREF paneNullColor,
int ppDistance, CString title
){
this->pDlg=pDlg;
this->x0=x0;
this->y0=y0;
this->row=row;
this->col=col;
this->height=height;
this->width=width;
x1=x0+col*width;
y1=y0+row*height;
this->panesBkColor=panesBkColor;
this->borderColor=borderColor;
this->paneFillColor=paneFillColor;
this->paneNullColor=paneNullColor;
this->ppDistance=ppDistance;
this->title=title;
this->sample="";
int i,j;
table= (int**) calloc(row, sizeof(int*));
for (i=0; i<row; i++) {
table[i]=(int*) calloc(col, sizeof(int));
}
for(i=0; i<row; i++){
for(j=0; j<row; j++){
table[i][j]=-1;
}
}
pDC=pDlg->GetDC();
penBorder.CreatePen(PS_COSMETIC,1,borderColor);
pPen=pDC->SelectObject(&penBorder);
pBrushPanes=new CBrush( panesBkColor );
pBrushPaneFill=new CBrush( paneFillColor );
pBrushPaneNull=new CBrush( paneNullColor );
font.CreatePointFont(1,"宋体");
pFont=pDC->SelectObject(&font);
bDrawing=false;
}
int CPanes::DRAW_SAMPLE=1;
void CPanes::Draw(int drawPart){
if(drawPart==DRAW_SAMPLE){
CFont font,*pFont;
//font.CreatePointFont(1, "宋体");
font.CreateFont( /*int nHeight*/sampleLfheight, /*int nWidth*/sampleLfwidth,
/*int nEscapement*/0, /*int nOrientation*/1, /*int nWeight*/FW_NORMAL,
/*BYTE bItalic*/0, /*BYTE bUnderline*/0, /*BYTE cStrikeOut*/0,
/*BYTE nCharSet*/DEFAULT_CHARSET, /*BYTE nOutPrecision*/700,
/* BYTE nClipPrecision*/100, /*BYTE nQuality*/0 ,
/*BYTE nPitchAndFamily*/DEFAULT_PITCH,
/*LPCTSTR lpszFacename*/sampleFont );
pFont=pDC->SelectObject(&font);
pDC->SetTextColor(sampleColor);
pDC->SetBkColor(sampleBkColor);
pDC->TextOut(sampleX0,sampleY0,sample);
pDC->SelectObject(pFont);
}
int i,j;
pDC->SetBkColor(RGB(0x0,0x4d,0x99));
pDC->SetTextColor(RGB(0xff,0xff,0x00));
//画边框
if(title!="")
pDC->TextOut(x0,y0-17,title);
pDC->FillRect(CRect(x0,y0,x1,y1),pBrushPanes);
//画边界
for(i=0; i<=row; i++){
pDC->MoveTo(x0,y0+i*height);
pDC->LineTo(x1,y0+i*height);
}
for(j=0; j<=col; j++){
pDC->MoveTo(x0+j*width,y0);
pDC->LineTo(x0+j*width,y1);
}
//画掩膜
for(i=0; i<row; i++){
for(j=0; j<col; j++){
if(table[i][j]==1)
pBrush=pBrushPaneFill;
else
pBrush=pBrushPaneNull;
pDC->FillRect(
CRect(x0+j*width+ppDistance,y0+i*height+ppDistance,
x0+(j+1)*width,y0+(i+1)*height),
pBrush);
}
}
}
void CPanes::Draw(int r,int c,int bin){
table[r][c]=bin;
if(table[r][c]==1)
pBrush=pBrushPaneFill;
else
pBrush=pBrushPaneNull;
pDC->FillRect(
CRect(x0+c*width+ppDistance,y0+r*height+ppDistance,
x0+(c+1)*width,y0+(r+1)*height),
pBrush);
}
void CPanes::DoLButtonDown(CPoint point){
if(point.x<x0 || point.x>=x1 || point.y<y0 || point.y>=y1){
return;
}
bDrawing=true;
int r,c;
r=(point.y-y0)/height;
c=(point.x-x0)/width;
if(table[r][c]==1)
return;
table[r][c]=1;
pDC->FillRect(
CRect(x0+c*width+ppDistance,y0+r*height+ppDistance,
x0+(c+1)*width,y0+(r+1)*height),
pBrushPaneFill);
}
void CPanes::DoMouseMove(CPoint point){
if(point.x<x0 || point.x>=x1 || point.y<y0 || point.y>=y1){
bDrawing=false;
}
if(!bDrawing)
return;
int r,c;
r=(point.y-y0)/height;
c=(point.x-x0)/width;
if(table[r][c]==1)
return;
table[r][c]=1;
pDC->FillRect(
CRect(x0+c*width+ppDistance,y0+r*height+ppDistance,
x0+(c+1)*width,y0+(r+1)*height),
pBrushPaneFill);
}
void CPanes::DoLButtonUp(CPoint point){
bDrawing=false;
}
void CPanes::Clear(){
int i,j;
for(i=0; i<row; i++){
for(j=0; j<col; j++){
table[i][j]=-1;
}
}
Draw();
}
void CPanes::ToFile(CString fileName, CString sBlank){
int i,j;
CString sBin,s;
s.Format("%d行×%d列/n",row,col);
sBin+=s;
for(i=0; i<row; i++){
for(j=0; j<col; j++){
s.Format("%d,/t",table[i][j]);
sBin+=s;
}
sBin+="/n";
}
CStdioFile out;
out.Open(fileName, CFile::modeCreate | CFile::modeWrite);
out.WriteString(sBin);
out.Close();
}
void CPanes::Get(int p[]){
int i,j;
for(i=0; i<row; i++){
for(j=0; j<col; j++){
p[i*col+j]=table[i][j];
}
}
}
void CPanes::Get(int **p){
int i,j;
for(i=0; i<row; i++){
for(j=0; j<col; j++){
p[i][j]=table[i][j];
}
}
}
void CPanes::Fill(int p[]){
int i,j;
for(i=0; i<row; i++){
for(j=0; j<col; j++){
table[i][j]=p[i*col+j];
}
}
Draw();
}
void CPanes::Fill(int **p){
int i,j;
for(i=0; i<row; i++){
for(j=0; j<col; j++){
table[i][j]=p[i][j];
}
}
Draw();
}
void CPanes::SetSample( CString sample,
int sampleX0,int sampleY0,
CString sampleFont,
COLORREF sampleBkColor,COLORREF sampleColor){
this->sample=sample;
this->sampleBkColor=sampleBkColor;
this->sampleColor=sampleColor;
this->sampleFont=sampleFont;
this->sampleLfheight=row;
this->sampleLfwidth=9;col;
this->sampleX0=sampleX0;
this->sampleY0=sampleY0;
Draw(DRAW_SAMPLE);
}
void CPanes::GetSample(int x,int y){
int i,j;
samplePixels= (int**) calloc(row, sizeof(int*));
for (i=0; i<row; i++) {
samplePixels[i]=(int*) calloc(col, sizeof(int));
}
for(i=0; i<row; i++){
for(j=0; j<col; j++){
if(pDC->GetPixel(x+j,y+i)==sampleColor){
samplePixels[i][j]=1;
}
else{
samplePixels[i][j]=-1;
}
}
}
}
void CPanes::FillSample(int x,int y){
this->GetSample(x,y);
this->Fill(samplePixels);
}
void CPanes::useFuncPoint(void (*pFunc)()){
if(pFunc==NULL)
::AfxMessageBox("函数的函数参数为空!");
}
主函数 (8) StdAfx.cpp
// stdafx.cpp : source file that includes just the standard includes
// Compress.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
附录2
快速游程长度在简易图像编码算法中的应用
E-mail: {joliver, mperez}@disca.upv.es
摘要:复杂图像编码算法曾提议使用高率失真函数的编码方式,也详细设计过信噪比和解析分辨率和误差纠错。这些算法在设计和计算时的复杂性导致了执行速度的减缓。这篇论文中,我们提供一种全新的小波图象编码方式,它在定义和执行时非常简易,并且表现比以前的算法快很多。尽管非常简易,它的实际执行表明它的压缩比率和失真度都在艺术要求范围内。因此,我们的运算编码法则目前与SPIHT和JASPER(官方联合图象专家组2000)达到同样的信号-噪音功率比。更重要的是,由于SPIHT缺乏交互式,执行时间较长,我们的方案比SPIHT更有发展潜力。
1.介绍
小波图象编码器已证明在最优化率失真时是最好的压缩数据方案。尽管如此,主要的缺点是小波图象编码器[1][2][3]是相当复杂的。那主要是由于压缩位流处理,通过不断的重复,达到了来用于不同的位流的极限。通过这样的方法,很容易达到使用先进的编码的位流,自从更多的比特位图获得更大的信噪比用到图片中。
尽管嵌入式的位流是图象编码器的优点,但它不总是必须的,并且有其他的可选择的特点例如,解析度可测量性可能对最终效果来讲更加有价值。这论文中,我们提供一个非常简易快速的运算法则,它很容易把小波系数编码下来,而且都不需要先把每个位流先循环扫描一遍。相反,从头到尾仅需要一次扫描。
在第2段中,小波编码器将做详细介绍。第3段将会调谐好并评价。第4段将介绍游程长度模式以及在第5段中执行中达到数字化结果。最后,结论将会在第6段。
2.简单小波图象编码器
在先前的运算法则中,量子化进程是由2种策略执行的,一个是简易粗糙的,一个是完美的。较好的一边包括把标量的统一量子化应用到系数中,并且紧随DWT应用后执行。另外一个粗糙的方法是基于去除比特位图中最少的系数的重要部分,它与运算法则应用同时执行。现在我们把RPLANES设为被清除的不太重要的比特信息数量。
在编码器初始化时,最大数量的比特数量(我们设为MAXPLANE)已经被记数。这个MAXPLANE和RPLANES将作为参数送往编码器。然后,我们将初始化一个自适应的算术编码器,它是用来将系数所需要的比特数量编码。然后我们把所有系数编码。因为那些需要的系数比编码RPLANES比特( )需要得更多,我们使用一个算术特征来表明到底编码那个特征多少比特是必须的。仅仅MAXPLANE- RPLANES个记号是必须的来描述信息。尽管如此,一个多余的符号(成为LOWER符号),还是必须用来编码这样的系数,系数是略微小于建立时的极限( )的。请注意当它在抛弃最少的重要RPLANES比特时,还不是0的话,我们称 是一个重要的系数。换言之,即 时.
在下一阶段,小波系数将按如下步骤编码好。对于每个分块,所有的系数都将被仔细扫描。为了保护信息的位置,扫描信息不是逐行进行的,而是取中等大小的码块,一个适合扫描的大小的块,其大小与 分块(在二维分解中最小且最少频率的分块)。对于每个分块的系数,如果它是重要的,一个用来描述系数的比特数量的标志将会被算术编码。在同样大小的分块中将有大小相似量级的系数,并且由于规则,我们也将确立扫描系数。我们的自适应的运算编码能够非常有效率地再次描述出信息内容。尽管如此,我们并没有足够的信息来重新正确地构建系数,所以我们仍需要将重要的比特信号编码。
另一方面,如果一个系数不是重要信息,我们应该将其编为LOWER信号,所以解码器可以肯定它已经被完全量子化,并且因此系数和信号都与信息没有联系。
你会注意到当我们把重要信息编码时,最开头的RPLANES和最重要的比特并没有被编码,通过暗示比特编码时需要多少数量的算法记号,解码器能将最重要的比特解码。另外,为了提高执行速度,重要的比特和信号将原封不动地编码起来,导致了在率失真函数上表现出非常少的信息丢失。
如下编码算术法则,算术法则1:
(E1)INITIALIZATION
Output rplanes
Output maxplane= {
(E2) 输出系数。在每个分块中扫描
Arithmetic_output
Output
Output sign( )
Else
Arithmetic_output LOWER
3.调整提议的运算法则
尽管被提议的运算法则很简易,它的率失真函数表现可以跟艺术编码要求可以媲美。它提供了匹配的调谐参数。在这段,我们将提供运算法则的细节部分,它使得运算法则执行得更有效。为了表现出理想的执行结果,我们选择了一个标准的LENA的照片做为基本的模板。
一个自适应的运算编码器是用来有效地将译码进程输出编码。一个自适应编码器使用一个动态的柱状图来估计目前符号出现的几率。为了提高命中几率,将一个与每时每刻出现符号联系着的频率计数编码。因此,我们引入一个全新的参数,参数是反映柱状图随每个符号的增长趋势,我们把这个参数称为增长因素。在最初始的自适应的运算法则编码器,每个的价值就被用来做参数。如果它比其他的有更高的价值,它的自适应运算编码器将很快地会聚本地图片的特征,导致了更高的压缩比率。尽管如此,增长过高将会把模型扭变得不相称的,导致了执行的错误。另外,参数将用maximum frequency count求得。当它的数值超过了所有的编码器柱状图的总和(这个数值称为cumulative frequency count),所有的数量将被减半,并且超出的部分将被阻止(更多细节在第4段)。最原始的提议参数是16384(当使用16进制时),但是实验结果使得我们稍微降低数值,12500,所以模型里减半了很多。
在实验一中,我们测试了不同的增长因素(例如低,中,高压缩比率2bpp,0.5bpp,0.25bpp,0.125bpp)对信号-噪音功率比的影响。实验结果表明,对于maximum frequency count为最大值12500时,增长因素在200时均达到了最佳效果,并且与原始数据相比得到了0.1~0.3dB的增益。
在前面曾提到,对于同样大小的码块,系数有同样大小的量级。为了达到较好的增益,编码的系数的量级将控制好不同的柱状图,当然它也受其他因素控制。特别地,由于左边和上方系数的重要性(如果扫描命令已经执行,系数就已经编码了),我们提议使用两种不同的前后关系。所以,如果两个系数都不重要,由它导致的编码也将会是不重要的,因此得使用一个特殊的模型。
使用这样的特殊模型的好处在图1中表现出来了,当信号-噪音功率是由两种因素引起,将会达到0.2dB的增益。另外,在图中我们可以看到我们的编码器在按照率失真函数里达到了艺术要求,与其他几个编码方式,达到了相似的信号-噪音功率比。
编码器速率 | 提议的算法 | CTXT编码 | JPEG2000 | SPIHT |
2 1 0.5 0.25 0.125 | 45.30 40.24 36.95 33.79 30.79 | 45.30 40.32 37.13 34.02 30.97 | 44.62 40.31 37.22 34.04 30.84 | 45.07 40.41 37.21 34.11 31.10 |
不同压缩比率和编码方式处理LENA照片时的信号-噪音功率比
尽管我们算法执行比SPIHT和Jasper快很多,它呈现出一个主要的劣势在低比特图片。如果我们分析先前的部分,我们会发现所有记号都明白地编码了,高 长记号是算术上的编码。众所周之,自适应编码器是图片编码系统的最慢的部分。在我们算术法则上,实验上的结果表明对于低比特速率,超过75%的部分花费了大部分在算术编码系统上。另外大部分的被编码的记号已经完全地量子化,并总是用同样的记号编码LOWER。
为了克服这样的问题,并减少这些事情的复杂性,一个新的分组方法来应对LOWER将被在下一段介绍。
4.快速游程长度模式
在这一段,游程模式曾在第2段中先前介绍过。由于容易在高压缩比率信号易出现的大量连续的LOWER符号,这个游程模式在处理到时能降低处理的复杂性。人们对压缩执行时期望较小的提高,是由于我们替代了很多连续的符号,或是比较少出现的暗示了多少LOWER信号的符号。因此,尽管很少数量的符号被编码,离散的几率相反地影响自适应编码器,因为编码器随着压缩比率提高而工作更好。
我们知道在这新的尝试里,仅当LOWER符号数量超过极限数量(称为ENTER_RUN_MODE参数)时,游程长度才将LOWER编码。另外,由于大量数量的游程长度符号代替了同样的短的流信号——LOWER符号,这算法的压缩性能将将会稍微减少。
当游程被更重要的信息打断,并且这个更重要信息的数值足够高(比ENTER_RUN_MODE还要高),这个游程的数值必须输出到解码器,同时游程重新安排。
在这种要求下,一个全新的符号将引进介绍给大家:RUN,它用来反映一个游程即将被编码。在将RUN编码后,RUN的存储方法跟重要数值的存储方法一样。首先,需要将RUN数值编码的比特数量,在算术上输出(使用先后层次关系),然后数据将原封不动的输出。
如下是全新的游程长度编码的算法2:
(E1) INITIALIZATION
Output rplanes
Output maxplane= {
Run_length=0
(E2) 输出系数。在每个分块中扫描
Increase run_length
Else
If run_length 0
If run_length<enter_run_mode
Repeat run_length times
Arithmetic_output LOWER
Else
Arithmetic_output RUN
Rbits=
Arithmetic_output rbits
Output
Arithmetic_output
Output
Output sign( )
5.数字结果
我们已经执行过这样的运算法则来测试它的压缩和复杂性。读者可以在http://www.disca.upv.es/joliver/wavelet/RLW.zip 轻易地在32位机器上测试这样的结果。为了比较我们的算法,使用了标准的lena和barbara的个人照片。所有的结果在如下的表格里表现出来了。
编码器速率 | 游程长度编码 | JPEG2000 | SPIHT |
1 0.5 0.25 0.125 | 36.54 31.66 27.95 25.12 | 37.11 32.14 28.34 25.25 | 36.41 31.39 27.58 24.86 |
不同解码器在处理barbara图片时的信号噪音功率比
编码器速率 | SPIHT | JPEG2000 | CTXT编码 | 游程长度编码 |
2 1 0.5 0.25 0.125 | 210.4 119.4 72.3 48.7 36.8 | 278.5 256.1 238.2 223.4 211.3 | 91.2 64.3 52.7 47.0 44.0 | 95.4 61.2 37.0 25.5 19.7 |
不同编码器编码的执行时间 (百万级别每秒)
编码器速率 | SPIHT | JPEG2000 | CTXT编码 | 游程长度编码 |
2 1 0.5 0.25 0.125 | 217.0 132.7 90.7 69.6 59.7 | 108.8 72.3 51.4 38.1 31.3 | 91.3 70.2 60.3 55.4 53.0 | 93.7 63.0 36.3 24.1 17.8 |
不同编码器解码的执行时间 (百万级别每秒)
6.结论
在这论文中,我们已经描述了一个全新简易的小波游程编码算法。这样的解码器更简单方便。不过尽管复杂性比其他的(如JPEG2000和SPIHT)少很多,游程长度是介绍来减少对低比特数据的处理。这样我们可以看到执行速度于10倍的Jasper,3.5倍的SPIHT。
由于较少的复杂性,需要较少的存储空间,无系统依赖性和高速的编解码能力,我们相信这样的编码方式会成为最真实的交互式多媒体通信最佳选择。
7.参考书目
[1] ISO/IEC 15444-1: “JPEG2000 image coding system,” 2000.
[2] J.M. Shapiro, “Embedded Image Coding Using Zerotrees ofWavelet Coefficients,” IEEE Tr.Signal Proc, vol. 41, Dec. 1993.
[3] A. Said, A. Pearlman. “A new, fast, and efficient imagecodec based on set partitioning in hierarchical trees,” IEEETrans. on circuits and sys. for video tech, vol. 6, nº 3, June 1996.
[4] I.H. Witten, R.M. Neal, J.G. Cleary, “Arithmetic coding forcompression,” Commun. ACM, vol 30. pp. 520-540, 1986.
[5] M. Adams. “Jasper Software Reference Manual (Version1.600.0,” ISO/IEC JTC 1/SC 29/WG 1 N 2415, Oct. 2002.