inweb-bootstrap/docs/foundation-module/6-id.html

149 lines
23 KiB
HTML
Raw Normal View History

2019-02-04 22:26:45 +00:00
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
2020-04-08 22:41:00 +00:00
<title>Image Dimensions</title>
2020-04-23 22:23:44 +00:00
<link href="../docs-assets/Breadcrumbs.css" rel="stylesheet" rev="stylesheet" type="text/css">
<meta name="viewport" content="width=device-width initial-scale=1">
2019-02-04 22:26:45 +00:00
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Language" content="en-gb">
2020-04-20 22:26:08 +00:00
<link href="../docs-assets/Base.css" rel="stylesheet" rev="stylesheet" type="text/css">
<script>
function togglePopup(material_id) {
var popup = document.getElementById(material_id);
popup.classList.toggle("show");
}
</script>
<link href="../docs-assets/Popups.css" rel="stylesheet" rev="stylesheet" type="text/css">
2020-04-21 16:55:17 +00:00
<link href="../docs-assets/Colours.css" rel="stylesheet" rev="stylesheet" type="text/css">
2020-04-23 22:23:44 +00:00
2019-02-04 22:26:45 +00:00
</head>
<body>
<nav role="navigation">
2020-04-13 16:06:45 +00:00
<h1><a href="../index.html">
2020-04-20 22:26:08 +00:00
<img src="../docs-assets/Octagram.png" width=72 height=72">
2020-04-13 16:06:45 +00:00
</a></h1>
<ul><li><a href="../inweb/index.html">inweb</a></li>
</ul><h2>Foundation Module</h2><ul>
<li><a href="index.html"><span class="selectedlink">foundation</span></a></li>
<li><a href="../foundation-test/index.html">foundation-test</a></li>
2020-04-13 16:06:45 +00:00
</ul><h2>Example Webs</h2><ul>
2020-04-12 16:24:23 +00:00
<li><a href="../goldbach/index.html">goldbach</a></li>
<li><a href="../twinprimes/twinprimes.html">twinprimes</a></li>
2020-04-15 22:45:08 +00:00
<li><a href="../eastertide/index.html">eastertide</a></li>
2020-04-14 17:36:42 +00:00
</ul><h2>Repository</h2><ul>
2020-04-20 22:34:44 +00:00
<li><a href="https://github.com/ganelson/inweb"><img src="../docs-assets/github.png" height=18> github</a></li>
2020-04-14 17:36:42 +00:00
</ul><h2>Related Projects</h2><ul>
<li><a href="../../../inform/docs/index.html">inform</a></li>
<li><a href="../../../intest/docs/index.html">intest</a></li>
2020-04-13 16:06:45 +00:00
</ul>
</nav>
<main role="main">
2020-04-23 22:23:44 +00:00
<!--Weave of 'Image Dimensions' generated by Inweb-->
2020-04-13 16:06:45 +00:00
<ul class="crumbs"><li><a href="../index.html">Home</a></li><li><a href="index.html">foundation</a></li><li><a href="index.html#6">Chapter 6: Media</a></li><li><b>Image Dimensions</b></li></ul><p class="purpose">These utility routines look at the headers of JPEG and PNG files to find the pixel dimensions of any images supplied by the user for cover art and figures.</p>
2019-02-04 22:26:45 +00:00
2020-04-15 22:45:08 +00:00
<ul class="toc"><li><a href="6-id.html#SP1">&#167;1. JPEG files</a></li><li><a href="6-id.html#SP2">&#167;2. PNG files</a></li></ul><hr class="tocbar">
2019-02-04 22:26:45 +00:00
<p class="inwebparagraph"><a id="SP1"></a><b>&#167;1. JPEG files. </b>The following code, contributed by Toby Nelson, either finds the pixel width
2020-04-22 22:57:09 +00:00
and height of a given JPEG file and returns <span class="extract"><span class="extract-syntax">TRUE</span></span> or, if it can't read the
file or doesn't recognise the header as having JPEG format, returns <span class="extract"><span class="extract-syntax">FALSE</span></span>.
2019-02-04 22:26:45 +00:00
</p>
<p class="inwebparagraph">JPEG is properly speaking not a file format but a compression technique:
the routine below works with either JIF (JPEG Interchange Format) or its
simpler cousin JFIF (JPEG File Interchange Format).
</p>
<p class="inwebparagraph">We scan the file looking for "markers", each of which begins with an
2020-04-22 22:57:09 +00:00
<span class="extract"><span class="extract-syntax">0xFF</span></span> byte and is followed by a marker-type byte which is neither <span class="extract"><span class="extract-syntax">0x00</span></span>
nor <span class="extract"><span class="extract-syntax">0xFF</span></span>. The compulsory marker SOI must appear at the start of the file,
2019-02-04 22:26:45 +00:00
providing one way to detect probable JPEGs by looking at the first two
bytes. There must also eventually be a start of frame marker, for the
actual image: this can have many forms, but in all cases tells us the
height and width.
</p>
2020-04-21 16:55:17 +00:00
<pre class="displayed-code all-displayed-code">
<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="function-syntax">ImageFiles::get_JPEG_dimensions</span><button class="popup" onclick="togglePopup('usagePopup1')">...<span class="popuptext" id="usagePopup1">Usage of <b>ImageFiles::get_JPEG_dimensions</b>:<br>none</span></button><span class="plain-syntax">(</span><span class="reserved-syntax">FILE</span><span class="plain-syntax"> *</span><span class="identifier-syntax">JPEG_file</span><span class="plain-syntax">, </span><span class="reserved-syntax">unsigned</span><span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> *</span><span class="identifier-syntax">width</span><span class="plain-syntax">, </span><span class="reserved-syntax">unsigned</span><span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> *</span><span class="identifier-syntax">height</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">unsigned</span><span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">sig</span><span class="plain-syntax">, </span><span class="identifier-syntax">length</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">marker</span><span class="plain-syntax">;</span>
2020-04-21 23:52:25 +00:00
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (!</span><a href="6-bf.html#SP1" class="function-link"><span class="function-syntax">BinaryFiles::read_int16</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">JPEG_file</span><span class="plain-syntax">, &amp;</span><span class="identifier-syntax">sig</span><span class="plain-syntax">)) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">FALSE</span><span class="plain-syntax">;</span>
2020-04-22 22:57:09 +00:00
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">sig</span><span class="plain-syntax"> != </span><span class="constant-syntax">0xFFD8</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">FALSE</span><span class="plain-syntax">; </span><span class="comment"> </span><span class="extract"><span class="extract-syntax">0xFF</span></span><span class="comment"> (marker) then </span><span class="extract"><span class="extract-syntax">0xD8</span></span><span class="comment"> (SOI)</span>
2020-04-21 16:55:17 +00:00
<span class="plain-syntax"> </span><span class="reserved-syntax">do</span><span class="plain-syntax"> {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">do</span><span class="plain-syntax"> {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">marker</span><span class="plain-syntax"> = </span><span class="identifier-syntax">getc</span><span class="plain-syntax">(</span><span class="identifier-syntax">JPEG_file</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">marker</span><span class="plain-syntax"> == </span><span class="identifier-syntax">EOF</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">FALSE</span><span class="plain-syntax">;</span>
2020-04-22 22:57:09 +00:00
<span class="plain-syntax"> } </span><span class="reserved-syntax">while</span><span class="plain-syntax"> (</span><span class="identifier-syntax">marker</span><span class="plain-syntax"> != </span><span class="constant-syntax">0xff</span><span class="plain-syntax">); </span><span class="comment"> skip to next </span><span class="extract"><span class="extract-syntax">0xFF</span></span><span class="comment"> byte</span>
2020-04-21 16:55:17 +00:00
<span class="plain-syntax"> </span><span class="reserved-syntax">do</span><span class="plain-syntax"> {</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">marker</span><span class="plain-syntax"> = </span><span class="identifier-syntax">getc</span><span class="plain-syntax">(</span><span class="identifier-syntax">JPEG_file</span><span class="plain-syntax">);</span>
2020-04-22 22:57:09 +00:00
<span class="plain-syntax"> } </span><span class="reserved-syntax">while</span><span class="plain-syntax"> (</span><span class="identifier-syntax">marker</span><span class="plain-syntax"> == </span><span class="constant-syntax">0xff</span><span class="plain-syntax">); </span><span class="comment"> skip to next non </span><span class="extract"><span class="extract-syntax">FF</span></span><span class="comment"> byte</span>
2020-04-21 16:55:17 +00:00
2020-04-21 23:52:25 +00:00
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (!</span><a href="6-bf.html#SP1" class="function-link"><span class="function-syntax">BinaryFiles::read_int16</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">JPEG_file</span><span class="plain-syntax">, &amp;</span><span class="identifier-syntax">length</span><span class="plain-syntax">)) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">FALSE</span><span class="plain-syntax">; </span><span class="comment"> length of marker</span>
2020-04-21 16:55:17 +00:00
<span class="plain-syntax"> </span><span class="reserved-syntax">switch</span><span class="plain-syntax">(</span><span class="identifier-syntax">marker</span><span class="plain-syntax">) {</span>
2020-04-22 22:57:09 +00:00
<span class="plain-syntax"> </span><span class="comment"> all variant forms of "start of frame": e.g., </span><span class="extract"><span class="extract-syntax">0xC0</span></span><span class="comment"> is a baseline DCT image</span>
2020-04-21 16:55:17 +00:00
<span class="plain-syntax"> </span><span class="reserved-syntax">case</span><span class="plain-syntax"> </span><span class="constant-syntax">0xc0</span><span class="identifier-syntax">:</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">case</span><span class="plain-syntax"> </span><span class="constant-syntax">0xc1</span><span class="identifier-syntax">:</span><span class="plain-syntax"> </span><span class="reserved-syntax">case</span><span class="plain-syntax"> </span><span class="constant-syntax">0xc2</span><span class="identifier-syntax">:</span><span class="plain-syntax"> </span><span class="reserved-syntax">case</span><span class="plain-syntax"> </span><span class="constant-syntax">0xc3</span><span class="identifier-syntax">:</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">case</span><span class="plain-syntax"> </span><span class="constant-syntax">0xc5</span><span class="identifier-syntax">:</span><span class="plain-syntax"> </span><span class="reserved-syntax">case</span><span class="plain-syntax"> </span><span class="constant-syntax">0xc6</span><span class="identifier-syntax">:</span><span class="plain-syntax"> </span><span class="reserved-syntax">case</span><span class="plain-syntax"> </span><span class="constant-syntax">0xc7</span><span class="identifier-syntax">:</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">case</span><span class="plain-syntax"> </span><span class="constant-syntax">0xc9</span><span class="identifier-syntax">:</span><span class="plain-syntax"> </span><span class="reserved-syntax">case</span><span class="plain-syntax"> </span><span class="constant-syntax">0xca</span><span class="identifier-syntax">:</span><span class="plain-syntax"> </span><span class="reserved-syntax">case</span><span class="plain-syntax"> </span><span class="constant-syntax">0xcb</span><span class="identifier-syntax">:</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">case</span><span class="plain-syntax"> </span><span class="constant-syntax">0xcd</span><span class="identifier-syntax">:</span><span class="plain-syntax"> </span><span class="reserved-syntax">case</span><span class="plain-syntax"> </span><span class="constant-syntax">0xce</span><span class="identifier-syntax">:</span><span class="plain-syntax"> </span><span class="reserved-syntax">case</span><span class="plain-syntax"> </span><span class="constant-syntax">0xcf</span><span class="identifier-syntax">:</span><span class="plain-syntax"> {</span>
<span class="plain-syntax"> </span><span class="comment"> fortunately these markers all then open with the same format</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">getc</span><span class="plain-syntax">(</span><span class="identifier-syntax">JPEG_file</span><span class="plain-syntax">) == </span><span class="identifier-syntax">EOF</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">FALSE</span><span class="plain-syntax">; </span><span class="comment"> skip 1 byte of data precision</span>
2020-04-21 23:52:25 +00:00
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (!</span><a href="6-bf.html#SP1" class="function-link"><span class="function-syntax">BinaryFiles::read_int16</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">JPEG_file</span><span class="plain-syntax">, </span><span class="identifier-syntax">height</span><span class="plain-syntax">)) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">FALSE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (!</span><a href="6-bf.html#SP1" class="function-link"><span class="function-syntax">BinaryFiles::read_int16</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">JPEG_file</span><span class="plain-syntax">, </span><span class="identifier-syntax">width</span><span class="plain-syntax">)) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">FALSE</span><span class="plain-syntax">;</span>
2020-04-21 16:55:17 +00:00
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">TRUE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="identifier-syntax">default:</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">fseek</span><span class="plain-syntax">(</span><span class="identifier-syntax">JPEG_file</span><span class="plain-syntax">, (</span><span class="reserved-syntax">long</span><span class="plain-syntax">) (</span><span class="identifier-syntax">length</span><span class="plain-syntax"> - </span><span class="constant-syntax">2</span><span class="plain-syntax">), </span><span class="identifier-syntax">SEEK_CUR</span><span class="plain-syntax">) != </span><span class="constant-syntax">0</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">FALSE</span><span class="plain-syntax">; </span><span class="comment"> skip rest of marker</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> }</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">while</span><span class="plain-syntax"> (</span><span class="identifier-syntax">marker</span><span class="plain-syntax"> != </span><span class="identifier-syntax">EOF</span><span class="plain-syntax">);</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">FALSE</span><span class="plain-syntax">;</span>
<span class="plain-syntax">}</span>
</pre><p class="inwebparagraph"><a id="SP2"></a><b>&#167;2. PNG files. </b>The PNG file must start with a signature which indicates that the
2019-02-04 22:26:45 +00:00
remainder contains a single PNG image, consisting of a series of chunks
beginning with an IHDR chunk and ending with an IEND chunk ("Portable
Network Graphics (PNG) Specification", 2nd edition, section 5.2). We only
need to scan the IHDR chunk, of which the pixel width and height are the
first two words (section 11.2.2).
</p>
2020-04-21 16:55:17 +00:00
<pre class="displayed-code all-displayed-code">
<span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="function-syntax">ImageFiles::get_PNG_dimensions</span><button class="popup" onclick="togglePopup('usagePopup2')">...<span class="popuptext" id="usagePopup2">Usage of <b>ImageFiles::get_PNG_dimensions</b>:<br>none</span></button><span class="plain-syntax">(</span><span class="reserved-syntax">FILE</span><span class="plain-syntax"> *</span><span class="identifier-syntax">PNG_file</span><span class="plain-syntax">, </span><span class="reserved-syntax">unsigned</span><span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> *</span><span class="identifier-syntax">width</span><span class="plain-syntax">, </span><span class="reserved-syntax">unsigned</span><span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> *</span><span class="identifier-syntax">height</span><span class="plain-syntax">) {</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">unsigned</span><span class="plain-syntax"> </span><span class="reserved-syntax">int</span><span class="plain-syntax"> </span><span class="identifier-syntax">sig1</span><span class="plain-syntax">, </span><span class="identifier-syntax">sig2</span><span class="plain-syntax">, </span><span class="identifier-syntax">length</span><span class="plain-syntax">, </span><span class="identifier-syntax">type</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="comment"> Check PNG signature</span>
2020-04-21 23:52:25 +00:00
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (!</span><a href="6-bf.html#SP1" class="function-link"><span class="function-syntax">BinaryFiles::read_int32</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">PNG_file</span><span class="plain-syntax">, &amp;</span><span class="identifier-syntax">sig1</span><span class="plain-syntax">)) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">FALSE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (!</span><a href="6-bf.html#SP1" class="function-link"><span class="function-syntax">BinaryFiles::read_int32</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">PNG_file</span><span class="plain-syntax">, &amp;</span><span class="identifier-syntax">sig2</span><span class="plain-syntax">)) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">FALSE</span><span class="plain-syntax">;</span>
2020-04-21 16:55:17 +00:00
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> ((</span><span class="identifier-syntax">sig1</span><span class="plain-syntax"> != </span><span class="constant-syntax">0x89504e47</span><span class="plain-syntax">) || (</span><span class="identifier-syntax">sig2</span><span class="plain-syntax"> != </span><span class="constant-syntax">0x0d0a1a0a</span><span class="plain-syntax">)) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">FALSE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="comment"> Read first chunk</span>
2020-04-21 23:52:25 +00:00
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (!</span><a href="6-bf.html#SP1" class="function-link"><span class="function-syntax">BinaryFiles::read_int32</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">PNG_file</span><span class="plain-syntax">, &amp;</span><span class="identifier-syntax">length</span><span class="plain-syntax">)) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">FALSE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (!</span><a href="6-bf.html#SP1" class="function-link"><span class="function-syntax">BinaryFiles::read_int32</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">PNG_file</span><span class="plain-syntax">, &amp;</span><span class="identifier-syntax">type</span><span class="plain-syntax">)) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">FALSE</span><span class="plain-syntax">;</span>
2020-04-21 16:55:17 +00:00
<span class="plain-syntax"> </span><span class="comment"> First chunk must be IHDR</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (</span><span class="identifier-syntax">type</span><span class="plain-syntax"> != </span><span class="constant-syntax">0x49484452</span><span class="plain-syntax">) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">FALSE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="comment"> Width and height follow</span>
2020-04-21 23:52:25 +00:00
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (!</span><a href="6-bf.html#SP1" class="function-link"><span class="function-syntax">BinaryFiles::read_int32</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">PNG_file</span><span class="plain-syntax">, </span><span class="identifier-syntax">width</span><span class="plain-syntax">)) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">FALSE</span><span class="plain-syntax">;</span>
<span class="plain-syntax"> </span><span class="reserved-syntax">if</span><span class="plain-syntax"> (!</span><a href="6-bf.html#SP1" class="function-link"><span class="function-syntax">BinaryFiles::read_int32</span></a><span class="plain-syntax">(</span><span class="identifier-syntax">PNG_file</span><span class="plain-syntax">, </span><span class="identifier-syntax">height</span><span class="plain-syntax">)) </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">FALSE</span><span class="plain-syntax">;</span>
2020-04-21 16:55:17 +00:00
<span class="plain-syntax"> </span><span class="reserved-syntax">return</span><span class="plain-syntax"> </span><span class="constant-syntax">TRUE</span><span class="plain-syntax">;</span>
<span class="plain-syntax">}</span>
</pre><hr class="tocbar">
2019-03-12 23:32:12 +00:00
<ul class="toc"><li><a href="6-bf.html">Back to 'Binary Files'</a></li><li><a href="6-sd.html">Continue with 'Sound Durations'</a></li></ul><hr class="tocbar">
<!--End of weave-->
2020-04-23 22:23:44 +00:00
</main>
2019-02-04 22:26:45 +00:00
</body>
</html>