latin: unistrokes circles matched separately
[sheet.git] / codec-image.inc.pl
1 use utf8;
2 +{
3 intro => 'Comparison of image encoding formats, based on <a href="https://cloudinary.com/blog/one_pixel_is_worth_three_thousand_words">Cloudinary</a> research.',
4 codec => {
5         jpeg => {
6                 name => '<abbr title="Joint Photographic Experts Group">JPEG</abbr>',
7                 available => 1992,
8                 generation => 0,
9         },
10         gif => {
11                 name => '<abbr title="Graphics Interchange Format">GIF</abbr>',
12                 available => 1987,
13                 generation => 0,
14         },
15         png => {
16                 name => '<abbr title="Portable Network Graphics">PNG</abbr>',
17                 available => 1996,
18                 generation => 1,
19         },
20         jp2k => {
21                 name => 'JPEG 2000',
22                 available => 2000,
23                 generation => 1,
24         },
25         webp => {
26                 name => 'WebP',
27                 available => 2010,
28                 generation => 1,
29         },
30         heic => {
31                 name => '<abbr title="High Efficiency Image Container (HEVC in HEIF)">HEIC</abbr>',
32                 available => 2015,
33                 generation => 2,
34         },
35         avif => {
36                 name => '<abbr title="AV1 Image File Format">AVIF</abbr>',
37                 available => 2019,
38                 generation => 2,
39         },
40         jxl => {
41                 name => 'JPEG XL',
42                 available => 2021,
43                 generation => 2,
44         },
45         pnm => {
46                 name => '<abbr title="Portable aNyMap">PNM</abbr>',
47                 available => 1988,
48                 generation => 0,
49         },
50 },
51 feature => {
52         default => {
53                 children => [qw( quality_photo quality_art speed limits features royalties overhead support )],
54         },
55         quality_photo => {
56                 name => 'compression (photo)',
57                 score => {
58                         jpeg => 3,
59                         pnm  => 'n',
60                         gif  => 1,
61                         png  => 1,
62                         jp2k => 4,
63                         webp => 3,
64                         heic => 5,
65                         avif => 5,
66                         jxl  => 5,
67                 },
68                 children => [qw( quality_photo_1 quality_photo_2 quality_photo_3 quality_photo_ll )],
69         },
70         quality_photo_1 => {
71                 parent => 'quality_photo',
72                 name => 'thumbnails',
73                 score => {
74                         jpeg => 2,
75                         pnm  => 1,
76                         gif  => 1,
77                         png  => 1,
78                         jp2k => 3,
79                         webp => 4,
80                         heic => 5,
81                         avif => 5,
82                         jxl  => 3,
83                 },
84         },
85         quality_photo_2 => {
86                 parent => 'quality_photo',
87                 name => 'medium fidelity',
88                 score => {
89                         jpeg => 3,
90                         pnm  => 1,
91                         gif  => 1,
92                         png  => 1,
93                         jp2k => 4,
94                         webp => 3,
95                         heic => 4,
96                         avif => 5,
97                         jxl  => 5,
98                 },
99         },
100         quality_photo_3 => {
101                 parent => 'quality_photo',
102                 name => 'high fidelity',
103                 score => {
104                         jpeg => 3,
105                         pnm  => 1,
106                         gif  => 1,
107                         png  => 2,
108                         jp2k => 4,
109                         webp => 2,
110                         heic => 3,
111                         avif => 4,
112                         jxl  => 5,
113                 },
114         },
115         quality_photo_ll => {
116                 parent => 'quality_photo',
117                 name => 'lossless',
118                 score => {
119                         jpeg => 1,
120                         pnm  => 1,
121                         gif  => 1,
122                         png  => 2,
123                         jp2k => 4,
124                         webp => 3,
125                         heic => 3,
126                         avif => 3,
127                         jxl  => 5,
128                 },
129         },
130         quality_art => {
131                 name => 'compression (other images)',
132                 score => {
133                         jpeg => 2,
134                         pnm  => 'n',
135                         gif  => 1,
136                         png  => 3,
137                         jp2k => 2,
138                         webp => 4,
139                         heic => 3,
140                         avif => 4.5,
141                         jxl  => 5,
142                 },
143                 children => [qw( quality_art_2 quality_art_ll quality_art_mixed )],
144         },
145         quality_art_2 => {
146                 name => 'lossy non-photographic',
147                 score => {
148                         jpeg => 2,
149                         pnm  => 1,
150                         gif  => 2,
151                         png  => 3,
152                         jp2k => 2,
153                         webp => 4,
154                         heic => 3,
155                         avif => 5,
156                         jxl  => 5,
157                 },
158         },
159         quality_art_ll => {
160                 name => 'lossless non-photographic',
161                 score => {
162                         jpeg => 1,
163                         pnm  => 1,
164                         gif  => 1,
165                         png  => 4,
166                         jp2k => 2,
167                         webp => 5,
168                         heic => 2,
169                         avif => 3,
170                         jxl  => 5,
171                 },
172         },
173         quality_art_mixed => {
174                 name => 'mixed photo/nonphoto',
175                 score => {
176                         jpeg => 2,
177                         pnm  => 1,
178                         gif  => 1,
179                         png  => 2,
180                         jp2k => 2,
181                         webp => 3,
182                         heic => 3,
183                         avif => 5,
184                         jxl  => 5,
185                 },
186         },
187         speed => {
188                 score => {
189                         jpeg => 5,
190                         pnm  => 5,
191                         gif  => 4,
192                         png  => 4,
193                         jp2k => 3,
194                         webp => 4,
195                         heic => 3,
196                         avif => 3,
197                         jxl  => 5,
198                 },
199                 children => [qw( speed_encode speed_decode speed_parallel )],
200         },
201         speed_encode => {
202                 parent => 'speed',
203                 name => 'single-core encode',
204                 score => {
205                         jpeg => 5,
206                         pnm  => 0,
207                         gif  => 3, # palette conversion
208                         png  => 3,
209                         jp2k => 4,
210                         webp => 4,
211                         heic => 3,
212                         avif => 2,
213                         jxl  => 5,
214                 },
215         },
216         speed_decode => {
217                 parent => 'speed',
218                 name => 'single-core decode',
219                 score => {
220                         jpeg => 5,
221                         pnm  => 0,
222                         gif  => 5,
223                         png  => 5,
224                         jp2k => 4,
225                         webp => 5,
226                         heic => 3,
227                         avif => 3,
228                         jxl  => 5,
229                 },
230         },
231         speed_parallel => {
232                 parent => 'speed',
233                 name => 'pararellizable',
234                 score => {
235                         jpeg => 2,
236                         pnm  => 0,
237                         gif  => 2,
238                         png  => 2,
239                         jp2k => 4,
240                         webp => 2,
241                         heic => 4,
242                         avif => 4,
243                         jxl  => 5,
244                 },
245         },
246         limits => {
247                 score => {
248                         jpeg => 3,
249                         pnm  => 3,
250                         gif  => 2,
251                         png  => 4,
252                         jp2k => 5,
253                         webp => 2,
254                         heic => 4,
255                         avif => 4.5,
256                         jxl  => 5,
257                 },
258                 children => [qw( max_dimensions max_bitdepth color_444 hdr max_channels  )],
259         },
260         max_dimensions => {
261                 parent => 'limits',
262                 name => 'maximum image dimensions',
263                 score => {
264                         jpeg => [3, '65k²'],   # 2**16
265                         pnm  => [5,    '∞'],
266                         gif  => [3, '65k²'],   # 2**16
267                         png  => [4,  '2G²'],   # 2**31
268                         jp2k => [4,  '4G²'],   # 2**32
269                         webp => [1, '16k²'],   # 2**14
270                         heic => [2,'8k×4k+', 'tilable, only 512×512 on Apple'], # 8193x4320
271                         avif => [3, '65k²+', 'tilable, 7680×4320 with Advanced profile'], # 2**16
272                         jxl  => [4,  '1G²'],   # 2**30
273                 },
274         },
275         max_bitdepth => {
276                 parent => 'limits',
277                 name => 'precision (max. bit depth)',
278                 score => {
279                         jpeg => [2,  8],
280                         pnm  => [2,  8, 'unofficial PFM extension for 32-bit'],
281                         gif  => [1,  8, '256 colour palette per frame'],
282                         png  => [4, 16],
283                         jp2k => [5, 38],
284                         webp => [2,  8],
285                         heic => [3, 10], #TODO 16?
286                         avif => [3, 12, '8, 10, 12 bit'],
287                         jxl  => [5, 32, '24-bit integer or 32-bit float'],
288                 },
289         },
290         color_444 => {
291                 parent => 'limits',
292                 name => 'chroma subsampling',
293                 score => {
294                         jpeg => ['y', undef, '4:2:0, 4:2:2, 4:4:4'],
295                         pnm  => [4, '✘'],
296                         gif  => [4, '✘'],
297                         png  => [4, '✘'],
298                         jp2k => 'y',
299                         webp => [1, '4:2:0'],
300                         heic => [1, '4:2:0'],
301                         avif => ['y', undef, '4:2:0, 4:2:2, 4:4:4'],
302                         jxl  => ['y', undef, 'for JPEG compatibility'],
303                 },
304         },
305         hdr => {
306                 parent => 'limits',
307                 name => 'wide gamut/HDR',
308                 score => {
309                         jpeg => 'n',
310                         pnm  => 'n',
311                         gif  => 'n',
312                         png  => 'y',
313                         jp2k => 'y',
314                         webp => 'n',
315                         heic => 'y',
316                         avif => 'y',
317                         jxl  => 'y',
318                 },
319         },
320         max_channels => {
321                 parent => 'limits',
322                 name => 'maximum number of channels',
323                 score => {
324                         jpeg => [3, 4, 'RGB or CMYK'],
325                         pnm  => [3, 3, 'RGB'],
326                         gif  => [3, 3, 'RGB palette'],
327                         png  => [3, 4, 'RGBA'],
328                         jp2k => [5, 2**15],
329                         webp => [3, 4, 'RGBA'],
330                         heic => [3, 3, 'RGB, separate alpha and depth'],
331                         avif => [3, 3, 'RGB, separate alpha and depth'],
332                         jxl  => [4, 4099, 'native XYB'],
333                 },
334         },
335         features => {
336                 score => {
337                         jpeg => 2,
338                         pnm  => [2, undef, 'great for simplicity and ASCII storage'],
339                         gif  => 2,
340                         png  => 3,
341                         jp2k => 4,
342                         webp => 2,
343                         heic => 4,
344                         avif => 4,
345                         jxl  => 5,
346                 },
347                 children => [qw( animation progressive alpha depthmap overlays authoring reencode compat_jpeg )],
348         },
349         animation => {
350                 parent => 'features',
351                 name => 'supports animation',
352                 score => {
353                         jpeg => [2, 'MJPEG'],
354                         pnm  => 'n',
355                         gif  => 'y',
356                         png  => [4, 'APNG', 'later backwards-compatible extension'],
357                         jp2k => [2, 'MJP2'],
358                         webp => 'y',
359                         heic => 'y',
360                         avif => 'y',
361                         jxl  => 'y',
362                 },
363         },
364         progressive => {
365                 parent => 'features',
366                 name => 'progressive decoding',
367                 score => {
368                         jpeg => 4,
369                         pnm  => 'n',
370                         gif  => 2,
371                         png  => 2,
372                         jp2k => 5,
373                         webp => 'n',
374                         heic => 'n',
375                         avif => 'n',
376                         jxl  => 5,
377                 },
378         },
379         alpha => {
380                 parent => 'features',
381                 name => 'alpha transparency',
382                 score => {
383                         jpeg => 'n',
384                         pnm  => ['n', undef, 'PAM extension'],
385                         gif  => [3, '1 bit'],
386                         png  => 'y',
387                         jp2k => 'y',
388                         webp => 'y',
389                         heic => 'y',
390                         avif => 'y',
391                         jxl  => 'y',
392                 },
393         },
394         depthmap => {
395                 parent => 'features',
396                 name => 'depth map',
397                 score => {
398                         jpeg => 'n',
399                         pnm  => 'n',
400                         gif  => 'n',
401                         png  => 'n',
402                         jp2k => 'n',
403                         webp => 'n',
404                         heic => 'y',
405                         avif => 'y',
406                         jxl  => 'y',
407                 },
408         },
409         overlays => {
410                 parent => 'features',
411                 name => 'overlays (layers)',
412                 score => {
413                         jpeg => 'n',
414                         pnm  => 'n',
415                         gif  => 'y',
416                         png  => 'n',
417                         jp2k => 'n',
418                         webp => 'n',
419                         heic => 'y',
420                         avif => 'y',
421                         jxl  => 'y',
422                 },
423         },
424         authoring => {
425                 parent => 'features',
426                 name => 'authoring workflow suitability',
427                 score => {
428                         jpeg => 2,
429                         pnm  => 2,
430                         gif  => 2,
431                         png  => 3,
432                         jp2k => 3,
433                         webp => 2,
434                         heic => 2,
435                         avif => 2,
436                         jxl  => 5,
437                 },
438         },
439         reencode => {
440                 parent => 'features',
441                 name => 'generation loss resilience',
442                 score => {
443                         jpeg => 4,
444                         pnm  => 0,
445                         png  => 0,
446                         gif  => 0,
447                         jp2k => 3,
448                         webp => 2,
449                         heic => 3,
450                         avif => 3,
451                         jxl  => 4,
452                 },
453         },
454         compat_jpeg => {
455                 parent => 'features',
456                 name => 'lossless JPEG recompression',
457                 score => {
458                         jpeg => 0,
459                         pnm  => 'n',
460                         gif  => 'n',
461                         png  => 'n',
462                         jp2k => 'n',
463                         webp => 'n',
464                         heic => 'n',
465                         avif => 'n',
466                         jxl  => 'y',
467                 },
468         },
469         royalties => {
470                 name => 'royalty-free',
471                 score => {
472                         jpeg => 5,
473                         pnm  => 5,
474                         gif  => [5, undef, 'patented before 2003'],
475                         png  => 5,
476                         jp2k => [3, undef, 'ISO specification not freely available'],
477                         webp => [4, undef, 'free format, low remaining risk of patent trolls'],
478                         heic => ['n', undef, 'heavily patented'],
479                         avif => [4, undef, 'free format, risk of patent trolls'],
480                         jxl  => [4, undef, 'free format, risk of patent trolls'],
481                 },
482                 children => [],
483         },
484         support => {
485                 score => {
486                         jpeg => 5,
487                         pnm  => [2, undef],
488                         gif  => 5,
489                         png  => 5,
490                         jp2k => [2, undef, 'Apple only'],
491                         webp => [4, undef, 'modern browsers'],
492                         heic => [1, undef, 'stored by latest cameras, no browser support'],
493                         avif => [3, undef, 'all modern browsers except Safari and Edge'],
494                         jxl  => [2, undef, 'upcoming in most browsers'],
495                 },
496         },
497         overhead => {
498                 name => 'container overhead (file size)',
499                 score => {
500                         png  => [3,  67, 'upto 70 bytes for specific RGBA'],
501                         jpeg => [2, 160, '159 bytes minimum for gray, 288 for specific colours'],
502                         gif  => [4,  35, '43 bytes for transparent'],
503                         webp => [4,  34, 'black or transparent lossless; 44-92 bytes lossy'],
504                         bpg  => [4,  31, 'lossy 29-62 bytes, lossless 37-160'],
505                         flif => [5,  14, 'black or transparent; 20 bytes for specific RGBA'],
506                         pnm  => [5,   8, 'monochrome text PBM; 12 bytes PPM; 69 bytes PAM'],
507                         jxl  => [5,  12, '512×256 black pixels'],
508                         avif => [1, 282, 'container overhead; 457 bytes with alpha'],
509                         jp2k => [2, 123, 'experimental results, likely not optimal'],
510                         heic => [1, 386],
511                 },
512         },
513 },
514 }