Inflate动态Huffman解压缩

news2024/9/27 7:24:16

上个已经实现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<>() {
				@Override
				public int compare(Node o1, Node o2) {
					return o1.bitLen!=o2.bitLen ? o1.bitLen-o2.bitLen : o1.value - o2.value;
				}
			});
			
			// 初始化第一个节点,实现规则1
			table.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,实现规则2
					node.code = prev.code + 1;
				else if (node.bitLen > prev.bitLen)	// 位长不等,实现规则3
					node.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 length
		
		int 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' length
		int ccl_num = hclen + 4;   // 
		
		int[] cl1 = new int[cl1_num];
		int[] cl2 = new int[cl2_num];
		int[] ccl = new int[19]; // ccl bits
		
		// 读取CCL
		Arrays.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, 每个3bit
			int 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 code
				value = code1.findValue(code);
			} while (value == null);
			
			// 判断
			if (value >= 0 && value <= 255)// literal
				baos.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 code
					value = 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.coloradmin.cn/o/1644266.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

推荐一个开源的MES系统

软件介绍 HM-MES是一款旨在帮助工厂实现生产计划、工艺管理和质量控制的工业生产管理软件。该软件基于Java Web技术和MySql数据库开发&#xff0c;拥有简洁、易用、安全和稳定等特点&#xff0c;适用于广泛的生产管理场景。 功能描述 1.产品和原材料双向溯源&#xff0c;支持二…

练习题(2024/5/3)

1对称二叉树 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true示例 2&#xff1a; 输入&#xff1a;root [1,2,2,null,3,null,3] 输出&#xff1a;false提示&#xff1a; 树中…

meshlab: pymeshlab计算两个模型的布尔交集(mesh boolean intersection)

一、关于环境 请参考&#xff1a;pymeshlab遍历文件夹中模型、缩放并导出指定格式-CSDN博客 二、关于代码 本文所给出代码仅为参考&#xff0c;禁止转载和引用&#xff0c;仅供个人学习。 本案例以两个圆环为例。 左侧为两个圆环&#xff0c;右上是重叠&#xff0c;右下是圆…

斯坦福开源端侧大模型Octopus v2,2B参数量可在移动端运行,性能超越GPT-4,准确率超Llama7B

前言 斯坦福大学研究人员近日推出了开源端侧大模型Octopus v2&#xff0c;引起了广泛关注。Octopus v2拥有20亿参数量&#xff0c;可以在智能手机、车载系统等终端设备上高效运行&#xff0c;在准确性和推理速度方面都超越了GPT-4。 Huggingface模型下载&#xff1a;https://h…

力扣每日一题113:路径总和||

题目 中等 给你二叉树的根节点 root 和一个整数目标和 targetSum &#xff0c;找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。 叶子节点 是指没有子节点的节点。 示例 1&#xff1a; 输入&#xff1a;root [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSu…

【Java】基本程序设计结构(二)

前言&#xff1a;上一篇我们详细介绍了Java基本程序设计结构中前半部分&#xff0c;一个简单的Java应用&#xff0c;注释&#xff0c;数据类型&#xff0c;变量与常量&#xff0c;运算符&#xff0c;字符串。包括本篇将延续上篇内容介绍后续内容&#xff0c;包括输入输出&#…

PC端Discord设置代理2022

开始使用 方法非常简单&#xff0c;在此下载release.zip并解压version.dll https://github.com/aiqinxuancai/discord-proxy/releases​github.com/aiqinxuancai/discord-proxy/releases 将version.dll放在Discord.exe所在目录&#xff08;如Discord有更新&#xff0c;则可能…

华为二层交换机与路由器连通上网实验

华为二层交换机与路由器连通上网实验 二层交换机是一种网络设备&#xff0c;用于在局域网&#xff08;LAN&#xff09;中转发数据帧。它工作在OSI模型的第二层&#xff0c;即数据链路层。二层交换机通过学习和维护MAC地址表&#xff0c;实现了数据的快速转发和广播域的隔离。 实…

Kannala-Brandt 鱼眼相机模型

最近在学习 ORB-SLAM3 的源代码&#xff0c;并模仿、重构了相机模型的实现 在学习的过程中发现针孔相机 (Pinhole) 与鱼眼相机 (Fisheye) 都有畸变参数&#xff0c;但是鱼眼相机无法使用 cv::undistort 函数去畸变 在对鱼眼相机的深度归一化平面进行可视化后&#xff0c;发现…

cordova build android 下载gradle太慢

一、 在使用cordova run android / cordova build android 的时候 gradle在线下载 对于国内的链接地址下载太慢。 等待了很长时间之后还会报错。 默认第一次编译在线下载 gradle-7.6.1-all.zip 然后解压缩到 C:\Users\Administrator\.gradle 文件夹中,下载慢导致失败。 二…

基于AT89C51单片机的温度上下限自动控制检报警设计

点击链接获取Keil源码与Project Backups仿真图: https://download.csdn.net/download/qq_64505944/89247694?spm=1001.2014.3001.5501 C 源码+仿真图+毕业设计+实物制作步骤+06 题 目 基于单片机的温度检测调节系统设计 姓 名 学 号 专业班级 指导教师 年 月 日 任务书 …

Android 14 变更及适配攻略

准备工作 首先将我们项目中的 targetSdkVersion和compileSdkVersion 升至 34。 影响Android 14上所有应用 1.最低可安装的目标 API 级别 从 Android 14 开始&#xff0c;targetSdkVersion 低于 23 的应用无法安装。要求应用满足这些最低目标 API 级别要求有助于提高用户的安…

图中有几个三角形

让我们先把三角形进行分类&#xff1a;1块组成的三角形、2块组成的三角形、依此类推。 1块组成的三角形有4个&#xff1a; 2块组成的三角形有&#xff1a;12,13,14,23,24,34.其中&#xff0c;14&#xff0c;23构不成三角形. 3块组成的三角形有&#xff1a;123,124,134,234。但…

Dragonfly 拓扑的路由算法

Dragonfly 拓扑的路由算法 1. Dragonfly 上的路由 (1)最小路由(2)非最小路由 2. 评估 Dragonfly 拓扑的路由算法 John Kim, William J. Dally 等人在 2008 年的 ISCA 中提出技术驱动、高度可扩展的 Dragonfly 拓扑。而文章中也提到了 针对 Dragonfly 拓扑的路由算法。本文对…

springboot医院信管系统

摘 要 随着信息技术和网络技术的飞速发展,人类已进入全新信息化时代,传统管理技术已无法高效,便捷地管理信息。为了迎合时代需求,优化管理效率,各种各样的管理系统应运而生,各行各业相继进入信息管理时代,医院信管系统就是信息时代变革中的产物之一。 任何系统都要遵循…

深入学习和理解Django模板层:构建动态页面

title: 深入学习和理解Django模板层&#xff1a;构建动态页面 date: 2024/5/5 20:53:51 updated: 2024/5/5 20:53:51 categories: 后端开发 tags: Django模板表单处理静态文件国际化性能优化安全防护部署实践 第一章&#xff1a;模板语法基础 Django模板语法介绍 Django模…

高扬程水泵助力森林消防,守护绿色生命线/恒峰智慧科技

随着人类社会的不断发展&#xff0c;森林资源的保护和管理变得越来越重要。然而&#xff0c;森林火灾却时常威胁着这一宝贵资源。为了有效应对森林火灾&#xff0c;提高灭火效率&#xff0c;高扬程水泵在森林消防中发挥了重要作用。本文将重点介绍高扬程水泵在森林消防中的应用…

微服务架构与单体架构

微服务架构与与单体架构比较 微服务架构是一种将应用程序作为一组小的、独立服务的系统架构风格&#xff0c;每个服务运行在其自己的进程中&#xff0c;并通常围绕业务能力组织。这些服务通过定义良好且轻量级的机制&#xff08;通常是HTTP REST API&#xff09;进行通信。微服…

js模块化:修改导入模块的内容,会有影响吗?

起因 element-ui的popper组件相关的层级&#xff0c;是使用popup-manager来统一管理的。 之前试图在自己的组件里导入并使用element-ui的popup-manager&#xff0c;但是层级老是和element-ui组件的层级冲突&#xff0c;看了下源码&#xff0c;竟意外发现&#xff0c;使用popu…

15_Scala面向对象编程_访问权限

文章目录 Scala访问权限1.同类中访问2.同包不同类访问3.不同包访问4.子类权限小结 Scala访问权限 知识点概念 private --同类访问private[包名] --包私有&#xff1b; 同类同包下访问protected --同类&#xff0c;或子类 //同包不能访问(default)(public)默认public --公…