-
Notifications
You must be signed in to change notification settings - Fork 10
/
example.html
281 lines (252 loc) · 15.4 KB
/
example.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
---
title: FLIF - Example
group: menu
menu_title: Example
---
{% include header.html %}
<h1 id="flif-by-example"><a href="/index.html">FLIF</a> by Example</h1>
<p>Here is an example that illustrates some of the strengths of <a href="/index.html">FLIF</a>. Consider the following image from <a href="http://pngimg.com/download/1156">pngimg.com</a>. It is a 1969x1307 image with four 8-bit channels (three for RGB color and one for alpha/transparency).</p>
<img src="/example-images/fish.png" class="show_bg" alt="Example image of a fish" />
<h2 id="lossless-compression">Lossless compression</h2>
<p>Here are the sizes of this image in various image file formats:</p>
<ul>
<li><strong>10,293,932</strong> bytes for uncompressed RGBA</li>
<li><strong>693,075</strong> bytes for PNG with Adam7 interlacing</li>
<li><strong>657,022</strong> bytes for PNG with Adam7 interlacing after brute-force pngcrush</li>
<li><strong>562,214</strong> bytes for JPEG 2000 (lossless)</li>
<li><strong>533,004</strong> bytes for the original PNG file as found on <a href="http://pngimg.com/download/1156">pngimg.com</a></li>
<li><strong>495,625</strong> bytes for PNG, after brute-force pngcrush</li>
<li><strong>447,419</strong> bytes for PNG, using PNGOUT</li>
<li><strong>334,889</strong> bytes for BPG (lossless)</li>
<li><strong>328,650</strong> bytes for WebP (lossless)</li>
<li><strong>299,643</strong> bytes for FLIF</li>
<li><strong>282,655</strong> bytes for FLIF without interlacing</li>
</ul>
<p>OK, so in lossless compression, FLIF wins (though BPG and WebP are not far behind).</p>
<h2 id="lossy-compression">Lossy compression</h2>
<p>What about lossy compression?</p>
<ul>
<li>WebP, JPEG 2000 and BPG have a lossy mode (in fact that is their default mode), so we can use that to produce smaller files.</li>
<li>FLIF does not have a lossy mode, but interlaced files can be decoded progressively so we can simply use something like <code>dd if=lossless.flif of=lossy.flif bs=1024 count=50</code> to produce a lossy file of an arbitrary size (in this case 50 KB).</li>
<li>PNG also does not have a lossy mode, but Adam7 interlaced files can be decoded progressively.</li>
</ul>
<p>Let us compare the compression artifacts of the different formats. We'll look at partial FLIF and PNG files, and compare with lossy WebP, lossy JPEG 2000, lossy BPG, and the older standard formats GIF and JPEG.</p>
<p>Note that what we will be doing is not a fair comparison. It heavily disadvantages FLIF and PNG, because we are looking at different-sized first parts of <strong>one file</strong> (the one that eventually leads to a lossless image), while for the other formats, we look at <strong>multiple files</strong>, each optimized for a specific quality setting.</p>
<p>To make it easier to compare the image quality, only part of the images are shown here. You can click on the image to see the full image.</p>
<p>The smallest possible file I could produce with existing image formats, was a <a href="/example-images/fish-1.jpg">16,977 bytes JPEG file</a> (encoded using the lowest possible quality setting). Obviously, this is extremely lossy: JPEG does not support transparency at all, quantization is extreme, etc. Here are the resulting images at this size:</p>
<table>
<tr>
<th>Original (lossless)</th>
<th>Partially loaded FLIF (16,977 first bytes of a 299,643 byte file)</th>
<th>Partially loaded PNG (16,977 first bytes of a 657,022 byte file)</th>
<th>Partially loaded lossy GIF (16,977 first bytes of a 219,377 byte file)</th>
<th>Lossy BPG (15,411 bytes)</th>
<th>Lossy WebP</th>
<th>Lossy JPEG 2000 (16,962 bytes)</th>
<th>Lossy JPEG (16,977 bytes)</th>
</tr>
<tr>
<td>
<a href="/example-images/fish.png" class="img">
<img src="/example-images/fish.png-cropped.png" class="show_bg" alt="Example image of a fish" />
</a>
</td>
<td>
<a href="/example-images/fish-flif16977.png" class="img">
<img src="/example-images/fish-flif16977.png-cropped.png" class="show_bg" alt="Example image of a fish" />
</a>
</td>
<td>
<a href="/example-images/fish-Adam7-16977.png" class="img">
<img src="/example-images/fish-Adam7-16977.png-cropped.png" class="show_bg" alt="Example image of a fish" />
</a>
</td>
<td>
<a href="/example-images/fish-interlaced.gif-16977.gif" class="img">
<img src="/example-images/fish-interlaced.gif-16977.png-cropped.png" class="show_bg" alt="Example image of a fish" />
</a>
</td>
<td>
<a href="/example-images/fish-lossy36.bpg.png" class="img">
<img src="/example-images/fish-lossy36.bpg.png-cropped.png" class="show_bg" alt="Example image of a fish" />
</a>
</td>
<td>no WebP at this size</td>
<td>
<a href="/example-images/fish-lossy607.jp2.png" class="img">
<img src="/example-images/fish-lossy607.jp2.png-cropped.png" class="show_bg" alt="Example image of a fish" />
</a>
</td>
<td>
<a href="/example-images/fish-1.jpg" class="img">
<img src="/example-images/fish-1.jpg-cropped.png" class="show_bg" alt="Example image of a fish" />
</a>
</td>
</tr>
</table>
<p>The winner? In my opinion, BPG looks best here. But keep in mind that this is a completely different BPG file than the lossless BPG file. Also, the BPG encoder is very slow.</p>
<p>The smallest WebP file I could produce (using <code>cwebp -q 1 -alpha_q 1 -m 6</code>) has a size of 22,702 bytes. Let's take a look:</p>
<table>
<tr>
<th>Original (lossless)</th>
<th>Partially loaded FLIF (22,702 first bytes of a 299,643 byte file)</th>
<th>Partially loaded PNG (22,702 first bytes of a 657,022 byte file)</th>
<th>Partially loaded lossy GIF (22,702 first bytes of a 219,377 byte file)</th>
<th>Lossy BPG (22,024 bytes)</th>
<th>Lossy WebP (22,702 bytes)</th>
<th>Lossy JPEG 2000 (22,676 bytes)</th>
<th>Lossy JPEG (22,749 bytes)</th>
</tr>
<tr>
<td>
<a href="/example-images/fish.png" class="img">
<img src="/example-images/fish.png-cropped.png" class="show_bg" alt="Example image of a fish" />
</a>
</td>
<td>
<a href="/example-images/fish-flif22702.png" class="img">
<img src="/example-images/fish-flif22702.png-cropped.png" class="show_bg" alt="Example image of a fish" />
</a>
</td>
<td>
<a href="/example-images/fish-Adam7-22702.png" class="img">
<img src="/example-images/fish-Adam7-22702.png-cropped.png" class="show_bg" alt="Example image of a fish" />
</a>
</td>
<td>
<a href="/example-images/fish-interlaced.gif-22702.gif" class="img">
<img src="/example-images/fish-interlaced.gif-22702.png-cropped.png" class="show_bg" alt="Example image of a fish" />
</a>
</td>
<td>
<a href="/example-images/fish-lossy33.bpg.png" class="img">
<img src="/example-images/fish-lossy33.bpg.png-cropped.png" class="show_bg" alt="Example image of a fish" />
</a>
</td>
<td>
<a href="/example-images/fish-lossy_1_1.webp.png" class="img">
<img src="/example-images/fish-lossy_1_1.webp.png-cropped.png" class="show_bg" alt="Example image of a fish" />
</a>
</td>
<td>
<a href="/example-images/fish-lossy454.jp2.png" class="img">
<img src="/example-images/fish-lossy454.jp2.png-cropped.png" class="show_bg" alt="Example image of a fish" />
</a>
</td>
<td>
<a href="/example-images/fish-10.jpg" class="img">
<img src="/example-images/fish-10.jpg-cropped.png" class="show_bg" alt="Example image of a fish" />
</a>
</td>
</tr>
</table>
<p>Again, the BPG file looks best. I would say FLIF is second best. Now, let's give WebP some more bytes to work with. With <code>cwebp -q 20 -alpha_q 20 -m 6</code>) I got a .webp file with a size of 40,100 bytes.</p>
<table>
<tr>
<th>Original (lossless)</th>
<th>Partially loaded FLIF (40,100 first bytes of a 299,643 byte file)</th>
<th>Partially loaded PNG (40,100 first bytes of a 657,022 byte file)</th>
<th>Partially loaded lossy GIF (40,100 first bytes of a 219,377 byte file)</th>
<th>Lossy BPG (38,590 bytes)</th>
<th>Lossy WebP (40,100 bytes)</th>
<th>Lossy JPEG 2000 (40,024 bytes)</th>
<th>Lossy JPEG (40,442 bytes)</th>
</tr>
<tr>
<td>
<a href="/example-images/fish.png" class="img">
<img src="/example-images/fish.png-cropped.png" class="show_bg" alt="Example image of a fish" />
</a>
</td>
<td>
<a href="/example-images/fish-flif40100.png" class="img">
<img src="/example-images/fish-flif40100.png-cropped.png" class="show_bg" alt="Example image of a fish" />
</a>
</td>
<td>
<a href="/example-images/fish-Adam7-40100.png" class="img">
<img src="/example-images/fish-Adam7-40100.png-cropped.png" class="show_bg" alt="Example image of a fish" />
</a>
</td>
<td>
<a href="/example-images/fish-interlaced.gif-40100.gif" class="img">
<img src="/example-images/fish-interlaced.gif-40100.png-cropped.png" class="show_bg" alt="Example image of a fish" />
</a>
</td>
<td>
<a href="/example-images/fish-lossy27.bpg.png" class="img">
<img src="/example-images/fish-lossy27.bpg.png-cropped.png" class="show_bg" alt="Example image of a fish" />
</a>
</td>
<td>
<a href="/example-images/fish-lossy_20_20.webp.png" class="img">
<img src="/example-images/fish-lossy_20_20.webp.png-cropped.png" class="show_bg" alt="Example image of a fish" />
</a>
</td>
<td>
<a href="/example-images/fish-lossy257.jp2.png" class="img">
<img src="/example-images/fish-lossy257.jp2.png-cropped.png" class="show_bg" alt="Example image of a fish" />
</a>
</td>
<td>
<a href="/example-images/fish-36.jpg" class="img">
<img src="/example-images/fish-36.jpg-cropped.png" class="show_bg" alt="Example image of a fish" />
</a>
</td>
</tr>
</table>
<h2 id="progressive-decoding">Progressive decoding</h2>
<p>What about progressive decoding of the other lossless formats?</p>
<ul>
<li>Lossless WebP does not support progressive decoding (it will simply refuse to decode incomplete files).</li>
<li>JPEG 2000 supposedly does support progressive decoding but I haven't found a way yet to do that (please help me if you know a way!).</li>
<li>BPG makes no claims about progressive decoding, but trying to decode an incomplete file does sometimes work.</li>
</ul>
<p>BPG is very good at lossy compression, but its lossless files cannot be progressively decoded very well. In this example, <code>bpgdec</code> only wanted to decode the lossless BPG file after about 90,000 bytes were downloaded, and then still only the alpha channel seems to be OK:</p>
<table>
<tr>
<th>Partially loaded FLIF (90,000 first bytes of a 299,643 byte file)</th>
<th>Partially loaded BPG (90,000 first bytes of a 334,889 byte file)</th>
</tr>
<tr>
<td>
<a href="/example-images/fish-flif90000.png" class="img">
<img src="/example-images/fish-flif90000.png-cropped.png" class="show_bg" alt="Example image of a fish" />
</a>
</td>
<td>
<a href="/example-images/fish-lossless.bpg-90000.png" class="img">
<img src="/example-images/fish-lossless.bpg-90000.png-cropped.png" class="show_bg" alt="Example image of a fish" />
</a>
</td>
</tr>
</table>
<p>Even after 200,000 bytes, the lossless BPG file still looks pretty bad:</p>
<table>
<tr>
<th>Partially loaded FLIF (200,000 first bytes of a 299,643 byte file)</th>
<th>Partially loaded BPG (200,000 first bytes of a 334,889 byte file)</th>
</tr>
<tr>
<td>
<a href="/example-images/fish-flif200000.png" class="img">
<img src="/example-images/fish-flif200000.png-cropped.png" class="show_bg" alt="Example image of a fish" />
</a>
</td>
<td>
<a href="/example-images/fish-lossless.bpg-200000.png" class="img">
<img src="/example-images/fish-lossless.bpg-200000.png-cropped.png" class="show_bg" alt="Example image of a fish" />
</a>
</td>
</tr>
</table>
<p>WebP does not support progressive decoding at all. JPEG 2000 supposedly does, but I couldn't find any program that can handle partial JPEG 2000 files. So besides FLIF, the only real choice for a progressively downloading lossless format would be PNG with Adam7 interlacing. But in this example, that would be a file that is twice as large. In general, FLIF files are about <a href="https://docs.google.com/spreadsheets/d/16ghJEjf_T7TDTOg2WlelnG1SYCsHng6V-1rxdo78YL8/edit?usp=sharing">39% smaller</a> than PNG files with Adam7 interlacing (even after pngcrushing them).</p>
<h2 id="responsive-images">Responsive images</h2>
<p>The original image is 1969x1307 pixels, which is quite big. Most likely your browser has to scale the image down so it fits the available space:</p>
<img src="/example-images/fish.png" class="show_bg" alt="Example image of a fish" />
<p>As said before, the above image can be encoded in FLIF using 299,643 bytes. However, using <code>flif -d -s 2</code>, a downscaled image can be decoded at scale 1:2, which results in the following 653x985 image after reading only the first 80,389 bytes of the file:</p>
<img src="/example-images/fish-flif-s2.png" class="show_bg" alt="Example image of a fish" />
<p>If scale 1:4 is good enough (e.g. you're viewing the image on a smartphone), then you can get the following 492x326 image from the first 37,014 bytes of the FLIF file:</p>
<img src="/example-images/fish-flif-s4.png" class="show_bg" alt="Example image of a fish" />
</body>
</html>