7.8 LZW压缩的实现
7-10 lzw.c
#include <stdlib.h>
#include <stdio.h>
#define BITS 12 //每个数据项的二进制位数
#define HASHING_SHIFT BITS-8 //HASH表的移位数
#define MAX_VALUE (1<<BITS)-1
#define MAX_CODE MAX_VALUE-1 //最大标号
#define TABLE_SIZE 4099 //HASH表的长度
typedef struct{
int *code; //代码
unsigned int *prefix; //前缀
unsigned char *suffix; //后缀
}LZW_DATA;
unsigned char decode_stack[TABLE_SIZE]; //用于保存解压缩后的数据
LZW_DATA lzw1,*lzw;
void compress(FILE *input,FILE *output); //压缩函数
void expand(FILE *input,FILE *output); //解压函数
unsigned int hashsearch(int hash_prefix,unsigned int hash_character); //HASH表搜索函数
char *decode(unsigned char *buffer,unsigned int code);
unsigned int incode(FILE *input);
void outcode(FILE *output,unsigned int code);
void compress(FILE *input,FILE *output) //压缩函数
{
unsigned int curr_code;
unsigned int suffix; //后缀字符
unsigned int prefix; //前缀字符
unsigned int index;
int i;
if(!(lzw1.code=malloc(TABLE_SIZE*sizeof(unsigned int)))) //代码值数组
{
printf("内存分配失败!\n");
exit();
}
if(!(lzw1.prefix=malloc(TABLE_SIZE*sizeof(unsigned int))))//压缩前数据
{
printf("内存分配失败!\n");
exit();
}
if(!(lzw1.suffix=malloc(TABLE_SIZE*sizeof(unsigned char))))//压缩后数据
{
printf("内存分配失败!\n");
exit();
}
lzw=&lzw1;
curr_code=; //编译表中的字符串编号从258开始
;i<TABLE_SIZE;i++) //初始化标号数组
lzw->code[i]=-;
i=;
printf("\n开始压缩.");
prefix=getc(input); //从文件读取一个字节
while((suffix=getc(input))!= (unsigned)EOF) //循环处理输入文件中的内容
{
) //处理1000个字节显示一个小数点,表示系统正在处理
{
i=;
printf(".");
}
index=hashsearch(prefix,suffix); //在HASH表中查找并返回索引号
)//若该标号存在
prefix=lzw->code[index];//使用该标号作为前缀
else{ //若标号不存在
if (curr_code<=(MAX_CODE)){ //标号未超过最大标号
lzw->code[index]=curr_code++; //增加一个标号
lzw->prefix[index]=prefix; //保存前缀
lzw->suffix[index]=suffix; //保存后缀
}
outcode(output,prefix); //输出前缀字节的内容
prefix=suffix;//将后缀作前缀,准备下次循环
}
}
outcode(output,prefix); //输出前缀
outcode(output,(MAX_VALUE)); //输出结束标志
outcode(output,);
free(lzw->code); //释放分配的内存
free(lzw->prefix);
free(lzw->suffix);
}
unsigned int hashsearch(int prefix,unsigned int suffix)//HASH表搜索函数
{
int index;
int offset;
index=(suffix << HASHING_SHIFT)^prefix; //构造HASH地址
)
offset=;
else
offset=TABLE_SIZE-index;
)
{
) //找到一个空表项
return(index); //返回HASH地址
if (lzw->prefix[index]==prefix && lzw->suffix[index]==suffix) //找到目标数据
return(index); //返回HASH地址
index-=offset; //处理冲突,调整HASH地址
) index+=TABLE_SIZE; //调整HASH地址
}
}
void outcode(FILE *output,unsigned int code) //输出压缩后的字节内容
{
; //静态变量,保存已输出数据的二进制位数
static unsigned long obb=0L;//静态变量,保存需输出数据的二进制位数
obb |= (unsigned -BITS-ob); //进行移位合并
ob+=BITS; //增加需输出数据的二进制位
) //达到一个字节,则输出
{
putc(obb>>,output); //右移24位,使低字节8位为需要输出的数据
obb<<= ; //左移8位,去掉已输入的一个字节数据
ob-=; //减去已输出的8位,保留剩余的未输出的位数
}
return;
}
void expand(FILE *input,FILE *output) //解压缩函数
{
unsigned int curr_code;
unsigned int suffix;
unsigned int prefix;
int ch;
int i;
unsigned char *ps;
char *decode(unsigned char *buffer,unsigned int code);
if(!(lzw1.code=malloc(TABLE_SIZE*sizeof(unsigned int)))) //代码值数组
{
printf("内存分配失败!\n");
exit();
}
if(!(lzw1.prefix=malloc(TABLE_SIZE*sizeof(unsigned int))))//压缩前数据
{
printf("内存分配失败!\n");
exit();
}
if(!(lzw1.suffix=malloc(TABLE_SIZE*sizeof(unsigned char))))//压缩后数据
{
printf("内存分配失败!\n");
exit();
}
lzw=&lzw1;
curr_code=; //定义标号从258开始
i=;
printf("\n解压缩.");
prefix=incode(input); //读入第一个编码,并初始化字符变量
ch=prefix; //保存前缀到字符变量
putc(prefix,output); // 输出字符到输出文件上
while ((suffix=incode(input))!=(MAX_VALUE)) //循环进行解压缩
{
) //处理1000个字节就显示一个点
{
i=;
printf(".");
}
if (suffix>=curr_code)//后缀是未定义的标号
{
*decode_stack=ch; //保存前缀字符
ps=decode(decode_stack+,prefix);//调用函数进行解码
}
else
ps=decode(decode_stack,suffix); //调用解码函数处理后缀
ch=*ps;
while(ps>=decode_stack) //循环输出解码的字节
putc(*ps--,output);
if (curr_code<=MAX_CODE) //若标号未超过最大值
{
lzw->prefix[curr_code]=prefix; //保存前缀到编译表
lzw->suffix[curr_code]=ch; //保存后缀到编译表
curr_code++; //标号增加
}
prefix=suffix; //后缀作前缀,准备下次的循环
}
free(lzw->code); //释放分配的内存
free(lzw->prefix);
free(lzw->suffix);
}
char *decode(unsigned char *buffer,unsigned int code) //解码函数
{
;
) //code不是ASCII码字符
{
*buffer++ =lzw->suffix[code]; //保存标号到缓冲区
code=lzw->prefix[code]; //取得该标号的前缀
if (i++>=TABLE_SIZE)
{
printf("内存溢出!\n");
exit();
}
}
*buffer=code; //将标号放入缓冲区
return(buffer); //返回缓冲区中的内容
}
unsigned int incode(FILE *input) //从压缩文件中读取数据
{
unsigned int ret;
; //静态变量,保存读入数据的二进制位数
static unsigned long ibb=0L; //静态变量,保存已读入数据的二进制位
) //若数据位数小于24位
{
ibb |= (unsigned -ib); //从文件中获取一个字节,并组合到需输出的二进制位中
ib += ;
}
ret=ibb>>(-BITS); //右移20位二进制数 (32-12)
ibb <<= BITS; //再左多12位
ib -= BITS; //减去已返回的位数
return(ret);//返回移位后的数据
}
int main(int argc, char *argv[])
{
FILE *fp1,*fp2;
;
char *op;
) //判断传入参数的数量
flag=;
else{
op=argv[];
) && strcmp(op,) flag=;
}
if(flag)
{
printf("使用方法:command -z/-e source dest\n");
exit();
}
],"rb"))==NULL) //打开文件出错
{
printf("不能打开源文件!\n");
exit();
}
],"wb"))==NULL) //创建文件出错
{
printf("不能创建目标文件!\n");
exit();
}
)
compress(fp1,fp2);//调用压缩函数
else
expand(fp1,fp2);//调用解压缩函数
fclose(fp1);//释放文件指针
fclose(fp2);
;
}
7.8 LZW压缩的实现的更多相关文章
- LZW压缩算法
转载自http://www.cnblogs.com/jillzhang/archive/2006/11/06/551298.html 记录此处仅自己供学习之用 lzw解压缩算法: 用单个字符初始化字符 ...
- 浓缩的才是精华:浅析GIF格式图片的存储和压缩
成文迪, 在Web前端摸爬滚打的码农一枚,对技术充满热情的菜鸟,致力为手Q的建设添砖加瓦. GIF格式的历史 GIF(Graphics Interchange Format)原义是"图像互换 ...
- golang使用 gzip压缩
golang使用 gzip压缩 这个例子中使用gzip压缩格式,标准库还支持zlib, bz2, flate, lzw 压缩处理_三步: 1.创建压缩文件2.gzip write包装3.写入数据 ou ...
- 【腾讯Bugly干货分享】舞动的表情包——浅析GIF格式图片的存储和压缩
本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:https://mp.weixin.qq.com/s/v0pffOhjFWnVbU2lXjuEmw 导语 G ...
- 腾讯技术分享:GIF动图技术详解及手机QQ动态表情压缩技术实践
本文来自腾讯前端开发工程师“ wendygogogo”的技术分享,作者自评:“在Web前端摸爬滚打的码农一枚,对技术充满热情的菜鸟,致力为手Q的建设添砖加瓦.” 1.GIF格式的历史 GIF ( Gr ...
- LZW算法PHP实现方法 lzw_decompress php
LZW算法PHP实现方法 lzw_decompress php 博客分类: Php / Pear / Mysql / Node.js LZW算法简介 字符串和编码的对应关系是在压缩过程中动态生成的 ...
- 黄聪:浓缩的才是精华:浅析GIF格式图片的存储和压缩(转)
http://www.cnblogs.com/qcloud1001/p/6647080.html 成文迪, 在Web前端摸爬滚打的码农一枚,对技术充满热情的菜鸟,致力为手Q的建设添砖加瓦. GIF格式 ...
- 如何将matlab画出的图片保存为要求精度
· 来源:http://emuch.net/bbs/viewthread.php?tid=2705843 杂志社对投稿图片的分辨率通常有如下要求: TIFF: Colour or greyscale ...
- (转)原始图像数据和PDF中的图像数据
比较原始图像数据和PDF中的图像数据,结果见表1.1.表1.1中各种“解码器”的解释见本文后续的“PDF支持的图像格式”部分,“PDF中的图像数据”各栏中的数据来自开源的PdfView.如果您有兴趣查 ...
随机推荐
- vue2.X v-model 指令
1.v-model指令 <!DOCTYPE html> <html> <head> <title></title> <script s ...
- SpringBoot学习之启动方式
1.通过@SpringBootAppliction注解类启动 启动方法:找到注解类->鼠标右键->run as-> java application. 2 通过maven启动Spri ...
- (七)jQuery中的DOM操作
一.jQuery的DOM操作 (1)查找节点: 查找元素节点: 1. 获取指定的标签节点 $(“上级标签 标签:eq(“标签索引”) ; 如:var li = $("ul li:eq(2) ...
- css 使表格随着内容自动适应宽度
所谓难而不会,会儿不难.这个问题让我纠结了很长时间,一句css解决了,仅仅靠一个属性 td { white-space: nowrap; }
- PLSQL怎样导出oracle表结构
tools->export tables 是导出表结构还有数据 tools->export user objects是导出表结构 可以用tools->export tables ...
- sql 注入 与解决
package cn.itcast.jdbc; import java.sql.Connection;import java.sql.ResultSet;import java.sql.SQLExce ...
- C++钩子程序浅析
在网上搜索“键盘记录C++”实现可以找到很多相关文章,我也是照着上面的介绍去研究去试着做的,从懂到不懂.那么为什么有那么多材料我还要去写这样一篇 文章,我想这个是我个人需要关心的问题,我不是那种ctr ...
- swift基础教程笔记
http://www.imooc.com/learn/127 <玩儿转swift> 慕课网教程笔记,自己根据2.1的语法做了更新. I. 1.通过playground来学习.熟悉swift ...
- 苹果开发之COCOA编程(第三版)下半部分
第十八章:Image和鼠标事件 1.NSResponderNSView继承自NSResponder类.所有的事件处理方法都定义在NSResponder类中.NSResponder申明了如下方法:- ( ...
- EasyDSS RTMP流媒体服务器的HTTP接口query url的C++实现方法
EasyDSS支持HTTP GET接口访问,我们需要获取url的各种参数信息 比如http://ip:port/action?a=1&b=2&c=3 我们需要知道对应的a.b.c的值 ...