Files
thejinchao.github.io/blog/2025/02/JPEG004.html
T

42 lines
35 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="zh-CN" data-theme="light">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<meta name="generator" content="VuePress 2.0.0-rc.24" />
<meta name="theme" content="VuePress Theme Hope 2.0.0-rc.94" />
<style>
:root {
--vp-c-bg: #fff;
}
[data-theme="dark"] {
--vp-c-bg: #1b1b1f;
}
html,
body {
background: var(--vp-c-bg);
}
</style>
<script>
const userMode = localStorage.getItem("vuepress-theme-hope-scheme");
const systemDarkMode =
window.matchMedia &&
window.matchMedia("(prefers-color-scheme: dark)").matches;
if (userMode === "dark" || (userMode !== "light" && systemDarkMode)) {
document.documentElement.setAttribute("data-theme", "dark");
}
</script>
<script type="application/ld+json">{"@context":"https://schema.org","@type":"Article","headline":"JPEG算法解密(四)","image":["https://thejinchao.github.io/images/2014/08/hufman7.gif"],"dateModified":"2025-08-31T08:33:30.000Z","author":[{"@type":"Person","name":"JinChao","url":"https://thecodeway.com"}]}</script><meta property="og:url" content="https://thejinchao.github.io/blog/2025/02/JPEG004.html"><meta property="og:site_name" content="我的博客和笔记"><meta property="og:title" content="JPEG算法解密(四)"><meta property="og:description" content="JPEG算法解密(四) 步骤五:哈弗曼编码 JPEG压缩的最后一步是对数据进行哈弗曼编码(Huffman coding),哈弗曼几乎是所有压缩算法的基础,它的基本原理是根据数据中元素的使用频率,调整元素的编码长度,以得到更高的压缩比。 举个例子,比如下面这段数据 这段数据里面包含了33个字符,每种字符出现的次数统计如下 如果我们用我们常见的定长编码,每..."><meta property="og:type" content="article"><meta property="og:image" content="https://thejinchao.github.io/images/2014/08/hufman7.gif"><meta property="og:locale" content="zh-CN"><meta property="og:updated_time" content="2025-08-31T08:33:30.000Z"><meta property="article:modified_time" content="2025-08-31T08:33:30.000Z"><title>JPEG算法解密(四) | 我的博客和笔记</title><meta name="description" content="JPEG算法解密(四) 步骤五:哈弗曼编码 JPEG压缩的最后一步是对数据进行哈弗曼编码(Huffman coding),哈弗曼几乎是所有压缩算法的基础,它的基本原理是根据数据中元素的使用频率,调整元素的编码长度,以得到更高的压缩比。 举个例子,比如下面这段数据 这段数据里面包含了33个字符,每种字符出现的次数统计如下 如果我们用我们常见的定长编码,每...">
<link rel="preload" href="/assets/style-DeGCDZm0.css" as="style"><link rel="stylesheet" href="/assets/style-DeGCDZm0.css">
<link rel="modulepreload" href="/assets/app-DlommLbD.js"><link rel="modulepreload" href="/assets/JPEG004.html-DcmzbaxE.js"><link rel="modulepreload" href="/assets/plugin-vue_export-helper-DlAUqK2U.js">
<link rel="prefetch" href="/assets/about.html-BnEMLcqZ.js" as="script"><link rel="prefetch" href="/assets/index.html-jPVMq3lp.js" as="script"><link rel="prefetch" href="/assets/index.html-gMM-Tcqk.js" as="script"><link rel="prefetch" href="/assets/index.html-BP5ZChLS.js" as="script"><link rel="prefetch" href="/assets/flip_coin.html-B2WEW5Us.js" as="script"><link rel="prefetch" href="/assets/index.html-DjkAC4H8.js" as="script"><link rel="prefetch" href="/assets/mental_poker.html-NukViYhN.js" as="script"><link rel="prefetch" href="/assets/rsa.html-DkW71JZH.js" as="script"><link rel="prefetch" href="/assets/index.html-BOW7o10m.js" as="script"><link rel="prefetch" href="/assets/index.html-IbfWY_do.js" as="script"><link rel="prefetch" href="/assets/group.html-CpuVx9QA.js" as="script"><link rel="prefetch" href="/assets/index.html-BoggU2W0.js" as="script"><link rel="prefetch" href="/assets/linear_algebra.html-D2rwkcWr.js" as="script"><link rel="prefetch" href="/assets/number_theory_1.html-DxR9wxh5.js" as="script"><link rel="prefetch" href="/assets/number_theory_2.html-D_7QOhMm.js" as="script"><link rel="prefetch" href="/assets/number_theory_3.html-DlPu_try.js" as="script"><link rel="prefetch" href="/assets/probability.html-CcUq30wr.js" as="script"><link rel="prefetch" href="/assets/symbol.html-B89a6TZU.js" as="script"><link rel="prefetch" href="/assets/DH.html-XHTT2Dni.js" as="script"><link rel="prefetch" href="/assets/Ellipse.html-jPnF-eHK.js" as="script"><link rel="prefetch" href="/assets/Fibonacci.html-Dfag1Tc5.js" as="script"><link rel="prefetch" href="/assets/JPEG001.html-tWNO9VdD.js" as="script"><link rel="prefetch" href="/assets/JPEG002.html-BEmu0vf2.js" as="script"><link rel="prefetch" href="/assets/JPEG003.html-D9Ortpcj.js" as="script"><link rel="prefetch" href="/assets/JPEG005.html-CrflKMjW.js" as="script"><link rel="prefetch" href="/assets/Martingle.html-CrN7W3v6.js" as="script"><link rel="prefetch" href="/assets/MentalPoker01.html-DQgCJzB7.js" as="script"><link rel="prefetch" href="/assets/MentalPoker02.html-COcBjpS-.js" as="script"><link rel="prefetch" href="/assets/RandRound.html-C2MbgskP.js" as="script"><link rel="prefetch" href="/assets/SPH001.html-D2MTcfUh.js" as="script"><link rel="prefetch" href="/assets/SPH002.html-zxw79sTo.js" as="script"><link rel="prefetch" href="/assets/SPH003.html-_EEngzPo.js" as="script"><link rel="prefetch" href="/assets/SPH004.html-Cl8MDUJ-.js" as="script"><link rel="prefetch" href="/assets/SegmentCircle.html-BmcqcBYE.js" as="script"><link rel="prefetch" href="/assets/BezierLine01.html-CCv3Q06c.js" as="script"><link rel="prefetch" href="/assets/BezierLine02.html-je2Sr2gz.js" as="script"><link rel="prefetch" href="/assets/index.html-wTPaBKgF.js" as="script"><link rel="prefetch" href="/assets/ibl_01.html-9-g3WOr_.js" as="script"><link rel="prefetch" href="/assets/ibl_02.html-B9w0S9ZM.js" as="script"><link rel="prefetch" href="/assets/index.html-DvOuOIj1.js" as="script"><link rel="prefetch" href="/assets/index.html-CtAhYpjx.js" as="script"><link rel="prefetch" href="/assets/math_01.html-BiHpFlvW.js" as="script"><link rel="prefetch" href="/assets/math_02.html-DU7nOJT4.js" as="script"><link rel="prefetch" href="/assets/math_03.html-DPY6uVlX.js" as="script"><link rel="prefetch" href="/assets/transform_01.html-BWc2obRV.js" as="script"><link rel="prefetch" href="/assets/transform_02.html-BBme5AL7.js" as="script"><link rel="prefetch" href="/assets/transform_03.html-0Spljc9Z.js" as="script"><link rel="prefetch" href="/assets/transform_04.html-B91CMNsE.js" as="script"><link rel="prefetch" href="/assets/index.html-Xf2P60os.js" as="script"><link rel="prefetch" href="/assets/raster01.html-CiDi8IIr.js" as="script"><link rel="prefetch" href="/assets/raster02.html-DaZmjPFr.js" as="script"><link rel="prefetch" href="/assets/raster03.html-CZ6-ezPj.js" as="script"><link rel="prefetch" href="/assets/function.html-BPDZyrA7.js" as="script"><link rel="prefetch" href="/assets/grammar.html-JXO2EZb3.js" as="script"><link rel="prefetch" href="/assets/helloworld.html-DXN6yoiB.js" as="script"><link rel="prefetch" href="/assets/index.html-CkI9T8iX.js" as="script"><link rel="prefetch" href="/assets/object_and_class.html-C8Sq9bvd.js" as="script"><link rel="prefetch" href="/assets/BRDF.html-BcMwSED8.js" as="script"><link rel="prefetch" href="/assets/illumination_model_01.html-B8okaqnE.js" as="script"><link rel="prefetch" href="/assets/luminosity.html-QezvYI4b.js" as="script"><link rel="prefetch" href="/assets/microfacets_1.html-DtDbnYGH.js" as="script"><link rel="prefetch" href="/assets/microfacets_2.html-C3jhKwje.js" as="script"><link rel="prefetch" href="/assets/microfacets_3.html-M4UREu0c.js" as="script"><link rel="prefetch" href="/assets/render_function_1.html-DfDAw2P3.js" as="script"><link rel="prefetch" href="/assets/404.html-DPwPvEI9.js" as="script"><link rel="prefetch" href="/assets/index.html-DoEtvOh-.js" as="script"><link rel="prefetch" href="/assets/index.html-BnSbgljJ.js" as="script"><link rel="prefetch" href="/assets/index.html-CUvLlIy5.js" as="script"><link rel="prefetch" href="/assets/index.html-B2GzXoS9.js" as="script"><link rel="prefetch" href="/assets/index.html-Xz77KHqc.js" as="script"><link rel="prefetch" href="/assets/index.html-CHHuyI8G.js" as="script"><link rel="prefetch" href="/assets/index.html-DS3csrkE.js" as="script"><link rel="prefetch" href="/assets/index.html-B4J2mk8T.js" as="script"><link rel="prefetch" href="/assets/photoswipe.esm-CKV1Bsxh.js" as="script">
</head>
<body>
<div id="app"><!--[--><!--[--><!--[--><span tabindex="-1"></span><a href="#main-content" class="vp-skip-link sr-only">跳至主要內容</a><!--]--><!--[--><div class="theme-container external-link-icon" vp-container><!--[--><header id="navbar" class="vp-navbar" vp-navbar><div class="vp-navbar-start"><button type="button" class="vp-toggle-sidebar-button" title="Toggle Sidebar"><span class="icon"></span></button><!--[--><a class="route-link vp-brand" href="/" aria-label="带我回家"><img class="vp-nav-logo" src="/favicon.png" alt><!----><span class="vp-site-name hide-in-pad">我的博客和笔记</span></a><!--]--></div><div class="vp-navbar-center"><!--[--><nav class="vp-nav-links"><div class="vp-nav-item hide-in-mobile"><a class="route-link auto-link" href="/" aria-label="主页"><!--[--><iconify-icon class="vp-icon" icon="fa6-solid:house" sizing="height" height="1em"></iconify-icon><!--]-->主页<!----></a></div><div class="vp-nav-item hide-in-mobile"><a class="route-link route-link-active auto-link" href="/blog/" aria-label="文章"><!--[--><iconify-icon class="vp-icon" icon="fa6-solid:book" sizing="height" height="1em"></iconify-icon><!--]-->文章<!----></a></div><div class="vp-nav-item hide-in-mobile"><div class="vp-dropdown-wrapper"><button type="button" class="vp-dropdown-title" aria-label="开源项目"><!--[--><iconify-icon class="vp-icon" icon="fa6-solid:diagram-project" sizing="height" height="1em"></iconify-icon>开源项目<!--]--><span class="arrow"></span><ul class="vp-dropdown"><li class="vp-dropdown-item"><a class="auto-link external-link" href="https://github.com/thejinchao/turbolink" aria-label="TurboLink" rel="noopener noreferrer" target="_blank"><!---->TurboLink<!----></a></li><li class="vp-dropdown-item"><a class="auto-link external-link" href="https://github.com/thejinchao/TinyEncrypt" aria-label="TinyEncrypt" rel="noopener noreferrer" target="_blank"><!---->TinyEncrypt<!----></a></li><li class="vp-dropdown-item"><a class="auto-link external-link" href="https://github.com/thejinchao/ue5-style-guide" aria-label="UnrealStyleGuide" rel="noopener noreferrer" target="_blank"><!---->UnrealStyleGuide<!----></a></li><li class="vp-dropdown-item"><a class="auto-link external-link" href="https://github.com/thejinchao/AxTrace" aria-label="AxTrace" rel="noopener noreferrer" target="_blank"><!---->AxTrace<!----></a></li><li class="vp-dropdown-item"><a class="auto-link external-link" href="https://github.com/thejinchao/cyclone" aria-label="Cyclone" rel="noopener noreferrer" target="_blank"><!---->Cyclone<!----></a></li></ul></button></div></div><div class="vp-nav-item hide-in-mobile"><div class="vp-dropdown-wrapper"><button type="button" class="vp-dropdown-title" aria-label="个人笔记"><!--[--><iconify-icon class="vp-icon" icon="fa6-solid:lightbulb" sizing="height" height="1em"></iconify-icon>个人笔记<!--]--><span class="arrow"></span><ul class="vp-dropdown"><li class="vp-dropdown-item"><a class="route-link auto-link" href="/note/math/" aria-label="数学相关"><!---->数学相关<!----></a></li><li class="vp-dropdown-item"><a class="route-link auto-link" href="/note/graphics/" aria-label="图形学"><!---->图形学<!----></a></li><li class="vp-dropdown-item"><a class="route-link auto-link" href="/note/cryptography/" aria-label="密码学"><!---->密码学<!----></a></li><li class="vp-dropdown-item"><a class="route-link auto-link" href="/note/language/" aria-label="编程语言"><!---->编程语言<!----></a></li></ul></button></div></div><div class="vp-nav-item hide-in-mobile"><a class="route-link auto-link" href="/about.html" aria-label="关于"><!--[--><iconify-icon class="vp-icon" icon="fa6-solid:user-astronaut" sizing="height" height="1em"></iconify-icon><!--]-->关于<!----></a></div></nav><!--]--></div><div class="vp-navbar-end"><!--[--><!----><!----><div class="vp-nav-item hide-in-mobile"><button type="button" class="vp-color-mode-switch" id="color-mode-switch"><svg xmlns="http://www.w3.org/2000/svg" class="icon auto-icon" viewBox="0 0 1024 1024" fill="currentColor" aria-label="auto icon" name="auto" style="display:block;"><path d="M512 992C246.92 992 32 777.08 32 512S246.92 32 512 32s480 214.92 480 480-214.92 480-480 480zm0-840c-198.78 0-360 161.22-360 360 0 198.84 161.22 360 360 360s360-161.16 360-360c0-198.78-161.22-360-360-360zm0 660V212c165.72 0 300 134.34 300 300 0 165.72-134.28 300-300 300z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" class="icon dark-icon" viewBox="0 0 1024 1024" fill="currentColor" aria-label="dark icon" name="dark" style="display:none;"><path d="M524.8 938.667h-4.267a439.893 439.893 0 0 1-313.173-134.4 446.293 446.293 0 0 1-11.093-597.334A432.213 432.213 0 0 1 366.933 90.027a42.667 42.667 0 0 1 45.227 9.386 42.667 42.667 0 0 1 10.24 42.667 358.4 358.4 0 0 0 82.773 375.893 361.387 361.387 0 0 0 376.747 82.774 42.667 42.667 0 0 1 54.187 55.04 433.493 433.493 0 0 1-99.84 154.88 438.613 438.613 0 0 1-311.467 128z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" class="icon light-icon" viewBox="0 0 1024 1024" fill="currentColor" aria-label="light icon" name="light" style="display:none;"><path d="M952 552h-80a40 40 0 0 1 0-80h80a40 40 0 0 1 0 80zM801.88 280.08a41 41 0 0 1-57.96-57.96l57.96-58a41.04 41.04 0 0 1 58 58l-58 57.96zM512 752a240 240 0 1 1 0-480 240 240 0 0 1 0 480zm0-560a40 40 0 0 1-40-40V72a40 40 0 0 1 80 0v80a40 40 0 0 1-40 40zm-289.88 88.08-58-57.96a41.04 41.04 0 0 1 58-58l57.96 58a41 41 0 0 1-57.96 57.96zM192 512a40 40 0 0 1-40 40H72a40 40 0 0 1 0-80h80a40 40 0 0 1 40 40zm30.12 231.92a41 41 0 0 1 57.96 57.96l-57.96 58a41.04 41.04 0 0 1-58-58l58-57.96zM512 832a40 40 0 0 1 40 40v80a40 40 0 0 1-80 0v-80a40 40 0 0 1 40-40zm289.88-88.08 58 57.96a41.04 41.04 0 0 1-58 58l-57.96-58a41 41 0 0 1 57.96-57.96z"></path></svg></button></div><!----><!--]--><button type="button" class="vp-toggle-navbar-button" aria-label="Toggle Navbar" aria-expanded="false" aria-controls="nav-screen"><span><span class="vp-top"></span><span class="vp-middle"></span><span class="vp-bottom"></span></span></button></div></header><!----><!--]--><!----><div class="toggle-sidebar-wrapper"><span class="arrow start"></span></div><aside id="sidebar" class="vp-sidebar" vp-sidebar><!----><ul class="vp-sidebar-links"><li><a class="route-link auto-link vp-sidebar-link" href="/" aria-label="主页"><!--[--><iconify-icon class="vp-icon" icon="fa6-solid:house" sizing="both" width="1em" height="1em"></iconify-icon><!--]-->主页<!----></a></li><li><section class="vp-sidebar-group"><button class="vp-sidebar-header clickable active" type="button"><iconify-icon class="vp-icon" icon="fa6-solid:book" sizing="both" width="1em" height="1em"></iconify-icon><span class="vp-sidebar-title">我的文章</span><span class="vp-arrow down"></span></button><ul class="vp-sidebar-links"><li><section class="vp-sidebar-group"><button class="vp-sidebar-header clickable" type="button"><!----><span class="vp-sidebar-title">从抛币协议到智能合约</span><span class="vp-arrow end"></span></button><!----></section></li><li><section class="vp-sidebar-group"><button class="vp-sidebar-header clickable active" type="button"><!----><span class="vp-sidebar-title">JPEG算法解密</span><span class="vp-arrow down"></span></button><ul class="vp-sidebar-links"><li><a class="route-link auto-link vp-sidebar-link" href="/blog/2025/02/JPEG001.html" aria-label="Part1"><!---->Part1<!----></a></li><li><a class="route-link auto-link vp-sidebar-link" href="/blog/2025/02/JPEG002.html" aria-label="Part2"><!---->Part2<!----></a></li><li><a class="route-link auto-link vp-sidebar-link" href="/blog/2025/02/JPEG003.html" aria-label="Part3"><!---->Part3<!----></a></li><li><a class="route-link route-link-active auto-link vp-sidebar-link active" href="/blog/2025/02/JPEG004.html" aria-label="Part4"><!---->Part4<!----></a></li><li><a class="route-link auto-link vp-sidebar-link" href="/blog/2025/02/JPEG005.html" aria-label="Part5"><!---->Part5<!----></a></li><li><a class="auto-link external-link vp-sidebar-link" href="http://github.com/thejinchao/jpeg_encoder" aria-label="Github" rel="noopener noreferrer" target="_blank"><!---->Github<!----></a></li></ul></section></li><li><section class="vp-sidebar-group"><button class="vp-sidebar-header clickable" type="button"><!----><span class="vp-sidebar-title">SPH算法简介</span><span class="vp-arrow end"></span></button><!----></section></li><li><a class="route-link auto-link vp-sidebar-link" href="/blog/2025/02/Martingle.html" aria-label="赌博中的数学:Martingle策略"><!---->赌博中的数学:Martingle策略<!----></a></li><li><a class="route-link auto-link vp-sidebar-link" href="/blog/2025/02/RandRound.html" aria-label="如何生成一个随机的圆形"><!---->如何生成一个随机的圆形<!----></a></li><li><a class="route-link auto-link vp-sidebar-link" href="/blog/2025/02/DH.html" aria-label="一个简单的DH密钥协商算法的实现"><!---->一个简单的DH密钥协商算法的实现<!----></a></li><li><a class="route-link auto-link vp-sidebar-link" href="/blog/2025/02/SegmentCircle.html" aria-label="如何计算线段和圆的交点"><!---->如何计算线段和圆的交点<!----></a></li><li><a class="route-link auto-link vp-sidebar-link" href="/blog/2025/02/Ellipse.html" aria-label="一道数学趣题"><!---->一道数学趣题<!----></a></li><li><a class="route-link auto-link vp-sidebar-link" href="/blog/2025/02/Fibonacci.html" aria-label="斐波那契数列和1/89"><!---->斐波那契数列和1/89<!----></a></li><li><section class="vp-sidebar-group"><button class="vp-sidebar-header clickable" type="button"><!----><span class="vp-sidebar-title">匀速贝塞尔曲线运动的实现</span><span class="vp-arrow end"></span></button><!----></section></li></ul></section></li><li><section class="vp-sidebar-group"><button class="vp-sidebar-header clickable" type="button"><iconify-icon class="vp-icon" icon="fa6-solid:diagram-project" sizing="both" width="1em" height="1em"></iconify-icon><span class="vp-sidebar-title">开源项目</span><span class="vp-arrow end"></span></button><!----></section></li><li><section class="vp-sidebar-group"><button class="vp-sidebar-header clickable" type="button"><iconify-icon class="vp-icon" icon="fa6-solid:lightbulb" sizing="both" width="1em" height="1em"></iconify-icon><span class="vp-sidebar-title">学习笔记</span><span class="vp-arrow down"></span></button><ul class="vp-sidebar-links"><li><section class="vp-sidebar-group"><button class="vp-sidebar-header clickable" type="button"><!----><span class="vp-sidebar-title">数学相关</span><span class="vp-arrow end"></span></button><!----></section></li><li><section class="vp-sidebar-group"><button class="vp-sidebar-header clickable" type="button"><!----><span class="vp-sidebar-title">密码学</span><span class="vp-arrow end"></span></button><!----></section></li><li><section class="vp-sidebar-group"><button class="vp-sidebar-header clickable" type="button"><!----><span class="vp-sidebar-title">图形学</span><span class="vp-arrow end"></span></button><!----></section></li><li><section class="vp-sidebar-group"><button class="vp-sidebar-header clickable" type="button"><!----><span class="vp-sidebar-title">编程语言</span><span class="vp-arrow end"></span></button><!----></section></li></ul></section></li></ul><!----></aside><!--[--><main id="main-content" class="vp-page"><!--[--><!----><!----><nav class="vp-breadcrumb disable"></nav><div class="vp-page-title"><h1><!---->JPEG算法解密(四)</h1><!----><hr></div><!----><div class="" vp-content><!----><div id="markdown-content"><h1 id="jpeg算法解密-四" tabindex="-1"><a class="header-anchor" href="#jpeg算法解密-四"><span>JPEG算法解密(四)</span></a></h1><h3 id="步骤五-哈弗曼编码" tabindex="-1"><a class="header-anchor" href="#步骤五-哈弗曼编码"><span>步骤五:哈弗曼编码</span></a></h3><hr><p>JPEG压缩的最后一步是对数据进行哈弗曼编码(Huffman coding),哈弗曼几乎是所有压缩算法的基础,它的基本原理是根据数据中元素的使用频率,调整元素的编码长度,以得到更高的压缩比。<br> 举个例子,比如下面这段数据</p><div class="language-" data-highlighter="shiki" data-ext="" style="--shiki-light:#383A42;--shiki-dark:#abb2bf;--shiki-light-bg:#FAFAFA;--shiki-dark-bg:#282c34;"><pre class="shiki shiki-themes one-light one-dark-pro vp-code"><code class="language-"><span class="line"><span>AABCBABBCDBBDDBAABDBBDABBBBDDEDBD</span></span></code></pre></div><p>这段数据里面包含了33个字符,每种字符出现的次数统计如下</p><table class="gridtable" style="width:400px;text-align:center;border-collapse:collapse;"><tbody><tr><th style="width:100px;">字符</th><td style="width:60px;">A</td><td style="width:60px;">B</td><td style="width:60px;">C</td><td style="width:60px;">D</td><td style="width:60px;">E</td></tr><tr><th>次数</th><td>6</td><td>15</td><td>2</td><td>9</td><td>1</td></tr></tbody></table> 如果我们用我们常见的定长编码,每个字符都是3个bit。 <table class="gridtable" style="width:400px;text-align:center;border-collapse:collapse;"><tbody><tr><th style="width:100px;">字符</th><td style="width:60px;">A</td><td style="width:60px;">B</td><td style="width:60px;">C</td><td style="width:60px;">D</td><td style="width:60px;">E</td></tr><tr><th>编码</th><td>001</td><td>010</td><td>011</td><td>100</td><td>101</td></tr></tbody></table><p>那么这段文字共需要<code>3*33=99</code>个bit来保存,但如果我们根据字符出现的概率来编码,也就是出现频率较高的字符,使用较短的编码,如下:</p><table class="gridtable" style="width:400px;text-align:center;border-collapse:collapse;"><tbody><tr><th style="width:100px;">字符</th><td style="width:60px;">A</td><td style="width:60px;">B</td><td style="width:60px;">C</td><td style="width:60px;">D</td><td style="width:60px;">E</td></tr><tr><th>编码</th><td>110</td><td>0</td><td>1110</td><td>10</td><td>1111</td></tr></tbody></table><p>那么这段文字共需要<code>3*6+1*15+4*2+2*9+4*1=63</code>个bit来保存,压缩比为63%,哈弗曼编码一般都是使用二叉树来生成的,这样得到的编码符合前缀规则,也就是较短的编码不能够是较长编码的前缀,比如字符&#39;B&#39;使用的编码是&#39;0&#39;,那么其他字符的编码的第一个字符都不能是‘0’。<br> 上面这个编码实例,就是由下面的这颗二叉树生成的。</p><figure><img src="/images/2014/08/hufman7.gif" alt="" tabindex="0" loading="lazy"><figcaption></figcaption></figure><p>我们回到JPEG压缩上,回顾上一节的内容,经过数据量化,我们现在要处理的数据是一串一维数组,举例如下:</p><table class="gridtable" style="width:600px;text-align:center;"><tbody><tr><th style="width:100px;text-align:left;">①原始数据</th><td style="width:500px;"><!----></td></tr></tbody></table> 在实际的压缩过程中,数据中的0出现的概率非常高,所以首先要做的事情,是使用RLE编码对其中的0进行处理,把数据中的非零的数据,以及数据前面0的个数作为一个处理单元。 <table class="gridtable" align="center" style="width:600px;text-align:center;"><tbody><tr><th style="width:100px;text-align:left;">①原始数据</th><td style="width:500px;" colspan="8"><!----></td></tr><tr><th style="text-align:left;"><strong>②RLE编码</strong></th><td>35</td><td>7</td><td>0,0,0,-6</td><td>-2</td><td>0,0,-9</td><td>0,0,…,0,8</td><td>0,0,…,0</td></tr></tbody></table> 如果其中某个单元的0的个数超过16,则需要分成每16个一组,如果最后一个单元全都是0,则使用特殊字符“EOB”表示,EOB意思就是“后面的数据全都是0”, <table class="gridtable" align="center" style="width:600px;text-align:center;"><tbody><tr><th style="width:100px;text-align:left;">①原始数据</th><td style="width:500px;" colspan="8"><!----></td></tr><tr><th style="text-align:left;" rowspan="3"><strong>②RLE编码</strong></th><td>35</td><td>7</td><td>0,0,0,-6</td><td>-2</td><td>0,0,-9</td><td colspan="2">0,0,…,0,8</td><td>0,0,…,0</td></tr><tr><td>35</td><td>7</td><td>0,0,0,-6</td><td>-2</td><td>0,0,-9</td><td>0,0,…,0</td><td>0,0,8</td><td>0,0,…,0</td></tr><tr><td>(0,35)</td><td>(0,7)</td><td>(3,-6)</td><td>(0,-2)</td><td>(2,-9)</td><td>(15,0)</td><td>(2,8)</td><td>EOB</td></tr></tbody></table> 其中(15,0)表示15+1也就是16个0,接下来我们要处理的是括号里右面的数字,这个数字的取值范围在-2047~2047之间,JPEG提供了一张标准的码表用于对这些数字编码: <table class="gridtable" style="width:550px;text-align:center;"><tbody><tr><th style="width:250px;" colspan="2">Value</th><th style="width:50px;">Size</th><th style="width:250px;" colspan="2">Bits </th></tr><tr><td align="center" colspan="2">0</td><td>0</td><td align="center" colspan="2">–</td></tr><tr><td align="right">-1</td><td align="left">1</td><td>1</td><td align="right">0</td><td align="left">1</td></tr><tr><td align="right">-3,-2</td><td align="left">2,3</td><td>2</td><td align="right">00,01</td><td align="left">10,11</td></tr><tr><td align="right">-7,-6,-5,-4</td><td align="left">4,5,6,7</td><td>3</td><td align="right">000,001,010,011</td><td align="left">100,101,110,111</td></tr><tr><td align="right">-15,…,-8</td><td align="left">8,…,15</td><td>4</td><td align="right">0000,…,0111</td><td align="left">1000,…,1111</td></tr><tr><td align="right">-31,…,-16</td><td align="left">16,…,31</td><td>5</td><td align="right">0 0000,…,0 1111</td><td align="left">1 0000,…,1 1111 </td></tr><tr><td align="right">-63,…,-32</td><td align="left">32,…,63</td><td>6</td><td align="right">00 0000,…</td><td align="left">…,11 1111 </td></tr><tr><td align="right">-127,…,-64</td><td align="left">64,…,127</td><td>7</td><td align="right">000 0000,…</td><td align="left">…,111 1111 </td></tr><tr><td align="right">-255,…,-128</td><td align="left">128,…,255</td><td>8</td><td align="right">0000 0000,…</td><td align="left">…,1111 1111 </td></tr><tr><td align="right">-511,…,-256</td><td align="left">256,…,511</td><td>9</td><td align="right">0 0000 0000,…</td><td align="left">…,1 1111 1111 </td></tr><tr><td align="right">-1023,…,-512</td><td align="left">512,…,1023</td><td>10</td><td align="right">00 0000 0000,…</td><td align="left">…,11 1111 1111 </td></tr><tr><td align="right">-2047,…,-1024</td><td align="left">1024,…,2047</td><td>11</td><td align="right">000 0000 0000,…</td><td align="left">…,111 1111 1111</td></tr></tbody></table> 举例来说,第一个单元中的“35”这个数字,在表中的位置是长度为6的那组,所对应的bit码是“100011”,而“-6”的编码是”001″,由于这种编码附带长度信息,所以我们的数据变成了如下的格式。 <table class="gridtable" align="center" style="width:800px;text-align:center;"><tbody><tr><th style="width:100px;text-align:left;">①原始数据</th><td style="width:700px;" colspan="8"><!----></td></tr><tr><th style="text-align:left;" rowspan="3"><strong>②RLE编码</strong></th><td>35</td><td>7</td><td>0,0,0,-6</td><td>-2</td><td>0,0,-9</td><td colspan="2">0,0,…,0,8</td><td>0,0,…,0</td></tr><tr style="padding:3px 3px;"><td>35</td><td>7</td><td>0,0,0,-6</td><td>-2</td><td>0,0,-9</td><td>0,0,…,0</td><td>0,0,8</td><td>0,0,…,0</td></tr><tr><td>(0,35)</td><td>(0,7)</td><td>(3,-6)</td><td>(0,-2)</td><td>(2,-9)</td><td>(15,0)</td><td>(2,8)</td><td>EOB</td></tr><tr><th style="text-align:left;"><strong>③BIT编码</strong></th><td>(0,6, <em><b>100011</b></em>)</td><td>(0,3, <em><b>111</b></em>)</td><td>(3,3, <em><b>001</b></em>)</td><td>(0,2, <em><b>01</b></em>)</td><td>(2,4, <em><b>0110</b></em>)</td><td>(15,-)</td><td>(2,4, <em><b>1000</b></em>)</td><td>EOB</td></tr></tbody></table> 括号中前两个数字分都在0~15之间,所以这两个数可以合并成一个byte,高四位是前面0的个数,后四位是后面数字的位数。 <table class="gridtable" align="center" style="width:800px;text-align:center;"><tbody><tr><th style="width:100px;text-align:left;">①原始数据</th><td style="width:700px;" colspan="8"><!----></td></tr><tr><th style="text-align:left;" rowspan="3"><strong>②RLE编码</strong></th><td>35</td><td>7</td><td>0,0,0,-6</td><td>-2</td><td>0,0,-9</td><td colspan="2">0,0,…,0,8</td><td>0,0,…,0</td></tr><tr style="padding:3px 3px;"><td>35</td><td>7</td><td>0,0,0,-6</td><td>-2</td><td>0,0,-9</td><td>0,0,…,0</td><td>0,0,8</td><td>0,0,…,0</td></tr><tr><td>(0,35)</td><td>(0,7)</td><td>(3,-6)</td><td>(0,-2)</td><td>(2,-9)</td><td>(15,0)</td><td>(2,8)</td><td>EOB</td></tr><tr><th style="text-align:left;" rowspan="2"><strong>③BIT编码</strong></th><td>(0,6, <em><b>100011</b></em>)</td><td>(0,3, <em><b>111</b></em>)</td><td>(3,3, <em><b>001</b></em>)</td><td>(0,2, <em><b>01</b></em>)</td><td>(2,4, <em><b>0110</b></em>)</td><td>(15,-)</td><td>(2,4, <em><b>1000</b></em>)</td><td>EOB</td></tr><tr><td>(0x6,<em><b>100011</b></em>)</td><td>(0x3,<em><b>111</b></em>)</td><td>(0x33,<em><b>001</b></em>)</td><td>(0x2,<em><b>01</b></em>)</td><td>(0x24,<em><b>0110</b></em>)</td><td>(0xF0,-)</td><td>(0x24,<em><b>1000</b></em>)</td><td>EOB</td></tr></tbody></table> 对于括号前面的数字的编码,就要使用到我们提到的哈弗曼编码了,比如下面这张表,就是一张针对数据中的第一个单元,也就是直流(DC)部分的哈弗曼表,由于直流部分没有前置的0,所以取值范围在0~15之间。 <table class="gridtable" style="width:300px;text-align:left;"><tbody><tr><th style="width:50px;">Length</th><th style="width:80px;">Value</th><th style="width:170px;">Bits</th></tr><tr><td>3 bits </td><td>04<br>05<br>03<br>02<br>06<br>01<br>00 (EOB) </td><td>000<br>001<br>010<br>011<br>100<br>101<br>110</td></tr><tr><td>4 bits </td><td>07</td><td>1110</td></tr><tr><td>5 bits </td><td>08</td><td>1111 0</td></tr><tr><td>6 bits </td><td>09</td><td>1111 10</td></tr><tr><td>7 bits </td><td>0A</td><td>1111 110 </td></tr><tr><td>8 bits </td><td>0B</td><td>1111 1110 </td></tr></tbody></table> 举例来说,示例中的DC部分的数据是0x06,对应的二进制编码是“100”,而对于后面的交流部分,取值范围在0~255之间,所以对应的哈弗曼表会更大一些 <table class="gridtable" style="width:300px;text-align:left;"><tbody><tr><th style="width:50px;">Length</th><th style="width:80px;">Value</th><th style="width:170px;">Bits</th></tr><tr><td>2 bits </td><td>01<br>02</td><td>00<br>01</td></tr><tr><td>3 bits </td><td>03</td><td>100</td></tr><tr><td>4 bits </td><td>00 (EOB)<br>04<br>11</td><td>1010<br>1011<br>1100</td></tr><tr><td>5 bits </td><td>05<br>12<br>21</td><td>1101 0<br>1101 1<br>1110 0 </td></tr><tr><td>6 bits </td><td>31<br>41</td><td>1110 10<br>1110 11 </td></tr><tr><td>…</td><td>…</td><td>…</td></tr><tr><td>12 bits </td><td>24<br>33<br>62<br>72</td><td>1111 1111 0100<br>1111 1111 0101<br>1111 1111 0110<br>1111 1111 0111</td></tr><tr><td>15 bits</td><td>82</td><td>1111 1111 1000 000</td></tr><tr><td>16 bits </td><td>09<br>…<br>FA</td><td>1111 1111 1000 0010<br>…<br>1111 1111 1111 1110</td></tr></tbody></table> 这样经过哈弗曼编码,并且序列化后,最终数据成为如下形式 <table class="gridtable" style="width:1000px;text-align:center;"><tbody><tr><th style="width:100px;text-align:left;">①原始数据</th><td style="width:900px;" colspan="14"><!----></td></tr><tr><th rowspan="3" style="text-align:left;"><strong>②RLE编码</strong></th><td colspan="2">35</td><td colspan="2">7</td><td colspan="2">0,0,0,-6</td><td colspan="2">-2</td><td colspan="2">0,0,-9</td><td colspan="3">0,0,…,0,8</td><td>0,0,…,0</td></tr><tr style="padding:3px 3px;"><td colspan="2">35</td><td colspan="2">7</td><td colspan="2">0,0,0,-6</td><td colspan="2">-2</td><td colspan="2">0,0,-9</td><td>0,0,…,0</td><td colspan="2">0,0,8</td><td>0,0,…,0</td></tr><tr><td colspan="2">(0,35)</td><td colspan="2">(0,7)</td><td colspan="2">(3,-6)</td><td colspan="2">(0,-2)</td><td colspan="2">(2,-9)</td><td>(15,0)</td><td colspan="2">(2,8)</td><td>EOB</td></tr><tr><th style="text-align:left;" rowspan="2"><strong>③BIT编码</strong></th><td colspan="2">(0,6, <em><b>100011</b></em>)</td><td colspan="2">(0,3, <em><b>111</b></em>)</td><td colspan="2">(3,3, <em><b>001</b></em>)</td><td colspan="2">(0,2, <em><b>01</b></em>)</td><td colspan="2">(2,4, <em><b>0110</b></em>)</td><td>(15,-)</td><td colspan="2">(2,4, <em><b>1000</b></em>)</td><td>EOB</td></tr><tr><td colspan="2">(0x6,<em><b>100011</b></em>)</td><td colspan="2">(0x3,<em><b>111</b></em>)</td><td colspan="2">(0x33,<em><b>001</b></em>)</td><td colspan="2">(0x2,<em><b>01</b></em>)</td><td colspan="2">(0x24,<em><b>0110</b></em>)</td><td>0xF0</td><td colspan="2">(0x24,<em><b>1000</b></em>)</td><td>EOB</td></tr><tr><th style="text-align:left;"><strong>④哈弗曼编码</strong></th><td><em><b>100</b></em></td><td><em><b>100011</b></em></td><td><em><b>100</b></em></td><td><em><b>111</b></em></td><td><em><b>1111 1111 0101</b></em></td><td><em><b>001</b></em></td><td><em><b>01</b></em></td><td><em><b>01</b></em></td><td><em><b>1111 1111 0100</b></em></td><td><em><b>0110</b></em></td><td><em><b>1111 1111 001</b></em></td><td><em><b>1111 1111 0100</b></em></td><td><em><b>1000</b></em></td><td><em><b>1010</b></em></td></tr><tr><th style="text-align:left;" rowspan="2">⑤序列化</th><td colspan="14"><!----></td></tr><tr><td colspan="14"><!----></td></tr></tbody></table></div><!----><!----><!----></div><footer class="vp-page-meta"><!----><div class="vp-meta-item git-info"><!----><!----></div></footer><nav class="vp-page-nav"><a class="route-link auto-link prev" href="/blog/2025/02/JPEG003.html" aria-label="JPEG算法解密(三)"><div class="hint"><span class="arrow start"></span>上一页</div><div class="link"><!---->JPEG算法解密(三)</div></a><a class="route-link auto-link next" href="/blog/2025/02/JPEG005.html" aria-label="JPEG算法解密(五)"><div class="hint">下一页<span class="arrow end"></span></div><div class="link">JPEG算法解密(五)<!----></div></a></nav><!----><!----><!--]--></main><!--]--><footer class="vp-footer-wrapper" vp-footer><div class="vp-footer">使用 <a href="https://theme-hope.vuejs.press/zh/" target="_blank">VuePress Theme Hope</a> 主题 | <a href="https://beian.miit.gov.cn/" target="_blank">京ICP备16018986号-1</a></div><!----></footer></div><!--]--><!--]--><!--[--><!----><!--[--><!--]--><!--]--><!--]--></div>
<script type="module" src="/assets/app-DlommLbD.js" defer></script>
</body>
</html>