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