Skip to content

Commit 09aa053

Browse files
committed
deploy: cb0aba9
1 parent 01b4c1d commit 09aa053

22 files changed

+1913
-1381
lines changed

docs/blurhash.html

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<title>Blur Hash | SkiaSharp.Extended </title>
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7+
<meta name="title" content="Blur Hash | SkiaSharp.Extended ">
8+
9+
<link rel="icon" href="../images/logo.ico">
10+
<link rel="stylesheet" href="../public/docfx.min.css">
11+
<link rel="stylesheet" href="../public/main.css">
12+
<meta name="docfx:navrel" content="../toc.html">
13+
<meta name="docfx:tocrel" content="toc.html">
14+
15+
<meta name="docfx:rel" content="../">
16+
17+
18+
<meta name="docfx:docurl" content="https://github.com/mono/SkiaSharp.Extended/blob/main/docs/docs/blurhash.md/#L1">
19+
<meta name="loc:inThisArticle" content="In this article">
20+
<meta name="loc:searchResultsCount" content="{count} results for &quot;{query}&quot;">
21+
<meta name="loc:searchNoResults" content="No results for &quot;{query}&quot;">
22+
<meta name="loc:tocFilter" content="Filter by title">
23+
<meta name="loc:nextArticle" content="Next">
24+
<meta name="loc:prevArticle" content="Previous">
25+
<meta name="loc:themeLight" content="Light">
26+
<meta name="loc:themeDark" content="Dark">
27+
<meta name="loc:themeAuto" content="Auto">
28+
<meta name="loc:changeTheme" content="Change theme">
29+
<meta name="loc:copy" content="Copy">
30+
<meta name="loc:downloadPdf" content="Download PDF">
31+
</head>
32+
33+
<script type="module" src="./../public/docfx.min.js"></script>
34+
35+
<script>
36+
const theme = localStorage.getItem('theme') || 'auto'
37+
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
38+
</script>
39+
40+
41+
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
42+
<header class="bg-body border-bottom">
43+
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
44+
<div class="container-xxl flex-nowrap">
45+
<a class="navbar-brand" href="../index.html">
46+
<img id="logo" class="svg" src="../images/logo.png" alt="">
47+
48+
</a>
49+
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
50+
<i class="bi bi-three-dots"></i>
51+
</button>
52+
<div class="collapse navbar-collapse" id="navpanel">
53+
<div id="navbar">
54+
<form class="search" role="search" id="search">
55+
<i class="bi bi-search"></i>
56+
<input class="form-control" id="search-query" type="search" disabled="" placeholder="Search" autocomplete="off" aria-label="Search">
57+
</form>
58+
</div>
59+
</div>
60+
</div>
61+
</nav>
62+
</header>
63+
64+
<main class="container-xxl">
65+
<div class="toc-offcanvas">
66+
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
67+
<div class="offcanvas-header">
68+
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
69+
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
70+
</div>
71+
<div class="offcanvas-body">
72+
<nav class="toc" id="toc"></nav>
73+
</div>
74+
</div>
75+
</div>
76+
77+
<div class="content">
78+
<div class="actionbar">
79+
<button class="btn btn-lg border-0 d-md-none" style="margin-top: -.65em; margin-left: -.8em" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
80+
<i class="bi bi-list"></i>
81+
</button>
82+
83+
<nav id="breadcrumb"></nav>
84+
</div>
85+
86+
<article data-uid="">
87+
<h1 id="blur-hash">Blur Hash</h1>
88+
89+
<p>Blur Hash is a compact representation of an image placeholder. Instead of loading a grey box while your image loads, you can show a colorful blur that hints at the final image—all from a tiny string that's only 20-30 characters.</p>
90+
<table>
91+
<thead>
92+
<tr>
93+
<th style="text-align: center;">Original</th>
94+
<th style="text-align: center;">Blur Hash Placeholder</th>
95+
</tr>
96+
</thead>
97+
<tbody>
98+
<tr>
99+
<td style="text-align: center;"><img src="../images/extended/skblurhash/logo.png" alt="Original"></td>
100+
<td style="text-align: center;"><img src="../images/extended/skblurhash/blur.png" alt="BlurHash"></td>
101+
</tr>
102+
</tbody>
103+
</table>
104+
<p>The hash for this image is just 28 characters: <code>LjPsbRxG%gx^aJxuM|W=?^X8Mxn$</code></p>
105+
<h2 id="quick-start">Quick Start</h2>
106+
<h3 id="encode-an-image">Encode an image</h3>
107+
<pre><code class="lang-csharp">using SkiaSharp;
108+
using SkiaSharp.Extended;
109+
110+
using var bitmap = SKBitmap.Decode(&quot;photo.jpg&quot;);
111+
string hash = SKBlurHash.Serialize(bitmap, 4, 3);
112+
// Returns something like: &quot;LjPsbRxG%gx^aJxuM|W=?^X8Mxn$&quot;
113+
</code></pre>
114+
<h3 id="decode-a-placeholder">Decode a placeholder</h3>
115+
<pre><code class="lang-csharp">var placeholder = SKBlurHash.DeserializeBitmap(hash, 32, 32);
116+
// Use this blurred bitmap while the real image loads
117+
</code></pre>
118+
<h2 id="how-it-works">How It Works</h2>
119+
<p>Blur Hash uses a technique similar to JPEG compression called the <a href="https://en.wikipedia.org/wiki/Discrete_cosine_transform">Discrete Cosine Transform</a> (DCT). It extracts the dominant color patterns from an image and encodes them into a short ASCII string.</p>
120+
<p>The <code>componentsX</code> and <code>componentsY</code> parameters control how much detail is captured:</p>
121+
<p><img src="../images/extended/skblurhash/components-comparison.png" alt="Components comparison"></p>
122+
<p>More components = more detail, but a longer string. For most use cases, <strong>4x3 is a good default</strong>.</p>
123+
<h2 id="customization">Customization</h2>
124+
<h3 id="components">Components</h3>
125+
<p>The component count (1-9 for each axis) determines the level of detail:</p>
126+
<table>
127+
<thead>
128+
<tr>
129+
<th style="text-align: center;">Components</th>
130+
<th style="text-align: center;">String Length</th>
131+
<th style="text-align: left;">Best For</th>
132+
</tr>
133+
</thead>
134+
<tbody>
135+
<tr>
136+
<td style="text-align: center;">2x2</td>
137+
<td style="text-align: center;">~12 chars</td>
138+
<td style="text-align: left;">Simple gradients</td>
139+
</tr>
140+
<tr>
141+
<td style="text-align: center;">4x3</td>
142+
<td style="text-align: center;">~28 chars</td>
143+
<td style="text-align: left;">Most images (recommended)</td>
144+
</tr>
145+
<tr>
146+
<td style="text-align: center;">6x6</td>
147+
<td style="text-align: center;">~76 chars</td>
148+
<td style="text-align: left;">Complex images with fine detail</td>
149+
</tr>
150+
</tbody>
151+
</table>
152+
<h3 id="punch">Punch</h3>
153+
<p>The <code>punch</code> parameter adjusts the contrast of the decoded image. Values greater than 1.0 make colors more vibrant:</p>
154+
<p><img src="../images/extended/skblurhash/punch-comparison.png" alt="Punch comparison"></p>
155+
<pre><code class="lang-csharp">// Default punch (1.0)
156+
var normal = SKBlurHash.DeserializeBitmap(hash, 32, 32);
157+
158+
// More vibrant (1.5)
159+
var vibrant = SKBlurHash.DeserializeBitmap(hash, 32, 32, punch: 1.5f);
160+
</code></pre>
161+
<h3 id="placeholder-size">Placeholder Size</h3>
162+
<p>The decoded placeholder doesn't need to match your final image size. A small size like 32x32 is usually sufficient—it will be scaled up and displayed blurred anyway.</p>
163+
<h2 id="usage-patterns">Usage Patterns</h2>
164+
<h3 id="include-in-api-responses">Include in API responses</h3>
165+
<p>Pre-compute hashes on your server and include them with image URLs:</p>
166+
<pre><code class="lang-json">{
167+
&quot;imageUrl&quot;: &quot;https://example.com/photo.jpg&quot;,
168+
&quot;blurHash&quot;: &quot;LjPsbRxG%gx^aJxuM|W=?^X8Mxn$&quot;,
169+
&quot;width&quot;: 1920,
170+
&quot;height&quot;: 1080
171+
}
172+
</code></pre>
173+
<h3 id="maui-value-converter">MAUI value converter</h3>
174+
<p>Create a converter to decode blur hashes directly in XAML bindings:</p>
175+
<pre><code class="lang-csharp">using System.Globalization;
176+
using SkiaSharp;
177+
using SkiaSharp.Extended;
178+
using SkiaSharp.Views.Maui.Controls;
179+
180+
public class BlurHashConverter : IValueConverter
181+
{
182+
public int Width { get; set; } = 32;
183+
public int Height { get; set; } = 32;
184+
185+
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
186+
{
187+
if (value is string hash &amp;&amp; !string.IsNullOrEmpty(hash))
188+
{
189+
var bitmap = SKBlurHash.DeserializeBitmap(hash, Width, Height);
190+
return (SKBitmapImageSource)bitmap;
191+
}
192+
return null;
193+
}
194+
195+
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
196+
=&gt; throw new NotImplementedException();
197+
}
198+
</code></pre>
199+
<p>Then use it in XAML:</p>
200+
<pre><code class="lang-xml">&lt;Image Source=&quot;{Binding BlurHash, Converter={StaticResource BlurHashConverter}}&quot; /&gt;
201+
</code></pre>
202+
<h2 id="learn-more">Learn More</h2>
203+
<ul>
204+
<li><a href="https://blurha.sh/">BlurHash.sh</a> — Official demo and explanation</li>
205+
<li><a href="https://github.com/woltapp/blurhash">BlurHash GitHub</a> — Original algorithm by Dag Ågren at Wolt</li>
206+
<li><a href="https://careers.wolt.com/en/blog/tech/how-we-came-to-create-a-new-image-placeholder-algorithm-blurhash">How Wolt created BlurHash</a> — The origin story</li>
207+
<li><a class="xref" href="../api/SkiaSharp.Extended.SKBlurHash.html">API Reference</a> — Full method documentation</li>
208+
</ul>
209+
210+
</article>
211+
212+
<div class="contribution d-print-none">
213+
<a href="https://github.com/mono/SkiaSharp.Extended/blob/main/docs/docs/blurhash.md/#L1" class="edit-link">Edit this page</a>
214+
</div>
215+
216+
<div class="next-article d-print-none border-top" id="nextArticle"></div>
217+
218+
</div>
219+
220+
<div class="affix">
221+
<nav id="affix"></nav>
222+
</div>
223+
</main>
224+
225+
<div class="container-xxl search-results" id="search-results"></div>
226+
227+
<footer class="border-top text-secondary">
228+
<div class="container-xxl">
229+
<div class="flex-fill">
230+
<span>Made with <a href="https://dotnet.github.io/docfx">docfx</a></span>
231+
</div>
232+
</div>
233+
</footer>
234+
</body>
235+
</html>

0 commit comments

Comments
 (0)