Inflate动态Huffman解压缩

上个已经实现GZIP压缩文件格式的Inflate静态Huffman解压,这个实现Inflate的无压缩输出和动态Huffman解压。

Java语言实现,Eclipse下编写。

范式Huffman解码实现,输入huffman编码,输出原始数据

    // 范式huffman解码static class CanonicalCode {Vector<Node> table = new Vector<>();public CanonicalCode(int[] len) {for (int i=0; i<len.length; i++)if (len[i] != 0) // 过滤0-即不使用的节点table.add( new Node(i, len[i]) ); // value, bits Length (值, 待编码的编码长度)// 按编码长度+值排序Collections.sort(table, new Comparator<>() {@Overridepublic int compare(Node o1, Node o2) {return o1.bitLen!=o2.bitLen ? o1.bitLen-o2.bitLen : o1.value - o2.value;}});// 初始化第一个节点,实现规则1table.get(0).code = 1 << table.get(0).bitLen;// 计算每一个值得huffman编码for (int i=1; i<table.size(); i++) {Node node = table.get(i);Node prev = table.get(i-1);if (node.bitLen == prev.bitLen)  // 如果位长相等+1,实现规则2node.code = prev.code + 1;else if (node.bitLen > prev.bitLen)	// 位长不等,实现规则3node.code = ( prev.code + 1) << (node.bitLen - prev.bitLen);  // 左移'位长差'}}// 打印符号和huffman码的对应关系void debug() {for (int i=0; i<table.size(); i++) {Node n = table.get(i);System.out.println( n);}}// 根据传入的huffman编码,得到原始数值Integer findValue(int code) {for (Node node : table)if (node.code == code)return node.value;return null;}}

无压缩数据解码:

	bis.alignByte(); // 对齐字节边界int len = bis.ReadBits(16);int nlen = bis.ReadBits(16);assert len + nlen == 65535;for (int i=0; i<len; i++) {baos.Write(bis.ReadBits(8));}

动态huffman解码:

	else if (bType == 2) { // dynamic huffman// length有29个int hlit = bis.ReadBits(5);  // CL1数量 - 字/长度 码个数, LIT(literal/length)// distance码有30个int hdist = bis.ReadBits(5); // CL2数量 - 距离 码个数, DIST(distance)int hclen = bis.ReadBits(4); // c_len:code lengths for the code lengthint cl1_num = hlit + 257;  // CL1(Code Length 1): 'literal/length' length (literal[0..255]+压缩块结束[256] = 257)int cl2_num = hdist + 1;   // CL2(Code Length 2): 'distance code' lengthint ccl_num = hclen + 4;   // int[] cl1 = new int[cl1_num];int[] cl2 = new int[cl2_num];int[] ccl = new int[19]; // ccl bits// 读取CCLArrays.fill(ccl, 0);int[] PermutationtTable = new int[] {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };for (int i=0; i<ccl_num; i++) { // 读取CCL, 每个3bitint p = PermutationtTable[i];ccl[p] = bis.ReadBits(3);}// 通过CCL构建范式huffman编码CanonicalCode codes = new CanonicalCode(ccl);//读取CL1和CL2,'literal/length' Sequence 码流 + dist流IntBuffer sq = IntBuffer.allocate(cl1_num + cl2_num);int prevValue = -1, cl_decode_num = 0;while (cl_decode_num < cl1_num + cl2_num) {Integer value = null;int code = 1;// 范式huffman解码int bits = 1;while (value == null) {code = (code << 1 ) | bis.ReadBit();  // huffman编码value = codes.findValue( code); // 查找对应的符号if ( (bits++) > 15 )throw new java.lang.IllegalArgumentException();}// 处理value, 实现 0-15,16,17,18 这套规则int[] bs;if (value == 17) { // 标识长度int len = bis.ReadBits(3) + 3;bs = new int[len];Arrays.fill(bs, (byte)0);}else if (value == 18) {int len = bis.ReadBits(7) + 11;bs = new int[len];Arrays.fill(bs, (byte)0);}else if (value == 16) {int len = bis.ReadBits(2) + 3;bs = new int[len];Arrays.fill(bs, (byte) prevValue);}else if (value >=0 && value <= 15){bs = new int[] {  value };prevValue = value;}else throw new java.lang.IllegalArgumentException(value + "");sq.put(bs); // 写入符号cl_decode_num += bs.length; // 增加已得到的码流长度}int[] bs = sq.array();// 分别得到CL1和CL2 System.arraycopy(bs, 0, cl1, 0, cl1.length);System.arraycopy(bs, cl1.length, cl2, 0, cl2.length);CanonicalCode code1 = new CanonicalCode(cl1); // literal/length解码器CanonicalCode code2 = new CanonicalCode(cl2); // distance解码器// 解码Integer value = null;do {// 解literal/length码int code = 1;do {code = (code << 1) | bis.ReadBit(); // 读取Huffman codevalue = code1.findValue(code);} while (value == null);// 判断if (value >= 0 && value <= 255)// literalbaos.Write(value);else if (value == 256) // 结束标志break ;else if (value >= 257 && value <= 285) { // length// 处理长度int length = LengthExtraCodeLengthsTable.get(value);int bits = LengthExtraCodeBitsTable.get(value); // 扩展bit长if (bits != 0) {int ext =  ReadExtCode(bis, bits);length = length + ext;}// 读取huffman编码code = 1;do {code = (code << 1) | bis.ReadBit(); // 读取Huffman codevalue = code2.findValue(code);} while (value == null);// 处理距离int distance = DistanceExtraCodeLengthsTable.get(value);bits = DistanceExtraCodeBitsTable.get(value); // 距离扩展if (bits != 0) {int ext =ReadExtCode(bis , bits);distance = distance + ext;}// LZ77滑动窗口计算获取量int[] arr = baos.GetInts();int d = arr.length - distance;if (d < 0) {d = 0;length = length + distance - arr.length;}// 读取滑动窗口,写入到结果for (int i=0; i<length; i++) {int m = arr[ d + i];baos.Write(m);arr = baos.GetInts();}}} while (value != 256);}

输出结果:

对待压缩文件sample-5.svg 计算md5值,得到:84018a59da62b5af9de4c0843ce5d0b6

使用gzip对文件压缩

使用Java程序对压缩后的文件sample-5.svg.gz解压缩,得到sample.svg

对解压后的文件计算md5值,得到84018a59da62b5af9de4c0843ce5d0b6

解压前文件的md5值==解压后的文件的md5值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/669676.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

视频号小店有自然/搜索流量吗?

我是王路飞。 视频号小店不过就是腾讯版的“抖音小店”。 本质都是借助短视频的流量红利&#xff0c;进行电商变现。 所以&#xff0c;在视频号开店&#xff0c;依旧是“无货源模式”“找达人带货玩法”。 至于自然/搜索流量&#xff0c;现阶段的视频号小店几乎是没有的&am…

27 JavaScript学习:异步编程

异步的概念 在JavaScript中&#xff0c;异步编程是一项重要的概念&#xff0c;特别在处理用户交互、网络请求和文件读写等场景下非常常见。JavaScript是一门单线程语言&#xff0c;因此需要通过异步编程来避免阻塞主线程&#xff0c;保证程序的流畅性和响应性。 在JavaScrip…

PDF到TXT:一键解锁文本魅力,轻松实现格式转换!

PDF文件以其独特的跨平台、易阅读性受到了广大用户的青睐。但是&#xff0c;有时我们也需要将PDF文件转换为其他格式&#xff0c;以满足不同的需求。比如&#xff0c;有时候我们需要将PDF文件转换为TXT格式&#xff0c;以便在移动设备上轻松阅读或进行文本编辑。这时&#xff0…

3.ERC4626

ERC4626是一个vault&#xff0c;在DAI中&#xff0c;使用ETH换取DAI。其流程为先充值ETH到maker vault。 Vault 资产的管理、分红用户充值某项资产获取某个凭证该凭证作为分红、推出的依据Yield Farming/借贷/质押等 以太坊改进提案EIP:ethereum improvemwnt proposal 最初E…

BTCOIN的革命之路:通过SocialFi重塑全球金融生态系统

BTCOIN的革命之路&#xff1a;通过SocialFi重塑全球金融生态系统 今日&#xff0c;BTCOIN宣布发布WEB3.0论坛引发业内现象级关注&#xff1a;作为一个倡导WEB3.0理念的数字金融平台&#xff0c;在数字货币的波澜壮阔中&#xff0c;BTCOIN以其独特的生态定位和战略愿景&#xff…

AI大模型探索之路-训练篇15:大语言模型预训练之全量参数微调

系列篇章&#x1f4a5; AI大模型探索之路-训练篇1&#xff1a;大语言模型微调基础认知 AI大模型探索之路-训练篇2&#xff1a;大语言模型预训练基础认知 AI大模型探索之路-训练篇3&#xff1a;大语言模型全景解读 AI大模型探索之路-训练篇4&#xff1a;大语言模型训练数据集概…

图像分割入门-Unet++理论与实践

探索 U-net&#xff1a;改进的图像分割神经网络 引言 图像分割是计算机视觉领域中的重要任务&#xff0c;旨在将图像中的每个像素分配到特定的类别或区域。在许多应用中&#xff0c;如医学影像分析、自动驾驶和地块识别等领域&#xff0c;图像分割都扮演着关键角色。 U-net …

前端奇怪面试题总结

面试题总结 不修改下面的代码进行正常解构 这道题考的是迭代器和生成器的概念 let [a,b] {a:1,b:2}答案 对象缺少迭代器&#xff0c;需要手动加上 Object.prototype[Symbol.iterator] function* (){// return Object.values(this)[Symbol.iterator]()return yeild* Object.v…

Java常用命令总结 持续更新中!!!

蓝桥杯JAVA组 推荐输入输出示例 // 基础输入 import java.util.*;public class Main{public static void main(String[] args){} }// 非静态方法调用 new Main.Solution();//static函数里面调用非static函数 类.函数// 更快的输入方式 BufferedReader // 更快的输出方式 Print…

腾讯云服务器 宝塔面板部署小程序和后台教程

文章目录 目录 文章目录 安装流程 小结 概要部署流程技术细节小结 概要 本次的部署准备了3个域名&#xff0c;都是从二级域名映射出3个三级域名&#xff0c;域名注册可以在3大互联网官网购买一个域名就行。并且备案审核这些比较花费时间一般需要15工作日 部署流程 宝塔面板的…

【ITK统计】第一期 分类器

很高兴在雪易的CSDN遇见你 VTK技术爱好者 QQ:870202403 公众号:VTK忠粉 前言 本文分享ITK中的分类器及其使用情况,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步! 你的点赞就是我的动力(^U^)ノ~YO 在统计分…

GROUP_CONCAT超出1024截取

GROUP_CONCAT 是 MySQL 数据库中的一个函数&#xff0c;用于将来自同一个组的多个字符串连接成一个字符串结果。但是&#xff0c;GROUP_CONCAT 有一个默认的最大长度限制&#xff0c;即 1024 字符。这意味着&#xff0c;如果你尝试连接的字符串总长度超过 1024 字符&#xff0c…