summaryrefslogtreecommitdiffhomepage
path: root/vhosts/blog/public/posts/2023-04-01
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2025-03-29 00:47:55 +0900
committernsfisis <nsfisis@gmail.com>2025-03-29 00:55:14 +0900
commitd30dfc89bf1b673b2fdc0638766b930adaec228c (patch)
tree739d8826451947adfeb526ef1adeb1db397a9af4 /vhosts/blog/public/posts/2023-04-01
parentf65ec15aaf8fc46685c39d721cab82f64baead8c (diff)
downloadnsfisis.dev-d30dfc89bf1b673b2fdc0638766b930adaec228c.tar.gz
nsfisis.dev-d30dfc89bf1b673b2fdc0638766b930adaec228c.tar.zst
nsfisis.dev-d30dfc89bf1b673b2fdc0638766b930adaec228c.zip
feat(blog/nuldoc): migrate syntax highlighter from highlight.js to shiki.js
Diffstat (limited to 'vhosts/blog/public/posts/2023-04-01')
-rw-r--r--vhosts/blog/public/posts/2023-04-01/implementation-of-minimal-png-image-encoder/index.html707
1 files changed, 363 insertions, 344 deletions
diff --git a/vhosts/blog/public/posts/2023-04-01/implementation-of-minimal-png-image-encoder/index.html b/vhosts/blog/public/posts/2023-04-01/implementation-of-minimal-png-image-encoder/index.html
index 4255b561..11831bdf 100644
--- a/vhosts/blog/public/posts/2023-04-01/implementation-of-minimal-png-image-encoder/index.html
+++ b/vhosts/blog/public/posts/2023-04-01/implementation-of-minimal-png-image-encoder/index.html
@@ -13,8 +13,7 @@
<meta property="og:locale" content="ja_JP">
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<title>PNG 画像の最小構成エンコーダを実装する|REPL: Rest-Eat-Program Loop</title>
- <link rel="stylesheet" href="/style.css?h=79020a898c7052f79b32e90376a4497d">
- <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b">
+ <link rel="stylesheet" href="/style.css?h=60eb349e583f5bd51518a7eb98598043">
</head>
<body class="single">
<header class="header">
@@ -98,44 +97,46 @@
以下のソースコードをベースにする。今回 PNG のデコーダは扱わないので、読み込みには Go の標準ライブラリ <code>image/png</code> を用いる。
</p>
- <pre class="highlight" language="go"><code class="highlight"><span class="hljs-keyword">package</span> main
-
-<span class="hljs-keyword">import</span> (
- <span class="hljs-string">&quot;image&quot;</span>
- _ <span class="hljs-string">&quot;image/png&quot;</span>
- <span class="hljs-string">&quot;io&quot;</span>
- <span class="hljs-string">&quot;os&quot;</span>
-)
-
-<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
- inFile, err := os.Open(<span class="hljs-string">&quot;input.png&quot;</span>)
- <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
- <span class="hljs-built_in">panic</span>(err)
- }
- <span class="hljs-keyword">defer</span> inFile.Close()
-
- img, _, err := image.Decode(inFile)
- <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
- <span class="hljs-built_in">panic</span>(err)
- }
-
- outFile, err := os.Create(<span class="hljs-string">&quot;output.png&quot;</span>)
- <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
- <span class="hljs-built_in">panic</span>(err)
- }
- <span class="hljs-keyword">defer</span> outFile.Close()
-
- writePng(outFile, img)
-}
-
-<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">writePng</span><span class="hljs-params">(w io.Writer, img image.Image)</span></span> {
- width := <span class="hljs-type">uint32</span>(img.Bounds().Dx())
- height := <span class="hljs-type">uint32</span>(img.Bounds().Dy())
- writeSignature(w)
- writeChunkIhdr(w, width, height)
- writeChunkIdat(w, width, height, img)
- writeChunkIend(w)
-}</code></pre>
+ <div class="codeblock" language="go">
+ <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">package</span><span style="color:#6F42C1"> main</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49">import</span><span style="color:#24292E"> (</span></span>
+<span class="line"><span style="color:#032F62"> "</span><span style="color:#6F42C1">image</span><span style="color:#032F62">"</span></span>
+<span class="line"><span style="color:#24292E"> _ </span><span style="color:#032F62">"</span><span style="color:#6F42C1">image/png</span><span style="color:#032F62">"</span></span>
+<span class="line"><span style="color:#032F62"> "</span><span style="color:#6F42C1">io</span><span style="color:#032F62">"</span></span>
+<span class="line"><span style="color:#032F62"> "</span><span style="color:#6F42C1">os</span><span style="color:#032F62">"</span></span>
+<span class="line"><span style="color:#24292E">)</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> main</span><span style="color:#24292E">() {</span></span>
+<span class="line"><span style="color:#24292E"> inFile, err </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> os.</span><span style="color:#6F42C1">Open</span><span style="color:#24292E">(</span><span style="color:#032F62">"input.png"</span><span style="color:#24292E">)</span></span>
+<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> err </span><span style="color:#D73A49">!=</span><span style="color:#005CC5"> nil</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#6F42C1"> panic</span><span style="color:#24292E">(err)</span></span>
+<span class="line"><span style="color:#24292E"> }</span></span>
+<span class="line"><span style="color:#D73A49"> defer</span><span style="color:#24292E"> inFile.</span><span style="color:#6F42C1">Close</span><span style="color:#24292E">()</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#24292E"> img, _, err </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> image.</span><span style="color:#6F42C1">Decode</span><span style="color:#24292E">(inFile)</span></span>
+<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> err </span><span style="color:#D73A49">!=</span><span style="color:#005CC5"> nil</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#6F42C1"> panic</span><span style="color:#24292E">(err)</span></span>
+<span class="line"><span style="color:#24292E"> }</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#24292E"> outFile, err </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> os.</span><span style="color:#6F42C1">Create</span><span style="color:#24292E">(</span><span style="color:#032F62">"output.png"</span><span style="color:#24292E">)</span></span>
+<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> err </span><span style="color:#D73A49">!=</span><span style="color:#005CC5"> nil</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#6F42C1"> panic</span><span style="color:#24292E">(err)</span></span>
+<span class="line"><span style="color:#24292E"> }</span></span>
+<span class="line"><span style="color:#D73A49"> defer</span><span style="color:#24292E"> outFile.</span><span style="color:#6F42C1">Close</span><span style="color:#24292E">()</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#6F42C1"> writePng</span><span style="color:#24292E">(outFile, img)</span></span>
+<span class="line"><span style="color:#24292E">}</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> writePng</span><span style="color:#24292E">(</span><span style="color:#E36209">w</span><span style="color:#6F42C1"> io</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Writer</span><span style="color:#24292E">, </span><span style="color:#E36209">img</span><span style="color:#6F42C1"> image</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Image</span><span style="color:#24292E">) {</span></span>
+<span class="line"><span style="color:#24292E"> width </span><span style="color:#D73A49">:=</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">(img.</span><span style="color:#6F42C1">Bounds</span><span style="color:#24292E">().</span><span style="color:#6F42C1">Dx</span><span style="color:#24292E">())</span></span>
+<span class="line"><span style="color:#24292E"> height </span><span style="color:#D73A49">:=</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">(img.</span><span style="color:#6F42C1">Bounds</span><span style="color:#24292E">().</span><span style="color:#6F42C1">Dy</span><span style="color:#24292E">())</span></span>
+<span class="line"><span style="color:#6F42C1"> writeSignature</span><span style="color:#24292E">(w)</span></span>
+<span class="line"><span style="color:#6F42C1"> writeChunkIhdr</span><span style="color:#24292E">(w, width, height)</span></span>
+<span class="line"><span style="color:#6F42C1"> writeChunkIdat</span><span style="color:#24292E">(w, width, height, img)</span></span>
+<span class="line"><span style="color:#6F42C1"> writeChunkIend</span><span style="color:#24292E">(w)</span></span>
+<span class="line"><span style="color:#24292E">}</span></span></code></pre>
+ </div>
<p>
以降は、<code>writeSignature</code> や <code>writeChunkIhdr</code> などを実装していく。
@@ -189,21 +190,23 @@
<code>writeSignature</code> の実装はこちら:
</p>
- <pre class="highlight" language="go"><code class="highlight"><span class="hljs-keyword">import</span> <span class="hljs-string">&quot;encoding/binary&quot;</span>
-
-<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">writeSignature</span><span class="hljs-params">(w io.Writer)</span></span> {
- sig := [<span class="hljs-number">8</span>]<span class="hljs-type">uint8</span>{
- <span class="hljs-number">0x89</span>,
- <span class="hljs-number">0x50</span>, <span class="hljs-comment">// P</span>
- <span class="hljs-number">0x4E</span>, <span class="hljs-comment">// N</span>
- <span class="hljs-number">0x47</span>, <span class="hljs-comment">// G</span>
- <span class="hljs-number">0x0D</span>, <span class="hljs-comment">// CR</span>
- <span class="hljs-number">0x0A</span>, <span class="hljs-comment">// LF</span>
- <span class="hljs-number">0x1A</span>, <span class="hljs-comment">// EOF (^Z)</span>
- <span class="hljs-number">0x0A</span>, <span class="hljs-comment">// LF</span>
- }
- binary.Write(w, binary.BigEndian, sig)
-}</code></pre>
+ <div class="codeblock" language="go">
+ <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">import</span><span style="color:#032F62"> "</span><span style="color:#6F42C1">encoding/binary</span><span style="color:#032F62">"</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> writeSignature</span><span style="color:#24292E">(</span><span style="color:#E36209">w</span><span style="color:#6F42C1"> io</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Writer</span><span style="color:#24292E">) {</span></span>
+<span class="line"><span style="color:#24292E"> sig </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> [</span><span style="color:#005CC5">8</span><span style="color:#24292E">]</span><span style="color:#D73A49">uint8</span><span style="color:#24292E">{</span></span>
+<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">89</span><span style="color:#24292E">,</span></span>
+<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">50</span><span style="color:#24292E">, </span><span style="color:#6A737D">// P</span></span>
+<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">4E</span><span style="color:#24292E">, </span><span style="color:#6A737D">// N</span></span>
+<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">47</span><span style="color:#24292E">, </span><span style="color:#6A737D">// G</span></span>
+<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">0D</span><span style="color:#24292E">, </span><span style="color:#6A737D">// CR</span></span>
+<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">0A</span><span style="color:#24292E">, </span><span style="color:#6A737D">// LF</span></span>
+<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">1A</span><span style="color:#24292E">, </span><span style="color:#6A737D">// EOF (^Z)</span></span>
+<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">0A</span><span style="color:#24292E">, </span><span style="color:#6A737D">// LF</span></span>
+<span class="line"><span style="color:#24292E"> }</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(w, binary.BigEndian, sig)</span></span>
+<span class="line"><span style="color:#24292E">}</span></span></code></pre>
+ </div>
<p>
<code>encoding/binary</code> パッケージの <code>binary.Write</code> を使い、固定の 8 バイトを書き込む。
@@ -238,55 +241,59 @@
CRC (Cyclic Redundancy Check) は誤り検出符号の一種。Go 言語では <code>hash/crc32</code> パッケージにあるが、今回はこれも自前で実装する。PNG の仕様書に C 言語のサンプルコードが載っている (<a href="https://www.w3.org/TR/png/#D-CRCAppendix" rel="noreferrer" target="_blank">D. Sample CRC implementation</a>) ので、これを Go に移植する。
</p>
- <pre class="highlight" language="go"><code class="highlight"><span class="hljs-keyword">var</span> (
- crcTable [<span class="hljs-number">256</span>]<span class="hljs-type">uint32</span>
- crcTableComputed <span class="hljs-type">bool</span>
-)
-
-<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">makeCrcTable</span><span class="hljs-params">()</span></span> {
- <span class="hljs-keyword">for</span> n := <span class="hljs-number">0</span>; n &lt; <span class="hljs-number">256</span>; n++ {
- c := <span class="hljs-type">uint32</span>(n)
- <span class="hljs-keyword">for</span> k := <span class="hljs-number">0</span>; k &lt; <span class="hljs-number">8</span>; k++ {
- <span class="hljs-keyword">if</span> (c &amp; <span class="hljs-number">1</span>) != <span class="hljs-number">0</span> {
- c = <span class="hljs-number">0xEDB88320</span> ^ (c &gt;&gt; <span class="hljs-number">1</span>)
- } <span class="hljs-keyword">else</span> {
- c = c &gt;&gt; <span class="hljs-number">1</span>
- }
- }
- crcTable[n] = c
- }
- crcTableComputed = <span class="hljs-literal">true</span>
-}
-
-<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">updateCrc</span><span class="hljs-params">(crc <span class="hljs-type">uint32</span>, buf []<span class="hljs-type">byte</span>)</span></span> <span class="hljs-type">uint32</span> {
- <span class="hljs-keyword">if</span> !crcTableComputed {
- makeCrcTable()
- }
-
- c := crc
- <span class="hljs-keyword">for</span> n := <span class="hljs-number">0</span>; n &lt; <span class="hljs-built_in">len</span>(buf); n++ {
- c = crcTable[(c^<span class="hljs-type">uint32</span>(buf[n]))&amp;<span class="hljs-number">0xFF</span>] ^ (c &gt;&gt; <span class="hljs-number">8</span>)
- }
- <span class="hljs-keyword">return</span> c
-}
-
-<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">crc</span><span class="hljs-params">(buf []<span class="hljs-type">byte</span>)</span></span> <span class="hljs-type">uint32</span> {
- <span class="hljs-keyword">return</span> updateCrc(<span class="hljs-number">0xFFFFFFFF</span>, buf) ^ <span class="hljs-number">0xFFFFFFFF</span>
-}</code></pre>
+ <div class="codeblock" language="go">
+ <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">var</span><span style="color:#24292E"> (</span></span>
+<span class="line"><span style="color:#24292E"> crcTable [</span><span style="color:#005CC5">256</span><span style="color:#24292E">]</span><span style="color:#D73A49">uint32</span></span>
+<span class="line"><span style="color:#24292E"> crcTableComputed </span><span style="color:#D73A49">bool</span></span>
+<span class="line"><span style="color:#24292E">)</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> makeCrcTable</span><span style="color:#24292E">() {</span></span>
+<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> n </span><span style="color:#D73A49">:=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">; n </span><span style="color:#D73A49">&#x3C;</span><span style="color:#005CC5"> 256</span><span style="color:#24292E">; n</span><span style="color:#D73A49">++</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#24292E"> c </span><span style="color:#D73A49">:=</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">(n)</span></span>
+<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> k </span><span style="color:#D73A49">:=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">; k </span><span style="color:#D73A49">&#x3C;</span><span style="color:#005CC5"> 8</span><span style="color:#24292E">; k</span><span style="color:#D73A49">++</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> (c </span><span style="color:#D73A49">&#x26;</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">) </span><span style="color:#D73A49">!=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#24292E"> c </span><span style="color:#D73A49">=</span><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">EDB88320</span><span style="color:#D73A49"> ^</span><span style="color:#24292E"> (c </span><span style="color:#D73A49">>></span><span style="color:#005CC5"> 1</span><span style="color:#24292E">)</span></span>
+<span class="line"><span style="color:#24292E"> } </span><span style="color:#D73A49">else</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#24292E"> c </span><span style="color:#D73A49">=</span><span style="color:#24292E"> c </span><span style="color:#D73A49">>></span><span style="color:#005CC5"> 1</span></span>
+<span class="line"><span style="color:#24292E"> }</span></span>
+<span class="line"><span style="color:#24292E"> }</span></span>
+<span class="line"><span style="color:#24292E"> crcTable[n] </span><span style="color:#D73A49">=</span><span style="color:#24292E"> c</span></span>
+<span class="line"><span style="color:#24292E"> }</span></span>
+<span class="line"><span style="color:#24292E"> crcTableComputed </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> true</span></span>
+<span class="line"><span style="color:#24292E">}</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> updateCrc</span><span style="color:#24292E">(</span><span style="color:#E36209">crc</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">, </span><span style="color:#E36209">buf</span><span style="color:#24292E"> []</span><span style="color:#D73A49">byte</span><span style="color:#24292E">) </span><span style="color:#D73A49">uint32</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#D73A49"> if</span><span style="color:#D73A49"> !</span><span style="color:#24292E">crcTableComputed {</span></span>
+<span class="line"><span style="color:#6F42C1"> makeCrcTable</span><span style="color:#24292E">()</span></span>
+<span class="line"><span style="color:#24292E"> }</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#24292E"> c </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> crc</span></span>
+<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> n </span><span style="color:#D73A49">:=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">; n </span><span style="color:#D73A49">&#x3C;</span><span style="color:#6F42C1"> len</span><span style="color:#24292E">(buf); n</span><span style="color:#D73A49">++</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#24292E"> c </span><span style="color:#D73A49">=</span><span style="color:#24292E"> crcTable[(c</span><span style="color:#D73A49">^uint32</span><span style="color:#24292E">(buf[n]))</span><span style="color:#D73A49">&#x26;0x</span><span style="color:#005CC5">FF</span><span style="color:#24292E">] </span><span style="color:#D73A49">^</span><span style="color:#24292E"> (c </span><span style="color:#D73A49">>></span><span style="color:#005CC5"> 8</span><span style="color:#24292E">)</span></span>
+<span class="line"><span style="color:#24292E"> }</span></span>
+<span class="line"><span style="color:#D73A49"> return</span><span style="color:#24292E"> c</span></span>
+<span class="line"><span style="color:#24292E">}</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> crc</span><span style="color:#24292E">(</span><span style="color:#E36209">buf</span><span style="color:#24292E"> []</span><span style="color:#D73A49">byte</span><span style="color:#24292E">) </span><span style="color:#D73A49">uint32</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#D73A49"> return</span><span style="color:#6F42C1"> updateCrc</span><span style="color:#24292E">(</span><span style="color:#D73A49">0x</span><span style="color:#005CC5">FFFFFFFF</span><span style="color:#24292E">, buf) </span><span style="color:#D73A49">^</span><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">FFFFFFFF</span></span>
+<span class="line"><span style="color:#24292E">}</span></span></code></pre>
+ </div>
<p>
できた <code>crc</code> 関数を使って、chunk 一般を書き込む関数も用意しておこう。
</p>
- <pre class="highlight" language="go"><code class="highlight"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">writeChunk</span><span class="hljs-params">(w io.Writer, chunkType <span class="hljs-type">string</span>, data []<span class="hljs-type">byte</span>)</span></span> {
- typeAndData := <span class="hljs-built_in">make</span>([]<span class="hljs-type">byte</span>, <span class="hljs-number">0</span>, <span class="hljs-built_in">len</span>(chunkType)+<span class="hljs-built_in">len</span>(data))
- typeAndData = <span class="hljs-built_in">append</span>(typeAndData, []<span class="hljs-type">byte</span>(chunkType)...)
- typeAndData = <span class="hljs-built_in">append</span>(typeAndData, data...)
-
- binary.Write(w, binary.BigEndian, <span class="hljs-type">uint32</span>(<span class="hljs-built_in">len</span>(data)))
- binary.Write(w, binary.BigEndian, typeAndData)
- binary.Write(w, binary.BigEndian, crc(typeAndData))
-}</code></pre>
+ <div class="codeblock" language="go">
+ <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> writeChunk</span><span style="color:#24292E">(</span><span style="color:#E36209">w</span><span style="color:#6F42C1"> io</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Writer</span><span style="color:#24292E">, </span><span style="color:#E36209">chunkType</span><span style="color:#D73A49"> string</span><span style="color:#24292E">, </span><span style="color:#E36209">data</span><span style="color:#24292E"> []</span><span style="color:#D73A49">byte</span><span style="color:#24292E">) {</span></span>
+<span class="line"><span style="color:#24292E"> typeAndData </span><span style="color:#D73A49">:=</span><span style="color:#6F42C1"> make</span><span style="color:#24292E">([]</span><span style="color:#D73A49">byte</span><span style="color:#24292E">, </span><span style="color:#005CC5">0</span><span style="color:#24292E">, </span><span style="color:#6F42C1">len</span><span style="color:#24292E">(chunkType)</span><span style="color:#D73A49">+</span><span style="color:#6F42C1">len</span><span style="color:#24292E">(data))</span></span>
+<span class="line"><span style="color:#24292E"> typeAndData </span><span style="color:#D73A49">=</span><span style="color:#6F42C1"> append</span><span style="color:#24292E">(typeAndData, []</span><span style="color:#D73A49">byte</span><span style="color:#24292E">(chunkType)</span><span style="color:#D73A49">...</span><span style="color:#24292E">)</span></span>
+<span class="line"><span style="color:#24292E"> typeAndData </span><span style="color:#D73A49">=</span><span style="color:#6F42C1"> append</span><span style="color:#24292E">(typeAndData, data</span><span style="color:#D73A49">...</span><span style="color:#24292E">)</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(w, binary.BigEndian, </span><span style="color:#D73A49">uint32</span><span style="color:#24292E">(</span><span style="color:#6F42C1">len</span><span style="color:#24292E">(data)))</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(w, binary.BigEndian, typeAndData)</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(w, binary.BigEndian, </span><span style="color:#6F42C1">crc</span><span style="color:#24292E">(typeAndData))</span></span>
+<span class="line"><span style="color:#24292E">}</span></span></code></pre>
+ </div>
<p>
仕様どおり、<code>chunkType</code> と <code>data</code> から CRC を計算し、<code>data</code> の長さと合わせて書き込んでいる。PNG では基本的に big endian を使うことに注意する。
@@ -372,20 +379,22 @@
今回ほとんどのデータは決め打ちするので、データに応じて変わるのは width と height だけになる。コードは次のようになる。
</p>
- <pre class="highlight" language="go"><code class="highlight"><span class="hljs-keyword">import</span> <span class="hljs-string">&quot;bytes&quot;</span>
-
-<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">writeChunkIhdr</span><span class="hljs-params">(w io.Writer, width, height <span class="hljs-type">uint32</span>)</span></span> {
- <span class="hljs-keyword">var</span> buf bytes.Buffer
- binary.Write(&amp;buf, binary.BigEndian, width)
- binary.Write(&amp;buf, binary.BigEndian, height)
- binary.Write(&amp;buf, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">8</span>))
- binary.Write(&amp;buf, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">2</span>))
- binary.Write(&amp;buf, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">0</span>))
- binary.Write(&amp;buf, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">0</span>))
- binary.Write(&amp;buf, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">0</span>))
-
- writeChunk(w, <span class="hljs-string">&quot;IHDR&quot;</span>, buf.Bytes())
-}</code></pre>
+ <div class="codeblock" language="go">
+ <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">import</span><span style="color:#032F62"> "</span><span style="color:#6F42C1">bytes</span><span style="color:#032F62">"</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> writeChunkIhdr</span><span style="color:#24292E">(</span><span style="color:#E36209">w</span><span style="color:#6F42C1"> io</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Writer</span><span style="color:#24292E">, </span><span style="color:#E36209">width</span><span style="color:#24292E">, </span><span style="color:#E36209">height</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">) {</span></span>
+<span class="line"><span style="color:#D73A49"> var</span><span style="color:#24292E"> buf </span><span style="color:#6F42C1">bytes</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Buffer</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">buf, binary.BigEndian, width)</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">buf, binary.BigEndian, height)</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#005CC5">8</span><span style="color:#24292E">))</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#005CC5">2</span><span style="color:#24292E">))</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">))</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">))</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">))</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#6F42C1"> writeChunk</span><span style="color:#24292E">(w, </span><span style="color:#032F62">"IHDR"</span><span style="color:#24292E">, buf.</span><span style="color:#6F42C1">Bytes</span><span style="color:#24292E">())</span></span>
+<span class="line"><span style="color:#24292E">}</span></span></code></pre>
+ </div>
</section>
<section id="section--implement-png-encoder--idat-chunk">
@@ -426,22 +435,24 @@
Adler-32 も CRC と同じく誤り検出符号である。こちらも zlib の仕様書に C 言語でサンプルコードが記載されている (<a href="https://www.rfc-editor.org/rfc/rfc1950#section-9" rel="noreferrer" target="_blank">9. Appendix: Sample code</a>) ので、Go に移植する。
</p>
- <pre class="highlight" language="go"><code class="highlight"><span class="hljs-keyword">const</span> adler32Base = <span class="hljs-number">65521</span>
-
-<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">updateAdler32</span><span class="hljs-params">(adler <span class="hljs-type">uint32</span>, buf []<span class="hljs-type">byte</span>)</span></span> <span class="hljs-type">uint32</span> {
- s1 := adler &amp; <span class="hljs-number">0xFFFF</span>
- s2 := (adler &gt;&gt; <span class="hljs-number">16</span>) &amp; <span class="hljs-number">0xFFFF</span>
-
- <span class="hljs-keyword">for</span> n := <span class="hljs-number">0</span>; n &lt; <span class="hljs-built_in">len</span>(buf); n++ {
- s1 = (s1 + <span class="hljs-type">uint32</span>(buf[n])) % adler32Base
- s2 = (s2 + s1) % adler32Base
- }
- <span class="hljs-keyword">return</span> (s2 &lt;&lt; <span class="hljs-number">16</span>) + s1
-}
-
-<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">adler32</span><span class="hljs-params">(buf []<span class="hljs-type">byte</span>)</span></span> <span class="hljs-type">uint32</span> {
- <span class="hljs-keyword">return</span> updateAdler32(<span class="hljs-number">1</span>, buf)
-}</code></pre>
+ <div class="codeblock" language="go">
+ <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">const</span><span style="color:#005CC5"> adler32Base</span><span style="color:#D73A49"> =</span><span style="color:#005CC5"> 65521</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> updateAdler32</span><span style="color:#24292E">(</span><span style="color:#E36209">adler</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">, </span><span style="color:#E36209">buf</span><span style="color:#24292E"> []</span><span style="color:#D73A49">byte</span><span style="color:#24292E">) </span><span style="color:#D73A49">uint32</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#24292E"> s1 </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> adler </span><span style="color:#D73A49">&#x26;</span><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">FFFF</span></span>
+<span class="line"><span style="color:#24292E"> s2 </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> (adler </span><span style="color:#D73A49">>></span><span style="color:#005CC5"> 16</span><span style="color:#24292E">) </span><span style="color:#D73A49">&#x26;</span><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">FFFF</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> n </span><span style="color:#D73A49">:=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">; n </span><span style="color:#D73A49">&#x3C;</span><span style="color:#6F42C1"> len</span><span style="color:#24292E">(buf); n</span><span style="color:#D73A49">++</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#24292E"> s1 </span><span style="color:#D73A49">=</span><span style="color:#24292E"> (s1 </span><span style="color:#D73A49">+</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">(buf[n])) </span><span style="color:#D73A49">%</span><span style="color:#24292E"> adler32Base</span></span>
+<span class="line"><span style="color:#24292E"> s2 </span><span style="color:#D73A49">=</span><span style="color:#24292E"> (s2 </span><span style="color:#D73A49">+</span><span style="color:#24292E"> s1) </span><span style="color:#D73A49">%</span><span style="color:#24292E"> adler32Base</span></span>
+<span class="line"><span style="color:#24292E"> }</span></span>
+<span class="line"><span style="color:#D73A49"> return</span><span style="color:#24292E"> (s2 </span><span style="color:#D73A49">&#x3C;&#x3C;</span><span style="color:#005CC5"> 16</span><span style="color:#24292E">) </span><span style="color:#D73A49">+</span><span style="color:#24292E"> s1</span></span>
+<span class="line"><span style="color:#24292E">}</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> adler32</span><span style="color:#24292E">(</span><span style="color:#E36209">buf</span><span style="color:#24292E"> []</span><span style="color:#D73A49">byte</span><span style="color:#24292E">) </span><span style="color:#D73A49">uint32</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#D73A49"> return</span><span style="color:#6F42C1"> updateAdler32</span><span style="color:#24292E">(</span><span style="color:#005CC5">1</span><span style="color:#24292E">, buf)</span></span>
+<span class="line"><span style="color:#24292E">}</span></span></code></pre>
+ </div>
<p>
「データ」の部分には圧縮したデータが入るのだが、真面目に deflate アルゴリズムを実装する必要はない。Zlib には無圧縮のデータブロックを格納することができるので、これを使う。本来は、データの圧縮効率の悪いランダムなデータをそのまま格納するためのものだが、今回は deflate の実装をサボるために使う。
@@ -473,30 +484,32 @@
実際にこの手抜き zlib を実装したものがこちら:
</p>
- <pre class="highlight" language="go"><code class="highlight"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">encodeZlib</span><span class="hljs-params">(data []<span class="hljs-type">byte</span>)</span></span> []<span class="hljs-type">byte</span> {
- <span class="hljs-keyword">var</span> buf bytes.Buffer
-
- binary.Write(&amp;buf, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">0x78</span>))
- binary.Write(&amp;buf, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">0x01</span>))
- blockSize := <span class="hljs-number">65535</span>
- isFinalBlock := <span class="hljs-literal">false</span>
- <span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; !isFinalBlock; i++ {
- <span class="hljs-keyword">var</span> block []<span class="hljs-type">byte</span>
- <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(data) &lt;= (i+<span class="hljs-number">1</span>)*blockSize {
- block = data[i*blockSize:]
- isFinalBlock = <span class="hljs-literal">true</span>
- } <span class="hljs-keyword">else</span> {
- block = data[i*blockSize : (i+<span class="hljs-number">1</span>)*blockSize]
- }
- binary.Write(&amp;buf, binary.BigEndian, isFinalBlock)
- binary.Write(&amp;buf, binary.LittleEndian, <span class="hljs-type">uint16</span>(<span class="hljs-built_in">len</span>(block)))
- binary.Write(&amp;buf, binary.LittleEndian, <span class="hljs-type">uint16</span>(^<span class="hljs-built_in">len</span>(block)))
- binary.Write(&amp;buf, binary.LittleEndian, block)
- }
- binary.Write(&amp;buf, binary.BigEndian, adler32(data))
-
- <span class="hljs-keyword">return</span> buf.Bytes()
-}</code></pre>
+ <div class="codeblock" language="go">
+ <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> encodeZlib</span><span style="color:#24292E">(</span><span style="color:#E36209">data</span><span style="color:#24292E"> []</span><span style="color:#D73A49">byte</span><span style="color:#24292E">) []</span><span style="color:#D73A49">byte</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#D73A49"> var</span><span style="color:#24292E"> buf </span><span style="color:#6F42C1">bytes</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Buffer</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#D73A49">0x</span><span style="color:#005CC5">78</span><span style="color:#24292E">))</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#D73A49">0x</span><span style="color:#005CC5">01</span><span style="color:#24292E">))</span></span>
+<span class="line"><span style="color:#24292E"> blockSize </span><span style="color:#D73A49">:=</span><span style="color:#005CC5"> 65535</span></span>
+<span class="line"><span style="color:#24292E"> isFinalBlock </span><span style="color:#D73A49">:=</span><span style="color:#005CC5"> false</span></span>
+<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> i </span><span style="color:#D73A49">:=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">; </span><span style="color:#D73A49">!</span><span style="color:#24292E">isFinalBlock; i</span><span style="color:#D73A49">++</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#D73A49"> var</span><span style="color:#24292E"> block []</span><span style="color:#D73A49">byte</span></span>
+<span class="line"><span style="color:#D73A49"> if</span><span style="color:#6F42C1"> len</span><span style="color:#24292E">(data) </span><span style="color:#D73A49">&#x3C;=</span><span style="color:#24292E"> (i</span><span style="color:#D73A49">+</span><span style="color:#005CC5">1</span><span style="color:#24292E">)</span><span style="color:#D73A49">*</span><span style="color:#24292E">blockSize {</span></span>
+<span class="line"><span style="color:#24292E"> block </span><span style="color:#D73A49">=</span><span style="color:#24292E"> data[i</span><span style="color:#D73A49">*</span><span style="color:#24292E">blockSize:]</span></span>
+<span class="line"><span style="color:#24292E"> isFinalBlock </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> true</span></span>
+<span class="line"><span style="color:#24292E"> } </span><span style="color:#D73A49">else</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#24292E"> block </span><span style="color:#D73A49">=</span><span style="color:#24292E"> data[i</span><span style="color:#D73A49">*</span><span style="color:#24292E">blockSize : (i</span><span style="color:#D73A49">+</span><span style="color:#005CC5">1</span><span style="color:#24292E">)</span><span style="color:#D73A49">*</span><span style="color:#24292E">blockSize]</span></span>
+<span class="line"><span style="color:#24292E"> }</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">buf, binary.BigEndian, isFinalBlock)</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">buf, binary.LittleEndian, </span><span style="color:#D73A49">uint16</span><span style="color:#24292E">(</span><span style="color:#6F42C1">len</span><span style="color:#24292E">(block)))</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">buf, binary.LittleEndian, </span><span style="color:#D73A49">uint16</span><span style="color:#24292E">(</span><span style="color:#D73A49">^</span><span style="color:#6F42C1">len</span><span style="color:#24292E">(block)))</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">buf, binary.LittleEndian, block)</span></span>
+<span class="line"><span style="color:#24292E"> }</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#6F42C1">adler32</span><span style="color:#24292E">(data))</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49"> return</span><span style="color:#24292E"> buf.</span><span style="color:#6F42C1">Bytes</span><span style="color:#24292E">()</span></span>
+<span class="line"><span style="color:#24292E">}</span></span></code></pre>
+ </div>
</section>
<section id="section--implement-png-encoder--idat-chunk--image-data">
@@ -513,20 +526,22 @@
先ほどの <code>encodeZlib</code> も使って実際に実装したものがこちら:
</p>
- <pre class="highlight" language="go"><code class="highlight"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">writeChunkIdat</span><span class="hljs-params">(w io.Writer, width, height <span class="hljs-type">uint32</span>, img image.Image)</span></span> {
- <span class="hljs-keyword">var</span> pixels bytes.Buffer
- <span class="hljs-keyword">for</span> y := <span class="hljs-type">uint32</span>(<span class="hljs-number">0</span>); y &lt; height; y++ {
- binary.Write(&amp;pixels, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">0</span>))
- <span class="hljs-keyword">for</span> x := <span class="hljs-type">uint32</span>(<span class="hljs-number">0</span>); x &lt; width; x++ {
- r, g, b, _ := img.At(<span class="hljs-type">int</span>(x), <span class="hljs-type">int</span>(y)).RGBA()
- binary.Write(&amp;pixels, binary.BigEndian, <span class="hljs-type">uint8</span>(r))
- binary.Write(&amp;pixels, binary.BigEndian, <span class="hljs-type">uint8</span>(g))
- binary.Write(&amp;pixels, binary.BigEndian, <span class="hljs-type">uint8</span>(b))
- }
- }
-
- writeChunk(w, <span class="hljs-string">&quot;IDAT&quot;</span>, encodeZlib(pixels.Bytes()))
-}</code></pre>
+ <div class="codeblock" language="go">
+ <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> writeChunkIdat</span><span style="color:#24292E">(</span><span style="color:#E36209">w</span><span style="color:#6F42C1"> io</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Writer</span><span style="color:#24292E">, </span><span style="color:#E36209">width</span><span style="color:#24292E">, </span><span style="color:#E36209">height</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">, </span><span style="color:#E36209">img</span><span style="color:#6F42C1"> image</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Image</span><span style="color:#24292E">) {</span></span>
+<span class="line"><span style="color:#D73A49"> var</span><span style="color:#24292E"> pixels </span><span style="color:#6F42C1">bytes</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Buffer</span></span>
+<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> y </span><span style="color:#D73A49">:=</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">); y </span><span style="color:#D73A49">&#x3C;</span><span style="color:#24292E"> height; y</span><span style="color:#D73A49">++</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">pixels, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">))</span></span>
+<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> x </span><span style="color:#D73A49">:=</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">); x </span><span style="color:#D73A49">&#x3C;</span><span style="color:#24292E"> width; x</span><span style="color:#D73A49">++</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#24292E"> r, g, b, _ </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> img.</span><span style="color:#6F42C1">At</span><span style="color:#24292E">(</span><span style="color:#D73A49">int</span><span style="color:#24292E">(x), </span><span style="color:#D73A49">int</span><span style="color:#24292E">(y)).</span><span style="color:#6F42C1">RGBA</span><span style="color:#24292E">()</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">pixels, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(r))</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">pixels, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(g))</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">pixels, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(b))</span></span>
+<span class="line"><span style="color:#24292E"> }</span></span>
+<span class="line"><span style="color:#24292E"> }</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#6F42C1"> writeChunk</span><span style="color:#24292E">(w, </span><span style="color:#032F62">"IDAT"</span><span style="color:#24292E">, </span><span style="color:#6F42C1">encodeZlib</span><span style="color:#24292E">(pixels.</span><span style="color:#6F42C1">Bytes</span><span style="color:#24292E">()))</span></span>
+<span class="line"><span style="color:#24292E">}</span></span></code></pre>
+ </div>
</section>
</section>
@@ -540,9 +555,11 @@
特に追加のデータはなく、必要なのは chunk type の <code>IEND</code> くらいなので実装は簡単:
</p>
- <pre class="highlight" language="go"><code class="highlight"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">writeChunkIend</span><span class="hljs-params">(w io.Writer)</span></span> {
- writeChunk(w, <span class="hljs-string">&quot;IEND&quot;</span>, <span class="hljs-literal">nil</span>)
-}</code></pre>
+ <div class="codeblock" language="go">
+ <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> writeChunkIend</span><span style="color:#24292E">(</span><span style="color:#E36209">w</span><span style="color:#6F42C1"> io</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Writer</span><span style="color:#24292E">) {</span></span>
+<span class="line"><span style="color:#6F42C1"> writeChunk</span><span style="color:#24292E">(w, </span><span style="color:#032F62">"IEND"</span><span style="color:#24292E">, </span><span style="color:#005CC5">nil</span><span style="color:#24292E">)</span></span>
+<span class="line"><span style="color:#24292E">}</span></span></code></pre>
+ </div>
</section>
</section>
@@ -552,180 +569,182 @@
最後に全ソースコードを再掲しておく。
</p>
- <pre class="highlight" language="go"><code class="highlight"><span class="hljs-keyword">package</span> main
-
-<span class="hljs-keyword">import</span> (
- <span class="hljs-string">&quot;bytes&quot;</span>
- <span class="hljs-string">&quot;encoding/binary&quot;</span>
- <span class="hljs-string">&quot;image&quot;</span>
- _ <span class="hljs-string">&quot;image/png&quot;</span>
- <span class="hljs-string">&quot;io&quot;</span>
- <span class="hljs-string">&quot;os&quot;</span>
-)
-
-<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
- inFile, err := os.Open(<span class="hljs-string">&quot;input.png&quot;</span>)
- <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
- <span class="hljs-built_in">panic</span>(err)
- }
- <span class="hljs-keyword">defer</span> inFile.Close()
-
- img, _, err := image.Decode(inFile)
- <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
- <span class="hljs-built_in">panic</span>(err)
- }
-
- outFile, err := os.Create(<span class="hljs-string">&quot;output.png&quot;</span>)
- <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
- <span class="hljs-built_in">panic</span>(err)
- }
- <span class="hljs-keyword">defer</span> outFile.Close()
-
- writePng(outFile, img)
-}
-
-<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">writePng</span><span class="hljs-params">(w io.Writer, img image.Image)</span></span> {
- width := <span class="hljs-type">uint32</span>(img.Bounds().Dx())
- height := <span class="hljs-type">uint32</span>(img.Bounds().Dy())
- writeSignature(w)
- writeChunkIhdr(w, width, height)
- writeChunkIdat(w, width, height, img)
- writeChunkIend(w)
-}
-
-<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">writeSignature</span><span class="hljs-params">(w io.Writer)</span></span> {
- sig := [<span class="hljs-number">8</span>]<span class="hljs-type">uint8</span>{
- <span class="hljs-number">0x89</span>,
- <span class="hljs-number">0x50</span>, <span class="hljs-comment">// P</span>
- <span class="hljs-number">0x4E</span>, <span class="hljs-comment">// N</span>
- <span class="hljs-number">0x47</span>, <span class="hljs-comment">// G</span>
- <span class="hljs-number">0x0D</span>, <span class="hljs-comment">// CR</span>
- <span class="hljs-number">0x0A</span>, <span class="hljs-comment">// LF</span>
- <span class="hljs-number">0x1A</span>, <span class="hljs-comment">// EOF (^Z)</span>
- <span class="hljs-number">0x0A</span>, <span class="hljs-comment">// LF</span>
- }
- binary.Write(w, binary.BigEndian, sig)
-}
-
-<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">writeChunkIhdr</span><span class="hljs-params">(w io.Writer, width, height <span class="hljs-type">uint32</span>)</span></span> {
- <span class="hljs-keyword">var</span> buf bytes.Buffer
- binary.Write(&amp;buf, binary.BigEndian, width)
- binary.Write(&amp;buf, binary.BigEndian, height)
- binary.Write(&amp;buf, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">8</span>))
- binary.Write(&amp;buf, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">2</span>))
- binary.Write(&amp;buf, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">0</span>))
- binary.Write(&amp;buf, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">0</span>))
- binary.Write(&amp;buf, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">0</span>))
-
- writeChunk(w, <span class="hljs-string">&quot;IHDR&quot;</span>, buf.Bytes())
-}
-
-<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">writeChunkIdat</span><span class="hljs-params">(w io.Writer, width, height <span class="hljs-type">uint32</span>, img image.Image)</span></span> {
- <span class="hljs-keyword">var</span> pixels bytes.Buffer
- <span class="hljs-keyword">for</span> y := <span class="hljs-type">uint32</span>(<span class="hljs-number">0</span>); y &lt; height; y++ {
- binary.Write(&amp;pixels, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">0</span>))
- <span class="hljs-keyword">for</span> x := <span class="hljs-type">uint32</span>(<span class="hljs-number">0</span>); x &lt; width; x++ {
- r, g, b, _ := img.At(<span class="hljs-type">int</span>(x), <span class="hljs-type">int</span>(y)).RGBA()
- binary.Write(&amp;pixels, binary.BigEndian, <span class="hljs-type">uint8</span>(r))
- binary.Write(&amp;pixels, binary.BigEndian, <span class="hljs-type">uint8</span>(g))
- binary.Write(&amp;pixels, binary.BigEndian, <span class="hljs-type">uint8</span>(b))
- }
- }
-
- writeChunk(w, <span class="hljs-string">&quot;IDAT&quot;</span>, encodeZlib(pixels.Bytes()))
-}
-
-<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">encodeZlib</span><span class="hljs-params">(data []<span class="hljs-type">byte</span>)</span></span> []<span class="hljs-type">byte</span> {
- <span class="hljs-keyword">var</span> buf bytes.Buffer
-
- binary.Write(&amp;buf, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">0x78</span>))
- binary.Write(&amp;buf, binary.BigEndian, <span class="hljs-type">uint8</span>(<span class="hljs-number">0x01</span>))
- blockSize := <span class="hljs-number">65535</span>
- isFinalBlock := <span class="hljs-literal">false</span>
- <span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; !isFinalBlock; i++ {
- <span class="hljs-keyword">var</span> block []<span class="hljs-type">byte</span>
- <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(data) &lt;= (i+<span class="hljs-number">1</span>)*blockSize {
- block = data[i*blockSize:]
- isFinalBlock = <span class="hljs-literal">true</span>
- } <span class="hljs-keyword">else</span> {
- block = data[i*blockSize : (i+<span class="hljs-number">1</span>)*blockSize]
- }
- binary.Write(&amp;buf, binary.BigEndian, isFinalBlock)
- binary.Write(&amp;buf, binary.LittleEndian, <span class="hljs-type">uint16</span>(<span class="hljs-built_in">len</span>(block)))
- binary.Write(&amp;buf, binary.LittleEndian, <span class="hljs-type">uint16</span>(^<span class="hljs-built_in">len</span>(block)))
- binary.Write(&amp;buf, binary.LittleEndian, block)
- }
- binary.Write(&amp;buf, binary.BigEndian, adler32(data))
-
- <span class="hljs-keyword">return</span> buf.Bytes()
-}
-
-<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">writeChunkIend</span><span class="hljs-params">(w io.Writer)</span></span> {
- writeChunk(w, <span class="hljs-string">&quot;IEND&quot;</span>, <span class="hljs-literal">nil</span>)
-}
-
-<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">writeChunk</span><span class="hljs-params">(w io.Writer, chunkType <span class="hljs-type">string</span>, data []<span class="hljs-type">byte</span>)</span></span> {
- typeAndData := <span class="hljs-built_in">make</span>([]<span class="hljs-type">byte</span>, <span class="hljs-number">0</span>, <span class="hljs-built_in">len</span>(chunkType)+<span class="hljs-built_in">len</span>(data))
- typeAndData = <span class="hljs-built_in">append</span>(typeAndData, []<span class="hljs-type">byte</span>(chunkType)...)
- typeAndData = <span class="hljs-built_in">append</span>(typeAndData, data...)
-
- binary.Write(w, binary.BigEndian, <span class="hljs-type">uint32</span>(<span class="hljs-built_in">len</span>(data)))
- binary.Write(w, binary.BigEndian, typeAndData)
- binary.Write(w, binary.BigEndian, crc(typeAndData))
-}
-
-<span class="hljs-keyword">var</span> (
- crcTable [<span class="hljs-number">256</span>]<span class="hljs-type">uint32</span>
- crcTableComputed <span class="hljs-type">bool</span>
-)
-
-<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">makeCrcTable</span><span class="hljs-params">()</span></span> {
- <span class="hljs-keyword">for</span> n := <span class="hljs-number">0</span>; n &lt; <span class="hljs-number">256</span>; n++ {
- c := <span class="hljs-type">uint32</span>(n)
- <span class="hljs-keyword">for</span> k := <span class="hljs-number">0</span>; k &lt; <span class="hljs-number">8</span>; k++ {
- <span class="hljs-keyword">if</span> (c &amp; <span class="hljs-number">1</span>) != <span class="hljs-number">0</span> {
- c = <span class="hljs-number">0xEDB88320</span> ^ (c &gt;&gt; <span class="hljs-number">1</span>)
- } <span class="hljs-keyword">else</span> {
- c = c &gt;&gt; <span class="hljs-number">1</span>
- }
- }
- crcTable[n] = c
- }
- crcTableComputed = <span class="hljs-literal">true</span>
-}
-
-<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">updateCrc</span><span class="hljs-params">(crc <span class="hljs-type">uint32</span>, buf []<span class="hljs-type">byte</span>)</span></span> <span class="hljs-type">uint32</span> {
- <span class="hljs-keyword">if</span> !crcTableComputed {
- makeCrcTable()
- }
-
- c := crc
- <span class="hljs-keyword">for</span> n := <span class="hljs-number">0</span>; n &lt; <span class="hljs-built_in">len</span>(buf); n++ {
- c = crcTable[(c^<span class="hljs-type">uint32</span>(buf[n]))&amp;<span class="hljs-number">0xFF</span>] ^ (c &gt;&gt; <span class="hljs-number">8</span>)
- }
- <span class="hljs-keyword">return</span> c
-}
-
-<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">crc</span><span class="hljs-params">(buf []<span class="hljs-type">byte</span>)</span></span> <span class="hljs-type">uint32</span> {
- <span class="hljs-keyword">return</span> updateCrc(<span class="hljs-number">0xFFFFFFFF</span>, buf) ^ <span class="hljs-number">0xFFFFFFFF</span>
-}
-
-<span class="hljs-keyword">const</span> adler32Base = <span class="hljs-number">65521</span>
-
-<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">updateAdler32</span><span class="hljs-params">(adler <span class="hljs-type">uint32</span>, buf []<span class="hljs-type">byte</span>)</span></span> <span class="hljs-type">uint32</span> {
- s1 := adler &amp; <span class="hljs-number">0xFFFF</span>
- s2 := (adler &gt;&gt; <span class="hljs-number">16</span>) &amp; <span class="hljs-number">0xFFFF</span>
-
- <span class="hljs-keyword">for</span> n := <span class="hljs-number">0</span>; n &lt; <span class="hljs-built_in">len</span>(buf); n++ {
- s1 = (s1 + <span class="hljs-type">uint32</span>(buf[n])) % adler32Base
- s2 = (s2 + s1) % adler32Base
- }
- <span class="hljs-keyword">return</span> (s2 &lt;&lt; <span class="hljs-number">16</span>) + s1
-}
-
-<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">adler32</span><span class="hljs-params">(buf []<span class="hljs-type">byte</span>)</span></span> <span class="hljs-type">uint32</span> {
- <span class="hljs-keyword">return</span> updateAdler32(<span class="hljs-number">1</span>, buf)
-}</code></pre>
+ <div class="codeblock" language="go">
+ <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">package</span><span style="color:#6F42C1"> main</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49">import</span><span style="color:#24292E"> (</span></span>
+<span class="line"><span style="color:#032F62"> "</span><span style="color:#6F42C1">bytes</span><span style="color:#032F62">"</span></span>
+<span class="line"><span style="color:#032F62"> "</span><span style="color:#6F42C1">encoding/binary</span><span style="color:#032F62">"</span></span>
+<span class="line"><span style="color:#032F62"> "</span><span style="color:#6F42C1">image</span><span style="color:#032F62">"</span></span>
+<span class="line"><span style="color:#24292E"> _ </span><span style="color:#032F62">"</span><span style="color:#6F42C1">image/png</span><span style="color:#032F62">"</span></span>
+<span class="line"><span style="color:#032F62"> "</span><span style="color:#6F42C1">io</span><span style="color:#032F62">"</span></span>
+<span class="line"><span style="color:#032F62"> "</span><span style="color:#6F42C1">os</span><span style="color:#032F62">"</span></span>
+<span class="line"><span style="color:#24292E">)</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> main</span><span style="color:#24292E">() {</span></span>
+<span class="line"><span style="color:#24292E"> inFile, err </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> os.</span><span style="color:#6F42C1">Open</span><span style="color:#24292E">(</span><span style="color:#032F62">"input.png"</span><span style="color:#24292E">)</span></span>
+<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> err </span><span style="color:#D73A49">!=</span><span style="color:#005CC5"> nil</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#6F42C1"> panic</span><span style="color:#24292E">(err)</span></span>
+<span class="line"><span style="color:#24292E"> }</span></span>
+<span class="line"><span style="color:#D73A49"> defer</span><span style="color:#24292E"> inFile.</span><span style="color:#6F42C1">Close</span><span style="color:#24292E">()</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#24292E"> img, _, err </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> image.</span><span style="color:#6F42C1">Decode</span><span style="color:#24292E">(inFile)</span></span>
+<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> err </span><span style="color:#D73A49">!=</span><span style="color:#005CC5"> nil</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#6F42C1"> panic</span><span style="color:#24292E">(err)</span></span>
+<span class="line"><span style="color:#24292E"> }</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#24292E"> outFile, err </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> os.</span><span style="color:#6F42C1">Create</span><span style="color:#24292E">(</span><span style="color:#032F62">"output.png"</span><span style="color:#24292E">)</span></span>
+<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> err </span><span style="color:#D73A49">!=</span><span style="color:#005CC5"> nil</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#6F42C1"> panic</span><span style="color:#24292E">(err)</span></span>
+<span class="line"><span style="color:#24292E"> }</span></span>
+<span class="line"><span style="color:#D73A49"> defer</span><span style="color:#24292E"> outFile.</span><span style="color:#6F42C1">Close</span><span style="color:#24292E">()</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#6F42C1"> writePng</span><span style="color:#24292E">(outFile, img)</span></span>
+<span class="line"><span style="color:#24292E">}</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> writePng</span><span style="color:#24292E">(</span><span style="color:#E36209">w</span><span style="color:#6F42C1"> io</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Writer</span><span style="color:#24292E">, </span><span style="color:#E36209">img</span><span style="color:#6F42C1"> image</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Image</span><span style="color:#24292E">) {</span></span>
+<span class="line"><span style="color:#24292E"> width </span><span style="color:#D73A49">:=</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">(img.</span><span style="color:#6F42C1">Bounds</span><span style="color:#24292E">().</span><span style="color:#6F42C1">Dx</span><span style="color:#24292E">())</span></span>
+<span class="line"><span style="color:#24292E"> height </span><span style="color:#D73A49">:=</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">(img.</span><span style="color:#6F42C1">Bounds</span><span style="color:#24292E">().</span><span style="color:#6F42C1">Dy</span><span style="color:#24292E">())</span></span>
+<span class="line"><span style="color:#6F42C1"> writeSignature</span><span style="color:#24292E">(w)</span></span>
+<span class="line"><span style="color:#6F42C1"> writeChunkIhdr</span><span style="color:#24292E">(w, width, height)</span></span>
+<span class="line"><span style="color:#6F42C1"> writeChunkIdat</span><span style="color:#24292E">(w, width, height, img)</span></span>
+<span class="line"><span style="color:#6F42C1"> writeChunkIend</span><span style="color:#24292E">(w)</span></span>
+<span class="line"><span style="color:#24292E">}</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> writeSignature</span><span style="color:#24292E">(</span><span style="color:#E36209">w</span><span style="color:#6F42C1"> io</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Writer</span><span style="color:#24292E">) {</span></span>
+<span class="line"><span style="color:#24292E"> sig </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> [</span><span style="color:#005CC5">8</span><span style="color:#24292E">]</span><span style="color:#D73A49">uint8</span><span style="color:#24292E">{</span></span>
+<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">89</span><span style="color:#24292E">,</span></span>
+<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">50</span><span style="color:#24292E">, </span><span style="color:#6A737D">// P</span></span>
+<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">4E</span><span style="color:#24292E">, </span><span style="color:#6A737D">// N</span></span>
+<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">47</span><span style="color:#24292E">, </span><span style="color:#6A737D">// G</span></span>
+<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">0D</span><span style="color:#24292E">, </span><span style="color:#6A737D">// CR</span></span>
+<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">0A</span><span style="color:#24292E">, </span><span style="color:#6A737D">// LF</span></span>
+<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">1A</span><span style="color:#24292E">, </span><span style="color:#6A737D">// EOF (^Z)</span></span>
+<span class="line"><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">0A</span><span style="color:#24292E">, </span><span style="color:#6A737D">// LF</span></span>
+<span class="line"><span style="color:#24292E"> }</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(w, binary.BigEndian, sig)</span></span>
+<span class="line"><span style="color:#24292E">}</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> writeChunkIhdr</span><span style="color:#24292E">(</span><span style="color:#E36209">w</span><span style="color:#6F42C1"> io</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Writer</span><span style="color:#24292E">, </span><span style="color:#E36209">width</span><span style="color:#24292E">, </span><span style="color:#E36209">height</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">) {</span></span>
+<span class="line"><span style="color:#D73A49"> var</span><span style="color:#24292E"> buf </span><span style="color:#6F42C1">bytes</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Buffer</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">buf, binary.BigEndian, width)</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">buf, binary.BigEndian, height)</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#005CC5">8</span><span style="color:#24292E">))</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#005CC5">2</span><span style="color:#24292E">))</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">))</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">))</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">))</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#6F42C1"> writeChunk</span><span style="color:#24292E">(w, </span><span style="color:#032F62">"IHDR"</span><span style="color:#24292E">, buf.</span><span style="color:#6F42C1">Bytes</span><span style="color:#24292E">())</span></span>
+<span class="line"><span style="color:#24292E">}</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> writeChunkIdat</span><span style="color:#24292E">(</span><span style="color:#E36209">w</span><span style="color:#6F42C1"> io</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Writer</span><span style="color:#24292E">, </span><span style="color:#E36209">width</span><span style="color:#24292E">, </span><span style="color:#E36209">height</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">, </span><span style="color:#E36209">img</span><span style="color:#6F42C1"> image</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Image</span><span style="color:#24292E">) {</span></span>
+<span class="line"><span style="color:#D73A49"> var</span><span style="color:#24292E"> pixels </span><span style="color:#6F42C1">bytes</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Buffer</span></span>
+<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> y </span><span style="color:#D73A49">:=</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">); y </span><span style="color:#D73A49">&#x3C;</span><span style="color:#24292E"> height; y</span><span style="color:#D73A49">++</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">pixels, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">))</span></span>
+<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> x </span><span style="color:#D73A49">:=</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">); x </span><span style="color:#D73A49">&#x3C;</span><span style="color:#24292E"> width; x</span><span style="color:#D73A49">++</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#24292E"> r, g, b, _ </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> img.</span><span style="color:#6F42C1">At</span><span style="color:#24292E">(</span><span style="color:#D73A49">int</span><span style="color:#24292E">(x), </span><span style="color:#D73A49">int</span><span style="color:#24292E">(y)).</span><span style="color:#6F42C1">RGBA</span><span style="color:#24292E">()</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">pixels, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(r))</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">pixels, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(g))</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">pixels, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(b))</span></span>
+<span class="line"><span style="color:#24292E"> }</span></span>
+<span class="line"><span style="color:#24292E"> }</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#6F42C1"> writeChunk</span><span style="color:#24292E">(w, </span><span style="color:#032F62">"IDAT"</span><span style="color:#24292E">, </span><span style="color:#6F42C1">encodeZlib</span><span style="color:#24292E">(pixels.</span><span style="color:#6F42C1">Bytes</span><span style="color:#24292E">()))</span></span>
+<span class="line"><span style="color:#24292E">}</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> encodeZlib</span><span style="color:#24292E">(</span><span style="color:#E36209">data</span><span style="color:#24292E"> []</span><span style="color:#D73A49">byte</span><span style="color:#24292E">) []</span><span style="color:#D73A49">byte</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#D73A49"> var</span><span style="color:#24292E"> buf </span><span style="color:#6F42C1">bytes</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Buffer</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#D73A49">0x</span><span style="color:#005CC5">78</span><span style="color:#24292E">))</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#D73A49">uint8</span><span style="color:#24292E">(</span><span style="color:#D73A49">0x</span><span style="color:#005CC5">01</span><span style="color:#24292E">))</span></span>
+<span class="line"><span style="color:#24292E"> blockSize </span><span style="color:#D73A49">:=</span><span style="color:#005CC5"> 65535</span></span>
+<span class="line"><span style="color:#24292E"> isFinalBlock </span><span style="color:#D73A49">:=</span><span style="color:#005CC5"> false</span></span>
+<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> i </span><span style="color:#D73A49">:=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">; </span><span style="color:#D73A49">!</span><span style="color:#24292E">isFinalBlock; i</span><span style="color:#D73A49">++</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#D73A49"> var</span><span style="color:#24292E"> block []</span><span style="color:#D73A49">byte</span></span>
+<span class="line"><span style="color:#D73A49"> if</span><span style="color:#6F42C1"> len</span><span style="color:#24292E">(data) </span><span style="color:#D73A49">&#x3C;=</span><span style="color:#24292E"> (i</span><span style="color:#D73A49">+</span><span style="color:#005CC5">1</span><span style="color:#24292E">)</span><span style="color:#D73A49">*</span><span style="color:#24292E">blockSize {</span></span>
+<span class="line"><span style="color:#24292E"> block </span><span style="color:#D73A49">=</span><span style="color:#24292E"> data[i</span><span style="color:#D73A49">*</span><span style="color:#24292E">blockSize:]</span></span>
+<span class="line"><span style="color:#24292E"> isFinalBlock </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> true</span></span>
+<span class="line"><span style="color:#24292E"> } </span><span style="color:#D73A49">else</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#24292E"> block </span><span style="color:#D73A49">=</span><span style="color:#24292E"> data[i</span><span style="color:#D73A49">*</span><span style="color:#24292E">blockSize : (i</span><span style="color:#D73A49">+</span><span style="color:#005CC5">1</span><span style="color:#24292E">)</span><span style="color:#D73A49">*</span><span style="color:#24292E">blockSize]</span></span>
+<span class="line"><span style="color:#24292E"> }</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">buf, binary.BigEndian, isFinalBlock)</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">buf, binary.LittleEndian, </span><span style="color:#D73A49">uint16</span><span style="color:#24292E">(</span><span style="color:#6F42C1">len</span><span style="color:#24292E">(block)))</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">buf, binary.LittleEndian, </span><span style="color:#D73A49">uint16</span><span style="color:#24292E">(</span><span style="color:#D73A49">^</span><span style="color:#6F42C1">len</span><span style="color:#24292E">(block)))</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">buf, binary.LittleEndian, block)</span></span>
+<span class="line"><span style="color:#24292E"> }</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(</span><span style="color:#D73A49">&#x26;</span><span style="color:#24292E">buf, binary.BigEndian, </span><span style="color:#6F42C1">adler32</span><span style="color:#24292E">(data))</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49"> return</span><span style="color:#24292E"> buf.</span><span style="color:#6F42C1">Bytes</span><span style="color:#24292E">()</span></span>
+<span class="line"><span style="color:#24292E">}</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> writeChunkIend</span><span style="color:#24292E">(</span><span style="color:#E36209">w</span><span style="color:#6F42C1"> io</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Writer</span><span style="color:#24292E">) {</span></span>
+<span class="line"><span style="color:#6F42C1"> writeChunk</span><span style="color:#24292E">(w, </span><span style="color:#032F62">"IEND"</span><span style="color:#24292E">, </span><span style="color:#005CC5">nil</span><span style="color:#24292E">)</span></span>
+<span class="line"><span style="color:#24292E">}</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> writeChunk</span><span style="color:#24292E">(</span><span style="color:#E36209">w</span><span style="color:#6F42C1"> io</span><span style="color:#24292E">.</span><span style="color:#6F42C1">Writer</span><span style="color:#24292E">, </span><span style="color:#E36209">chunkType</span><span style="color:#D73A49"> string</span><span style="color:#24292E">, </span><span style="color:#E36209">data</span><span style="color:#24292E"> []</span><span style="color:#D73A49">byte</span><span style="color:#24292E">) {</span></span>
+<span class="line"><span style="color:#24292E"> typeAndData </span><span style="color:#D73A49">:=</span><span style="color:#6F42C1"> make</span><span style="color:#24292E">([]</span><span style="color:#D73A49">byte</span><span style="color:#24292E">, </span><span style="color:#005CC5">0</span><span style="color:#24292E">, </span><span style="color:#6F42C1">len</span><span style="color:#24292E">(chunkType)</span><span style="color:#D73A49">+</span><span style="color:#6F42C1">len</span><span style="color:#24292E">(data))</span></span>
+<span class="line"><span style="color:#24292E"> typeAndData </span><span style="color:#D73A49">=</span><span style="color:#6F42C1"> append</span><span style="color:#24292E">(typeAndData, []</span><span style="color:#D73A49">byte</span><span style="color:#24292E">(chunkType)</span><span style="color:#D73A49">...</span><span style="color:#24292E">)</span></span>
+<span class="line"><span style="color:#24292E"> typeAndData </span><span style="color:#D73A49">=</span><span style="color:#6F42C1"> append</span><span style="color:#24292E">(typeAndData, data</span><span style="color:#D73A49">...</span><span style="color:#24292E">)</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(w, binary.BigEndian, </span><span style="color:#D73A49">uint32</span><span style="color:#24292E">(</span><span style="color:#6F42C1">len</span><span style="color:#24292E">(data)))</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(w, binary.BigEndian, typeAndData)</span></span>
+<span class="line"><span style="color:#24292E"> binary.</span><span style="color:#6F42C1">Write</span><span style="color:#24292E">(w, binary.BigEndian, </span><span style="color:#6F42C1">crc</span><span style="color:#24292E">(typeAndData))</span></span>
+<span class="line"><span style="color:#24292E">}</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49">var</span><span style="color:#24292E"> (</span></span>
+<span class="line"><span style="color:#24292E"> crcTable [</span><span style="color:#005CC5">256</span><span style="color:#24292E">]</span><span style="color:#D73A49">uint32</span></span>
+<span class="line"><span style="color:#24292E"> crcTableComputed </span><span style="color:#D73A49">bool</span></span>
+<span class="line"><span style="color:#24292E">)</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> makeCrcTable</span><span style="color:#24292E">() {</span></span>
+<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> n </span><span style="color:#D73A49">:=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">; n </span><span style="color:#D73A49">&#x3C;</span><span style="color:#005CC5"> 256</span><span style="color:#24292E">; n</span><span style="color:#D73A49">++</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#24292E"> c </span><span style="color:#D73A49">:=</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">(n)</span></span>
+<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> k </span><span style="color:#D73A49">:=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">; k </span><span style="color:#D73A49">&#x3C;</span><span style="color:#005CC5"> 8</span><span style="color:#24292E">; k</span><span style="color:#D73A49">++</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> (c </span><span style="color:#D73A49">&#x26;</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">) </span><span style="color:#D73A49">!=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#24292E"> c </span><span style="color:#D73A49">=</span><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">EDB88320</span><span style="color:#D73A49"> ^</span><span style="color:#24292E"> (c </span><span style="color:#D73A49">>></span><span style="color:#005CC5"> 1</span><span style="color:#24292E">)</span></span>
+<span class="line"><span style="color:#24292E"> } </span><span style="color:#D73A49">else</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#24292E"> c </span><span style="color:#D73A49">=</span><span style="color:#24292E"> c </span><span style="color:#D73A49">>></span><span style="color:#005CC5"> 1</span></span>
+<span class="line"><span style="color:#24292E"> }</span></span>
+<span class="line"><span style="color:#24292E"> }</span></span>
+<span class="line"><span style="color:#24292E"> crcTable[n] </span><span style="color:#D73A49">=</span><span style="color:#24292E"> c</span></span>
+<span class="line"><span style="color:#24292E"> }</span></span>
+<span class="line"><span style="color:#24292E"> crcTableComputed </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> true</span></span>
+<span class="line"><span style="color:#24292E">}</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> updateCrc</span><span style="color:#24292E">(</span><span style="color:#E36209">crc</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">, </span><span style="color:#E36209">buf</span><span style="color:#24292E"> []</span><span style="color:#D73A49">byte</span><span style="color:#24292E">) </span><span style="color:#D73A49">uint32</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#D73A49"> if</span><span style="color:#D73A49"> !</span><span style="color:#24292E">crcTableComputed {</span></span>
+<span class="line"><span style="color:#6F42C1"> makeCrcTable</span><span style="color:#24292E">()</span></span>
+<span class="line"><span style="color:#24292E"> }</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#24292E"> c </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> crc</span></span>
+<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> n </span><span style="color:#D73A49">:=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">; n </span><span style="color:#D73A49">&#x3C;</span><span style="color:#6F42C1"> len</span><span style="color:#24292E">(buf); n</span><span style="color:#D73A49">++</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#24292E"> c </span><span style="color:#D73A49">=</span><span style="color:#24292E"> crcTable[(c</span><span style="color:#D73A49">^uint32</span><span style="color:#24292E">(buf[n]))</span><span style="color:#D73A49">&#x26;0x</span><span style="color:#005CC5">FF</span><span style="color:#24292E">] </span><span style="color:#D73A49">^</span><span style="color:#24292E"> (c </span><span style="color:#D73A49">>></span><span style="color:#005CC5"> 8</span><span style="color:#24292E">)</span></span>
+<span class="line"><span style="color:#24292E"> }</span></span>
+<span class="line"><span style="color:#D73A49"> return</span><span style="color:#24292E"> c</span></span>
+<span class="line"><span style="color:#24292E">}</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> crc</span><span style="color:#24292E">(</span><span style="color:#E36209">buf</span><span style="color:#24292E"> []</span><span style="color:#D73A49">byte</span><span style="color:#24292E">) </span><span style="color:#D73A49">uint32</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#D73A49"> return</span><span style="color:#6F42C1"> updateCrc</span><span style="color:#24292E">(</span><span style="color:#D73A49">0x</span><span style="color:#005CC5">FFFFFFFF</span><span style="color:#24292E">, buf) </span><span style="color:#D73A49">^</span><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">FFFFFFFF</span></span>
+<span class="line"><span style="color:#24292E">}</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49">const</span><span style="color:#005CC5"> adler32Base</span><span style="color:#D73A49"> =</span><span style="color:#005CC5"> 65521</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> updateAdler32</span><span style="color:#24292E">(</span><span style="color:#E36209">adler</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">, </span><span style="color:#E36209">buf</span><span style="color:#24292E"> []</span><span style="color:#D73A49">byte</span><span style="color:#24292E">) </span><span style="color:#D73A49">uint32</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#24292E"> s1 </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> adler </span><span style="color:#D73A49">&#x26;</span><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">FFFF</span></span>
+<span class="line"><span style="color:#24292E"> s2 </span><span style="color:#D73A49">:=</span><span style="color:#24292E"> (adler </span><span style="color:#D73A49">>></span><span style="color:#005CC5"> 16</span><span style="color:#24292E">) </span><span style="color:#D73A49">&#x26;</span><span style="color:#D73A49"> 0x</span><span style="color:#005CC5">FFFF</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> n </span><span style="color:#D73A49">:=</span><span style="color:#005CC5"> 0</span><span style="color:#24292E">; n </span><span style="color:#D73A49">&#x3C;</span><span style="color:#6F42C1"> len</span><span style="color:#24292E">(buf); n</span><span style="color:#D73A49">++</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#24292E"> s1 </span><span style="color:#D73A49">=</span><span style="color:#24292E"> (s1 </span><span style="color:#D73A49">+</span><span style="color:#D73A49"> uint32</span><span style="color:#24292E">(buf[n])) </span><span style="color:#D73A49">%</span><span style="color:#24292E"> adler32Base</span></span>
+<span class="line"><span style="color:#24292E"> s2 </span><span style="color:#D73A49">=</span><span style="color:#24292E"> (s2 </span><span style="color:#D73A49">+</span><span style="color:#24292E"> s1) </span><span style="color:#D73A49">%</span><span style="color:#24292E"> adler32Base</span></span>
+<span class="line"><span style="color:#24292E"> }</span></span>
+<span class="line"><span style="color:#D73A49"> return</span><span style="color:#24292E"> (s2 </span><span style="color:#D73A49">&#x3C;&#x3C;</span><span style="color:#005CC5"> 16</span><span style="color:#24292E">) </span><span style="color:#D73A49">+</span><span style="color:#24292E"> s1</span></span>
+<span class="line"><span style="color:#24292E">}</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49">func</span><span style="color:#6F42C1"> adler32</span><span style="color:#24292E">(</span><span style="color:#E36209">buf</span><span style="color:#24292E"> []</span><span style="color:#D73A49">byte</span><span style="color:#24292E">) </span><span style="color:#D73A49">uint32</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#D73A49"> return</span><span style="color:#6F42C1"> updateAdler32</span><span style="color:#24292E">(</span><span style="color:#005CC5">1</span><span style="color:#24292E">, buf)</span></span>
+<span class="line"><span style="color:#24292E">}</span></span></code></pre>
+ </div>
</section>
<section id="section--references">