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