/*************************************************************************
> File Name: compressor.c
> Author: hepan
> Mail: hepan@xiyoulinux.org
> Created Time: 2016年12月23日 星期五 11时15分00秒
************************************************************************/
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <pthread.h>
#define MAXLEN 256 //文件名最大长度
#define INFINITY 2147483647 //Long的最大值
//long file_len;
//float read_len = 0.0, write_len = 0.0;
long sumlength, FileLength, FileLength1; //记录源文件和压缩文件的长度
float rate, speed; //记录压缩率和速度
double duration; //记录压缩用时
int flag; //判断文件是否压缩解压完成
typedef struct {
unsigned char ch; //记录不同字符在数组中的位置
long weight; //字符出现频率(权值)
long parent, lchild, rchild; //定义哈夫曼树指针变量
char code[MAXLEN]; //定义存储哈夫曼编码的数组
int CodeLength; //编码长度
} HuffNode, HuffmanTree[512];
//将窗体独立成一个结构体
struct widget {
GtkWidget *window;
GtkWidget *window1;
GtkWidget *window2;
GtkWidget *label_tips;
GtkWidget *button_cancel;
GtkWidget *entry;
GtkWidget *entry1;
GtkWidget *entry2;
GtkWidget *pbar;
GtkWidget *text1;
GtkWidget *text2;
GtkWidget *vbox;
GtkWidget *hbox_button;
int timer;
} wgt;
void compressor(); //哈夫曼压缩器图形主界面
void *compress(void *arg); //压缩函数
void *decompress(void *arg); //解压函数
void complete_compress(); //压缩完成,打印压缩信息
void complete_decompress(); //解压完成,打印解压信息
void choose_file1(GtkWidget *widget, gpointer data); //选择压缩文件函数
void file_compress(GtkWidget *widget,gpointer data); //文件压缩窗口
void choose_file2(GtkWidget *widget,gpointer data); //选择解压文件函数
void file_decompress(GtkWidget *widget,gpointer data); //文件解压窗口
void send_file(GtkWidget *widget, gpointer data);
void file_ok_sel(GtkWidget *w, GtkFileSelection *fs);
void gtk_dialog_destroy(GtkWidget *widget, gpointer data); //窗口销毁函数
void my_err(const char *err_string, int line); //错误处理函数
int my_itoa(int val, char* buf, int r); //整型值转r进制字符串函数
void Select(HuffmanTree ht, int pos, int *s1, int *s2); //建立哈弗曼树中用于选择最小和次小权值结点的函数
void hfmcoding(HuffmanTree ht,int n); //哈夫曼编码函数
gboolean update_progress_bar_compress(gpointer data); //压缩进度条更新函数
gboolean update_progress_bar_decompress(gpointer data); //解压缩进度条更新函数
gint progress_timeout(gpointer data); //进度条循环函数
void destroy_progress(GtkWidget *widget, struct widget *pdata); // 清除分配的内存,删除定时器(timer)
GtkTextBuffer *text_buffer; //文本框缓冲区
char pathname[MAXLEN]; //保存文件的绝对路径名
//建立哈弗曼树中用于选择最小和次小权值结点的函数
void Select(HuffmanTree ht, int pos, int *s1, int *s2)
{
//m1存放最小权值,m2存放次小权值
//s1存放m1在数组中的下标,s2存放m2在数组中的下标
int i, j;
long m1, m2;
m1 = m2 = INFINITY;
for (j=0; j <= pos; j++) {
if (ht[j].weight < m1 && ht[j].parent == -1) {
m2 = m1;
*s2 = *s1;
*s1 = j;
m1 = ht[j].weight;
} else if (ht[j].weight < m2 && ht[j].parent == -1) {
m2 = ht[j].weight;
*s2 = j;
}
}
//使 s1 小于 s2
if (*s1 > *s2) {
i = *s1;
*s1 = *s2;
*s2 = i;
}
}
//哈弗曼编码函数
void hfmcoding(HuffmanTree ht, int n)
{
//从叶子向根求每个字符的哈弗曼编码
int start;
int i, f, c;
char codes[MAXLEN];
codes[n-1] = '\0'; //编码结束符
for (i=0; i<n; i++) {
//逐个字符求哈弗曼编码
start = n - 1;
for (c=i,f=ht[i].parent; f != -1; c=f,f=ht[f].parent) {
start--;
if (ht[f].lchild == c) {
codes[start] = '0';
} else {
codes[start] = '1';
}
}
strcpy(ht[i].code,&codes[start]);
ht[i].CodeLength = strlen(ht[i].code);
}
}
//压缩函数
void *compress(void *arg)
{
int i, j;
FILE *ifp, *ofp;
HuffmanTree ht;
unsigned char c;
int n, m; //叶子数和结点数
int s1, s2; //权值最小的两个结点的标号
char buf[MAXLEN], name[MAXLEN];
char codes[MAXLEN];
long filelength = 0;
int count = 0;
clock_t start1, start2, finish1, finish2;
double duration1, duration2;
ifp = fopen(pathname,"rb");
if (ifp == NULL) {
my_err("fopen",__LINE__);
}
bzero(buf,sizeof(buf));
bzero(name,sizeof(name));
for (i=0,j=0; i < strlen(pathname); i++) {
if (pathname[i] == '/') {
j = 0;
continue;
}
name[j++] = pathname[i];
}
name[j] = '\0';
for (i=0; i<strlen(name); i++) {
if (name[i] == '.') {
break;
}
}
strncpy(buf, name, i);
//printf("\n-->%s",buf);
ofp = fopen(strcat(buf,".code"),"wb");
if (ofp==NULL) {
my_err("fopen",__LINE__);
}
start1 = clock() ; //开始计时1
FileLength = 0;
while (!feof(ifp)) {
fread(&c,1,1,ifp);
ht[c].weight++;
FileLength++;
//printf("字符 %c : %ld 个; ", c, ht[c].weight);
}
FileLength--;
ht[c].weight--;
//再将ASCII转换为字符存入到结点的ch成员里,同时给双亲、孩子赋初值-1
n = 0;
for (i=0; i<256; i++) {
if (ht[i].weight != 0) {
//printf("\n****<>****%ld",ht[i].weight);
ht[i].ch = (unsigned char)i;
n++; //叶子数
ht[i].lchild = -1;
ht[i].rchild = -1;
ht[i].parent = -1;
}
}
m = 2 * n - 1; //哈弗曼树结点总数
j = 0;
for (i=0; i<256; i++) {
//去掉权值为0的结点
if (ht[i].weight != 0) {
ht[j] = ht[i];
j++;
}
}
for (i=n; i<m; i++) {
//初始化根结点
ht[i].lchild = -1;
ht[i].rchild = -1;
ht[i].parent = -1;
}
//建立哈弗曼树
for (i=n; i<m; i++) {
Select(ht,i-1,&s1,&s2);
ht[i].lchild = s1;
ht[i].rchild = s2;
ht[s1].parent = i;
ht[s2].parent = i;
ht[i].weight = ht[s1].weight + ht[s2].weight;
//printf("\n---->s1 = %d, \ts2 = %d", s1, s2);
//printf("\n****>w1 = %ld, \tw2 = %ld, \tsum = %ld", ht[s1].weight, ht[s2].weight, ht[i].weight);
}
hfmcoding(ht,n);
finish1 = clock();
duration1 = (double)(finish1 - start1) / CLOCKS_PER_SEC;
// printf( "哈弗曼树编码用时为:%f seconds\n", duration1 );
// printf("叶子数为%d,结点数为%d\n",n,m);
// for(i=0;i<n;i++) {
// printf("%d号叶子结点的权值为:%ld,双亲为:%d,左右孩子:%d,编码为:%s\n",
// i,ht[i].weight,ht[i].parent,ht[i].lchild,ht[i].code);
// }
start2 = clock() ; //开始计时2
fseek(ifp,0,SEEK_SET); //将ifp指针移到文件开头位置
fwrite(&FileLength,4,1,ofp); //将FileLength写入目标文件的前4个字节的位置
fseek(ofp,8,SEEK_SET); //再将目标文件指针ofp移到距文件开头8个字节位置
codes[0] = 0;
//将编码信息写入目标文件
while (!feof(ifp)) {
//fread(&c,1,1,ifp);
c = fgetc(ifp);
filelength++;
for (i=0; i<n; i++) {
if (c == ht[i].ch) {
break;
}
}
strcat(codes,ht[i].code);
c = 0;
while (strlen(codes) >= 8) {
//printf("\nbefore : c = %d", c);
//printf("\ncodes: >>%s",codes);
for (i=0; i<8; i++) {
//将codes的前8位01代码表示的字符存入c
//printf("\n------->%c",codes[i]);
if (codes[i] == '1') {
c = (c << 1) | 1;
//printf("\n<?*?>%d",c);
} else {
c = c << 1;
//printf("\n<?-^-?>%d",c);
}
}
//printf("\nafter: c = %d",c);
fwrite(&c,1,1,ofp); //将新的字符写入目标文件
sumlength++;
strcpy(codes,codes+8); //更新codes的值
}
if (filelength == FileLength) {
break;
}
}
//再将剩余的不足8位的01代码补全8位,继续写入
if (strlen(codes) > 0) {
strcat(codes,"00000000");
for (i=0; i<8; i++) {
if (codes[i] == '1') {
c = (c << 1) | 1;
} else {
c = c << 1;
}
}
fwrite(&c,1,1,ofp);
sumlength++;
}
sumlength += 8;
//printf("编码区总长为:%ld个字节\n",sumlength-8);
//将sumlength和n的值写入目标文件,为的是方便解压
fseek(ofp,4,SEEK_SET);
fwrite(&sumlength,4,1,ofp); //把sumlength写进目标文件的第5-8个字节里
fseek(ofp,sumlength,SEEK_SET);
fwrite(&n,4,1,ofp); //把叶子数n写进编码段后面的4个字节的位置
//存储方式为:n*(字符值(1个字节)+该字符的01编码的位数(1个字节)+编码(字节数不确定,用count来计算总值))
for (i=0; i<n; i++) {
fwrite(&(ht[i].ch),1,1,ofp);
c = ht[i].CodeLength; //编码最长为MAXLEN位,因此只需用一个字节存储
//printf("\n---->%d",c);
//printf("\n---->%s",ht[i].code);
fwrite(&c,1,1,ofp);
//写入字符的编码
if (ht[i].CodeLength % 8 != 0) {
for (j = ht[i].CodeLength % 8; j < 8; j++) {
//把编码不足8位的在低位补0,赋值给C,再把C写入
strcat(ht[i].code,"0");
}
}
while (ht[i].code[0] != 0) {
//开始存入编码,每8位二进制数存入一个字节
c = 0;
for (j=0; j<8; j++) {
if (ht[i].code[j] == '1') {
c = (c << 1) | 1;
} else {
c = c << 1;
}
}
//printf("\n***>%s",ht[i].code);
strcpy(ht[i].code,ht[i].code+8); //编码前移8位,继续存入编码
//printf("\n--->%s",ht[i].code);
count++; //编码占的字节数的总值
//printf("\n---->%d",count);
fwrite(&c,1,1,ofp);
}
}
sumlength = sumlength + 4 + n * 2 + count; //计算压缩后文件的长度
//printf("\nafter compress: %ld Byte\n", sumlength);
finish2 = clock();
duration2 = (double)(finish2- start2) / CLOCKS_PER_SEC;
duration = duration1 + duration2;
/*printf( "写入目标文件用时为:%f seconds\n", duration2);*/
//printf( "压缩用时为:%f seconds\n", duration1+duration2);
speed = (float)FileLength/(duration1+duration2)/1000;
//printf("\n压缩速率为:%5.4f KB/S\n",speed);
//printf("源文件长度为:%ld Byte\n",FileLength);
rate = (float)sumlength / (float)FileLength;
//printf("压缩率(百分比)为:%4.2f%%\n",rate*100);
flag = 1;
complete_compress();
fclose(ifp);
fclose(ofp);
pthread_exit(0);
}
//整型值转r进制字符串函数
int my_itoa(int val, char* buf, int r)
{
const unsigned int radix = r;
char* p;
unsigned int a; //every digit
int len;
char* b; //start of the digit char
char temp;
unsigned int u;
p = buf;
if (val < 0) {
*p++ = '-';
val = 0 - val;
}
u = (unsigned int)val;
b = p;
do {
a = u % radix;
u /= radix;
*p++ = a + '0';
} while (u > 0);
len = (int)(p - buf);
*p-- = 0;
//swap
do {
temp = *p;
*p = *b;
*b = temp;
--p;
++b;
} while (b < p);
return len;
}
//解压缩
void *decompress(void *arg)
{
HuffmanTree ht;
clock_t start, finish;
FILE *ifp, *ofp;
long filelength;
int n, m;
int i, j, k;
char buf[MAXLEN], codes[MAXLEN];
char buffer[MAXLEN], name[MAXLEN];
unsigned char c;
int maxlength;
ifp = fopen(pathname,"rb");
if (ifp == NULL) {
my_err("fopen",__LINE__);
}
bzero(buf,sizeof(buffer));
bzero(name,sizeof(name));
for (i=0,j=0; i < strlen(pathname); i++) {
if (pathname[i] == '/') {
j = 0;
continue;
}
name[j++] = pathname[i];
}
name[j] = '\0';
for (i=0; i<strlen(name); i++) {
if (name[i] == '.') {
break;
}
}
strncpy(buffer, name, i);
ofp = fopen(strcat(buffer,".decode"),"wb");
if (ofp==NULL) {
my_err("fopen",__LINE__);
}
start = clock() ; //开始计时
fread(&FileLength,4,1,ifp); //从压缩文件读出FileLength、sumlength
//printf("\n源文件为 %ld Byte",FileLength);
fread(&sumlength,4,1,ifp);
//printf("\n压缩文件为 %ld Byte",sumlength);
fseek(ifp,sumlength,SEEK_SET); //利用sumlength读出n的值
fread(&n,4,1,ifp);
//printf("\n解码信息:源文件长度为%d个字节,字符种类n=%d\n",FileLength,n);
for (i=0; i<n; i++) {
//读结点信息
fread(&ht[i].ch,1,1,ifp); //字符
//printf("\n***>%d",ht[i].ch);
fread(&c,1,1,ifp); //编码长度
//printf("\n--->%d",c);
ht[i].CodeLength = c;
ht[i].code[0] = 0;
if (ht[i].CodeLength % 8 > 0) {
m = ht[i].CodeLength / 8 + 1; //m为编码占的字节数
} else {
m = ht[i].CodeLength / 8;
}
for (j=0; j<m; j++) {
//根据字节长度m读出编码
fread(&c,1,1,ifp); //此处c为01编码转换成的字符
my_itoa(c,buf,2); //字符型编码转换成二进制型(首位为1)
//如果编码不够8位,则说明缺少了8-k位0,因此应先在前面空缺位写0
for (k=8; k>strlen(buf); k--) {
strcat(ht[i].code,"0");
}
//再把二进制编码存进ht.code中
strcat(ht[i].code,buf);
//printf("\n----->%s",ht[i].code);
}
ht[i].code[ht[i].CodeLength] = 0; //去掉编码中多余的0
}
//找出编码长度的最大值
maxlength = 0;
for (i=0; i<n; i++) {
if (ht[i].CodeLength > maxlength) {
maxlength = ht[i].CodeLength;
}
}
//开始写入目标文件
fseek(ifp,8,SEEK_SET); //指针指向编码区,开始解码
filelength = 0;
codes[0] = 0;
buf[0] = 0;
while (1) {
//codes小于编码长度的最大值时,继续读码
while (strlen(codes) < maxlength) {
fread(&c,1,1,ifp);
//printf("\n----->%d",c);
my_itoa(c,buf,2); //还原编码
for (k=8; k>strlen(buf); k--) {
strcat(codes,"0"); //把缺掉的0补上
}
strcat(codes,buf); //codes中此时存的为一串01编码
}
for (i=0; i<n; i++) {
//在codes中查找能使其前weight位和ht.code相同的i值,weight即为codelength
if (memcmp(ht[i].code,codes,(unsigned int)ht[i].CodeLength) == 0) {
break;
}
}
strcpy(codes,codes+ht[i].CodeLength); //更新codes的值
c = ht[i].ch;
fwrite(&c,1,1,ofp);
filelength++;
if (filelength == FileLength) {
break; //写入结束
}
}
finish = clock();
duration = (double)(finish - start) / CLOCKS_PER_SEC;
//printf( "\n解压完成,解压用时为:%f seconds\n", duration );
fseek(ifp,0,SEEK_SET);
while (!feof(ifp)) {
fread(&c,1,1,ifp);
FileLength1++;
}
FileLength1--;
speed = (float)FileLength/duration/1000;
//printf("此文件长度为:%ld Byte\n",FileLength);
//printf("\n解压速度为:%5.4f KB/S\n",speed);
flag = 1;
complete_decompress();
fclose(ifp);
fclose(ofp);
}
//错误处理函数
void my_err(const char *err_string, int line)
{
fprintf(stderr, "line: %d ",line);
perror(err_string);
exit(1);
}
//窗口销毁函数
void gtk_dialog_destroy(GtkWidget *widget, gpointer data)
{
gtk_widget_destroy((GtkWidget *)data);
}
/*
//压缩进度条更新函数
gboolean update_progress_bar_compress(gpointer data)
{
FILE *fp = NULL;
char buff[8] = {0};
long size = 351920;
unsigned char *pbuff;
GtkProgressBar *pbar = (GtkProgressBar *)data;
if((fp = fopen(pathname,"r")) == NULL) {
my_err("fopen",__LINE__);
}
fseek(fp,0,SEEK_END);
file_len = ftell(fp);
pbuff = (unsigned char *)malloc((size+1)*sizeof(unsigned char));
memset(pbuff,0,size*sizeof(unsigned char));
if(read_len <= file_len) {
fseek(fp,(long int)read_len,SEEK_SET);
fread(pbuff,sizeof(unsigned char),size,fp);
// fwrite(pbuff,size*sizeof(unsigned char),1,fp);
gtk_progress_bar_set_fraction(pbar, read_len / file_len);
sprintf(buff,"%d%s",(int)((read_len / file_len) * 100),"%");
gtk_progress_bar_set_text(GTK_PROGRESS_BAR(pbar),buff);
read_len += size;
return TRUE; //必须返回TRUE;
}
if(read_len > file_len) {
gtk_widget_hide(wgt.window1);
return TRUE;
}
fclose(fp);
free(pbuff);
return TRUE; //必须返回TRUE;
}
//解压缩进度条更新函数
gboolean update_progress_bar_decompress(gpointer data)
{
FILE *fp = NULL;
char buff[8] = {0};
long size = 61097;
unsigned char *pbuff;
GtkProgressBar *pbar = (GtkProgressBar *)data;
if((fp = fopen(pathname,"r")) == NULL) {
my_err("fopen",__LINE__);
}
fseek(fp,0,SEEK_END);
file_len = ftell(fp);
pbuff = (unsigned char *)malloc((size+1)*sizeof(unsigned char));
memset(pbuff,0,size*sizeof(unsigned char));
if(write_len <= file_len) {
fseek(fp,(long int)write_len,SEEK_SET);
fread(pbuff,sizeof(unsigned char),size,fp);
gtk_progress_bar_set_fraction(pbar,write_len/file_len);
sprintf(buff,"%d%s",(int)((write_len/file_len)*100),"%");
gtk_progress_bar_set_text(GTK_PROGRESS_BAR(pbar),buff);
write_len += size;
return TRUE; //必须返回TRUE;
}
if(write_len > file_len) {
gtk_widget_hide(wgt.window1);
return TRUE;
}
complete_compress();
fclose(fp);
free(pbuff);
return TRUE; //必须返回TRUE;
}
*/
//进度条循环函数
gint progress_timeout(gpointer data)
{
struct widget *pdata = (struct widget *)data;
gdouble new_val;
//使用在调整对象中设置的取值范围计算进度条的值
new_val = gtk_progress_bar_get_fraction (GTK_PROGRESS_BAR(pdata->pbar)) + 0.2;
if (new_val > 1.0) {
new_val = 0.0;
}
//设置进度条的新值
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR (pdata->pbar),new_val);
if (flag == 1) {
//gtk_widget_hide(pdata->window1);
destroy_progress(pdata->window1,pdata);
return TRUE;
}
//这是一个timeout函数,返回 TRUE,这样它就能够继续被调用
return TRUE;
}
//清除分配的内存,删除定时器(timer)
void destroy_progress(GtkWidget *widget, struct widget *pdata)
{
gtk_timeout_remove(pdata->timer);
pdata->timer = 0;
pdata->window = NULL;
g_free (pdata);
gtk_widget_hide(pdata->window1);
}
//哈夫曼压缩器图形主界面
void compressor()
{
GtkWidget *window;
GtkWidget *button1;
GtkWidget *button2;
GtkWidget *hbox;
GtkWidget *vbox;
GtkWidget *image;
GdkColor color1;
GdkColor color2;
gdk_color_parse("LawnGreen",&color1);
gdk_color_parse("DarkMagenta",&color2);
gtk_widget_hide(wgt.window);
image = gtk_image_new_from_file("file.jpg");
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 150, 70);
gtk_container_set_border_width(GTK_CONTAINER(window),10);
gtk_window_set_title(GTK_WINDOW(window),"Compress");
gtk_window_set_resizable(GTK_WINDOW(window),TRUE);
hbox = gtk_hbox_new(FALSE,20);
vbox = gtk_vbox_new(FALSE,20);
button1 = gtk_button_new_with_label("压缩");
button2 = gtk_button_new_with_label("解压");
gtk_widget_modify_fg(GTK_BIN(button1)->child,GTK_STATE_PRELIGHT,&color1);
gtk_widget_modify_fg(GTK_BIN(button2)->child,GTK_STATE_PRELIGHT,&color2);
gtk_widget_modify_bg(button1, GTK_STATE_PRELIGHT, &color1);
gtk_widget_modify_bg(button2, GTK_STATE_PRELIGHT, &color2);
gtk_box_pack_start(GTK_BOX(vbox),image,FALSE,FALSE,10);
gtk_box_pack_start(GTK_BOX(hbox),button1,FALSE,FALSE,10);
gtk_box_pack_end(GTK_BOX(hbox),button2,FALSE,FALSE,10);
gtk_container_add(GTK_CONTAINER(vbox),hbox);
gtk_container_add(GTK_CONTAINER(window),vbox);
gtk_widget_show_all(window);
g_signal_connect(GTK_OBJECT(button1),"clicked",GTK_SIGNAL_FUNC(choose_file1),(void *)window);
g_signal_connect(GTK_OBJECT(button2),"clicked",GTK_SIGNAL_FUNC(choose_file2),(void *)window);
g_signal_connect(GTK_OBJECT(window),"delete_event",GTK_SIGNAL_FUNC(gtk_main_quit),NULL);
gtk_widget_show_all(window);
}
//选择压缩文件函数
void choose_file1(GtkWidget *widget, gpointer data)
{
GtkWidget *scroll_box;
GtkWidget *hbox;
GtkWidget *button1;
GtkWidget *button2;
GtkWidget *button3;
GtkWidget *tmp;
GtkWidget *label;
GdkColor color1;
GdkColor color2;
GdkColor color3;
GdkColor color4;
gdk_color_parse("DarkBlue",&color1);
gdk_color_parse("LawnGreen",&color2);
gdk_color_parse("gray",&color3);
gdk_color_parse("red",&color4);
tmp = (GtkWidget *)data;
gtk_widget_hide(tmp);
wgt.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(wgt.window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(wgt.window), 400, 150);
gtk_container_set_border_width(GTK_CONTAINER(wgt.window),10);
gtk_window_set_title(GTK_WINDOW(wgt.window),"文件压缩");
gtk_window_set_resizable(GTK_WINDOW(wgt.window),TRUE);
wgt.vbox = gtk_vbox_new(FALSE,20);
hbox = gtk_hbox_new(FALSE,20);
scroll_box = gtk_scrolled_window_new(NULL,NULL);
wgt.text1 = gtk_text_view_new();
gtk_widget_modify_base(wgt.text1, GTK_STATE_NORMAL, &color3);
gtk_widget_modify_text(wgt.text1, GTK_STATE_NORMAL, &color1);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_box), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_container_add(GTK_CONTAINER(scroll_box), wgt.text1);
gtk_widget_set_size_request(scroll_box,390,50);
button1 = gtk_button_new_with_label("选择文件");
button2 = gtk_button_new_with_label("确认压缩");
button3 = gtk_button_new_with_label("取消压缩");
label = gtk_label_new("待压缩文件位置");
gtk_widget_modify_fg(label,GTK_STATE_NORMAL,&color1);
gtk_widget_modify_fg(GTK_BIN(button1)->child,GTK_STATE_PRELIGHT,&color1);
gtk_widget_modify_fg(GTK_BIN(button2)->child,GTK_STATE_PRELIGHT,&color2);
gtk_widget_modify_fg(GTK_BIN(button3)->child,GTK_STATE_PRELIGHT,&color4);
//gtk_widget_modify_bg(button1, GTK_STATE_PRELIGHT, &color1);
//gtk_widget_modify_bg(button2, GTK_STATE_PRELIGHT, &color2);
//gtk_widget_modify_bg(button3, GTK_STATE_PRELIGHT, &color3);
gtk_box_pack_start(GTK_BOX(wgt.vbox),button1,FALSE,FALSE,10);
gtk_box_pack_start(GTK_BOX(wgt.vbox),label,FALSE,FALSE,10);
gtk_box_pack_start(GTK_BOX(wgt.vbox),scroll_box,FALSE,FALSE,10);
gtk_box_pack_start(GTK_BOX(hbox),button2,FALSE,FALSE,10);
gtk_box_pack_end(GTK_BOX(hbox),button3,FALSE,FALSE,10);
gtk_container_add(GTK_CONTAINER(wgt.window),wgt.vbox);
gtk_container_add(GTK_CONTAINER(wgt.vbox),hbox);
gtk_widget_show_all(wgt.window);
g_signal_connect(GTK_OBJECT(button1),"clicked",GTK_SIGNAL_FUNC(send_file),NULL);
g_signal_connect(GTK_OBJECT(button2),"clicked",GTK_SIGNAL_FUNC(file_compress),NULL);
g_signal_connect(GTK_OBJECT(button3),"clicked",GTK_SIGNAL_FUNC(compressor),(void *)wgt.window);
g_signal_connect(GTK_OBJECT(wgt.window),"delete_event",GTK_SIGNAL_FUNC(compressor),(void *)wgt.window);
}
//文件压缩窗口
void file_compress(GtkWidget *widget,gpointer data)
{
GtkWidget *hbox, *vbox1, *vbox2, *button;
struct widget *pdata;
GdkColor color1;
int status;
pthread_t thid;
gdk_color_parse("red",&color1);
pdata = g_malloc(sizeof(struct widget));
pdata->window1 = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(pdata->window1),GTK_WIN_POS_CENTER);
gtk_window_set_title(GTK_WINDOW(pdata->window1),"Process bar");
gtk_window_set_default_size(GTK_WINDOW(pdata->window1),300,100);
hbox = gtk_hbox_new(FALSE,0);
vbox1 = gtk_vbox_new(FALSE,0);
vbox2 = gtk_vbox_new(FALSE,0);
pdata->pbar = gtk_progress_bar_new();
button = gtk_button_new_with_label("取消");
gtk_widget_set_size_request(button,55,30);
gtk_widget_set_size_request(pdata->pbar,240,30);
gtk_widget_modify_fg(GTK_BIN(button)->child,GTK_STATE_PRELIGHT,&color1);
gtk_box_pack_start(GTK_BOX(vbox1),pdata->pbar,FALSE,FALSE,50);
gtk_box_pack_end(GTK_BOX(vbox2),button,FALSE,FALSE,50);
gtk_box_pack_start(GTK_BOX(hbox),vbox1,FALSE,FALSE,0);
gtk_box_pack_end(GTK_BOX(hbox),vbox2,FALSE,FALSE,5);
gtk_container_add(GTK_CONTAINER(pdata->window1),hbox);
pthread_create(&thid, NULL, compress, NULL);
pdata->timer = g_timeout_add(120,progress_timeout,pdata);
//printf("\n----->%d",pdata->timer);
//pthread_join(thid, (void *)&status);
g_signal_connect(pdata->window1,"destroy",G_CALLBACK(destroy_progress),(void *)pdata);
g_signal_connect(GTK_OBJECT(button),"clicked",GTK_SIGNAL_FUNC(destroy_progress),(void *)pdata);
gtk_widget_show_all(pdata->window1);
}
//压缩完成,打印压缩信息
void complete_compress()
{
GtkWidget *vbox, *vbox1, *hbox, *label, *button;
GdkColor color1, color2;
gdk_color_parse("LawnGreen",&color1);
gdk_color_parse("DarkBlue",&color2);
wgt.window2 = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(wgt.window2),GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(wgt.window2),300,150);
char buf[MAXLEN];
vbox = gtk_vbox_new(FALSE,0);
vbox1 = gtk_vbox_new(FALSE,0);
hbox = gtk_hbox_new(FALSE,0);
button = gtk_button_new_with_label("确定");
gtk_widget_set_size_request(button,100,30);
bzero(buf,sizeof(buf));
sprintf(buf,"源文件大小: %ld Byte\n压缩后文件大小: %ld Byte\n压缩用时: %.2lf seconds\n压缩率: %.2f %%\n",FileLength,sumlength,duration,rate*100);
label = gtk_label_new(buf);
gtk_widget_modify_fg(label,GTK_STATE_NORMAL,&color2);
gtk_widget_modify_fg(GTK_BIN(button)->child,GTK_STATE_PRELIGHT,&color1);
gtk_box_pack_start(GTK_BOX(vbox1),label,FALSE,FALSE,0);
gtk_box_pack_start(GTK_BOX(hbox),button,FALSE,FALSE,150);
gtk_box_pack_start(GTK_BOX(vbox),vbox1,FALSE,FALSE,0);
gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,FALSE,15);
gtk_container_add(GTK_CONTAINER(wgt.window2),vbox);
g_signal_connect(wgt.window2,"destroy",G_CALLBACK(gtk_dialog_destroy),(void *)wgt.window2);
g_signal_connect(GTK_OBJECT(button),"clicked",GTK_SIGNAL_FUNC(gtk_dialog_destroy),(void *)wgt.window2);
gtk_widget_show_all(wgt.window2);
}
//选择解压文件函数
void choose_file2(GtkWidget *widget,gpointer data)
{
GtkWidget *scroll_box;
GtkWidget *hbox;
GtkWidget *button1;
GtkWidget *button2;
GtkWidget *button3;
GtkWidget *tmp;
GtkWidget *label;
GdkColor color1;
GdkColor color2;
GdkColor color3;
GdkColor color4;
gdk_color_parse("DarkBlue",&color1);
gdk_color_parse("LawnGreen",&color2);
gdk_color_parse("gray",&color3);
gdk_color_parse("red",&color4);
tmp = (GtkWidget *)data;
gtk_widget_hide(tmp);
wgt.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(wgt.window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(wgt.window), 400, 150);
gtk_container_set_border_width(GTK_CONTAINER(wgt.window),10);
gtk_window_set_title(GTK_WINDOW(wgt.window),"文件解压");
gtk_window_set_resizable(GTK_WINDOW(wgt.window),TRUE);
wgt.vbox = gtk_vbox_new(FALSE,20);
hbox = gtk_hbox_new(FALSE,20);
scroll_box = gtk_scrolled_window_new(NULL,NULL);
wgt.text1 = gtk_text_view_new();
gtk_widget_modify_base(wgt.text1, GTK_STATE_NORMAL, &color3);
gtk_widget_modify_text(wgt.text1, GTK_STATE_NORMAL, &color1);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_box), GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC);
gtk_container_add(GTK_CONTAINER(scroll_box), wgt.text1);
gtk_widget_set_size_request(scroll_box,390,50);
button1 = gtk_button_new_with_label("选择文件");
button2 = gtk_button_new_with_label("确认解压");
button3 = gtk_button_new_with_label("取消解压");
label = gtk_label_new("待解压文件位置");
gtk_widget_modify_fg(label,GTK_STATE_NORMAL,&color1);
gtk_widget_modify_fg(GTK_BIN(button1)->child,GTK_STATE_PRELIGHT,&color1);
gtk_widget_modify_fg(GTK_BIN(button2)->child,GTK_STATE_PRELIGHT,&color2);
gtk_widget_modify_fg(GTK_BIN(button3)->child,GTK_STATE_PRELIGHT,&color4);
//gtk_widget_modify_bg(button1, GTK_STATE_PRELIGHT, &color1);
//gtk_widget_modify_bg(button2, GTK_STATE_PRELIGHT, &color2);
//gtk_widget_modify_bg(button3, GTK_STATE_PRELIGHT, &color3);
gtk_box_pack_start(GTK_BOX(wgt.vbox),button1,FALSE,FALSE,10);
gtk_box_pack_start(GTK_BOX(wgt.vbox),label,FALSE,FALSE,10);
gtk_box_pack_start(GTK_BOX(wgt.vbox),scroll_box,FALSE,FALSE,10);
gtk_box_pack_start(GTK_BOX(hbox),button2,FALSE,FALSE,10);
gtk_box_pack_end(GTK_BOX(hbox),button3,FALSE,FALSE,10);
gtk_container_add(GTK_CONTAINER(wgt.window),wgt.vbox);
gtk_container_add(GTK_CONTAINER(wgt.vbox),hbox);
gtk_widget_show_all(wgt.window);
g_signal_connect(GTK_OBJECT(button1),"clicked",GTK_SIGNAL_FUNC(send_file),NULL);
g_signal_connect(GTK_OBJECT(button2),"clicked",GTK_SIGNAL_FUNC(file_decompress),NULL);
g_signal_connect(GTK_OBJECT(button3),"clicked",GTK_SIGNAL_FUNC(compressor),(void *)wgt.window);
g_signal_connect(GTK_OBJECT(wgt.window),"delete_event",GTK_SIGNAL_FUNC(compressor),(void *)wgt.window);
}
//文件解压窗口
void file_decompress(GtkWidget *widget,gpointer data)
{
GtkWidget *hbox, *vbox1, *vbox2, *pbar, *button;
struct widget *pdata;
GdkColor color1;
pthread_t thid;
gdk_color_parse("red",&color1);
pdata = g_malloc(sizeof(struct widget));
pdata->window1 = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(pdata->window1),GTK_WIN_POS_CENTER);
gtk_window_set_title(GTK_WINDOW(pdata->window1),"Process bar");
gtk_window_set_default_size(GTK_WINDOW(pdata->window1),300,100);
hbox = gtk_hbox_new(FALSE,0);
vbox1 = gtk_vbox_new(FALSE,0);
vbox2 = gtk_vbox_new(FALSE,0);
pdata->pbar = gtk_progress_bar_new();
button = gtk_button_new_with_label("取消");
gtk_widget_set_size_request(button,55,30);
gtk_widget_set_size_request(pdata->pbar,240,30);
gtk_widget_modify_fg(GTK_BIN(button)->child,GTK_STATE_PRELIGHT,&color1);
gtk_box_pack_start(GTK_BOX(vbox1),pdata->pbar,FALSE,FALSE,50);
gtk_box_pack_end(GTK_BOX(vbox2),button,FALSE,FALSE,50);
gtk_box_pack_start(GTK_BOX(hbox),vbox1,FALSE,FALSE,0);
gtk_box_pack_end(GTK_BOX(hbox),vbox2,FALSE,FALSE,5);
gtk_container_add(GTK_CONTAINER(pdata->window1),hbox);
pthread_create(&thid, NULL, decompress, NULL);
pdata->timer = g_timeout_add(120,progress_timeout,pdata);
g_signal_connect(pdata->window1,"destroy",G_CALLBACK(destroy_progress),(void *)pdata);
g_signal_connect(GTK_OBJECT(button),"clicked",GTK_SIGNAL_FUNC(destroy_progress),(void *)pdata);
gtk_widget_show_all(pdata->window1);
}
//解压缩完成,打印解压信息
void complete_decompress()
{
GtkWidget *window, *vbox, *vbox1, *hbox, *label, *button;
GdkColor color1, color2;
gdk_color_parse("LawnGreen",&color1);
gdk_color_parse("DarkBlue",&color2);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window),250,150);
char buf[MAXLEN];
vbox = gtk_vbox_new(FALSE,0);
vbox1 = gtk_vbox_new(FALSE,0);
hbox = gtk_hbox_new(FALSE,0);
button = gtk_button_new_with_label("确定");
gtk_widget_set_size_request(button,100,30);
bzero(buf,sizeof(buf));
sprintf(buf,"压缩文件大小: %ld Byte\n解压后文件大小: %ld Byte\n解压用时: %.2lf seconds\n解压速率: %.2f KB/s\n",FileLength1,FileLength,duration,speed);
label = gtk_label_new(buf);
gtk_widget_modify_fg(label,GTK_STATE_NORMAL,&color2);
gtk_widget_modify_fg(GTK_BIN(button)->child,GTK_STATE_PRELIGHT,&color1);
gtk_box_pack_start(GTK_BOX(vbox1),label,FALSE,FALSE,0);
gtk_box_pack_start(GTK_BOX(hbox),button,FALSE,FALSE,150);
gtk_box_pack_start(GTK_BOX(vbox),vbox1,FALSE,FALSE,0);
gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,FALSE,15);
gtk_container_add(GTK_CONTAINER(window),vbox);
g_signal_connect(window,"destroy",G_CALLBACK(gtk_dialog_destroy),(void *)window);
g_signal_connect(GTK_OBJECT(button),"clicked",GTK_SIGNAL_FUNC(gtk_dialog_destroy),(void *)window);
gtk_widget_show_all(window);
}
void file_ok_sel(GtkWidget *w, GtkFileSelection *fs)
{
GtkTextIter start, end;
const char *buf;
//g_print ("%s\n", gtk_file_selection_get_filename(GTK_FILE_SELECTION (fs)));
buf = gtk_file_selection_get_filename(GTK_FILE_SELECTION (fs));
strcpy(pathname,buf);
text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(wgt.text1));
gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(text_buffer),&start,&end);
gtk_text_buffer_insert(GTK_TEXT_BUFFER(text_buffer),&end,buf,strlen(buf));
gtk_widget_destroy((GtkWidget *)fs);
}
void send_file(GtkWidget *widget, gpointer data)
{
GtkWidget *filew;
filew = gtk_file_selection_new ("文件选择");
g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (filew)->ok_button),"clicked",G_CALLBACK(file_ok_sel), (void *)filew);
g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(filew)->cancel_button),"clicked",G_CALLBACK (gtk_dialog_destroy), (void *)filew);
gtk_widget_show (filew);
g_signal_connect (G_OBJECT (filew), "destroy",G_CALLBACK (gtk_dialog_destroy), (void *)filew);
}
//主函数
int main(int argc,char *argv[])
{
gtk_init(&argc,&argv);
//调用压缩器
compressor();
gtk_main();
return 0;
}
运行步骤:
1.安装gtk+2.0环境
Debian: sudo apt-get install libgtk2.0-dev
RedHat: sudo yum install gtk2-devel-docs
2.编译
gcc -o compressor compressor.c -g -lpthread `pkg-config --cflags --libs gtk+-2.0`
3.运行
./compressor
程序运行部分截图