forked from external-repos/squoosh
Compare commits
719 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1fb445b06 | ||
|
|
8a516131ea | ||
|
|
9816be83ab | ||
|
|
57418034c4 | ||
|
|
3892490023 | ||
|
|
5bedff583b | ||
|
|
d94835402f | ||
|
|
b7e45ab843 | ||
|
|
8313246fd1 | ||
|
|
2b3cafb1f4 | ||
|
|
d52698f005 | ||
|
|
6ad28c0b5c | ||
|
|
c76dabf063 | ||
|
|
e6d8bac9c5 | ||
|
|
42e43730c8 | ||
|
|
5c17fba349 | ||
|
|
85eb94b725 | ||
|
|
4fa73be842 | ||
|
|
7c89d09139 | ||
|
|
079e56f1e1 | ||
|
|
6065ceabfe | ||
|
|
265e6db2bd | ||
|
|
3a5c0aa30c | ||
|
|
f0c3ec9d51 | ||
|
|
1ae93b527c | ||
|
|
a95cb740bf | ||
|
|
de543b3206 | ||
|
|
1542bfb7fd | ||
|
|
bc8d75128f | ||
|
|
d3252bb1bb | ||
|
|
83d9d2c764 | ||
|
|
476268fe19 | ||
|
|
74492af675 | ||
|
|
bd4179aff2 | ||
|
|
27ae47117e | ||
|
|
7da3f07333 | ||
|
|
eeb3d3562a | ||
|
|
2d73c24e09 | ||
|
|
ed666dd381 | ||
|
|
6f18f08a8e | ||
|
|
eae808cb6f | ||
|
|
0ae99c9228 | ||
|
|
f4a16022ef | ||
|
|
12153c72dc | ||
|
|
ae7782031d | ||
|
|
7cd6487a28 | ||
|
|
62c53c9fed | ||
|
|
53a38b2ba1 | ||
|
|
f3dfcae3f0 | ||
|
|
3f7274a6ac | ||
|
|
f5bc715bc0 | ||
|
|
22b7e36c01 | ||
|
|
a0e6a377cd | ||
|
|
22b04c159d | ||
|
|
92249ac711 | ||
|
|
629d64326d | ||
|
|
4621cbcae9 | ||
|
|
164191d746 | ||
|
|
b22adc9957 | ||
|
|
6b0a675469 | ||
|
|
d7fb0d9b40 | ||
|
|
309947a08f | ||
|
|
6aeaae6160 | ||
|
|
71b3c7dda2 | ||
|
|
48c06e86fa | ||
|
|
1b7d3fa394 | ||
|
|
650db99818 | ||
|
|
7638bb795e | ||
|
|
570e604be0 | ||
|
|
a056d1c363 | ||
|
|
fce61c8c89 | ||
|
|
d60d0ae47d | ||
|
|
8bf741ed4e | ||
|
|
9f660e5178 | ||
|
|
ef2318bcc1 | ||
|
|
364a5db5d5 | ||
|
|
4a01d0d548 | ||
|
|
4a9c28f89f | ||
|
|
3aed873467 | ||
|
|
2b7f059b8f | ||
|
|
33726e9c68 | ||
|
|
3d29f486e7 | ||
|
|
79e8a26f06 | ||
|
|
e8efd54766 | ||
|
|
edcc774c16 | ||
|
|
746b33a590 | ||
|
|
8a264efc67 | ||
|
|
f0af6e97a0 | ||
|
|
043107c101 | ||
|
|
e9e3b923e0 | ||
|
|
aea6e91b1d | ||
|
|
9c4717a13d | ||
|
|
559cabce9e | ||
|
|
7f6a3de7ca | ||
|
|
f3adc87f52 | ||
|
|
6499e9f63d | ||
|
|
ac1f104e49 | ||
|
|
87f89e6b2f | ||
|
|
7f6404d5a8 | ||
|
|
8e857cd393 | ||
|
|
b8f801333d | ||
|
|
499956e216 | ||
|
|
3932ee2c00 | ||
|
|
68177b7590 | ||
|
|
0a2a4122dc | ||
|
|
e6299569d0 | ||
|
|
578ad8c291 | ||
|
|
eaa294b689 | ||
|
|
6e97cfb8d5 | ||
|
|
80a68c48b2 | ||
|
|
98865f8141 | ||
|
|
78da9fd144 | ||
|
|
94c50a989b | ||
|
|
3e525e767c | ||
|
|
dfcc1e24e4 | ||
|
|
f3aa8edfca | ||
|
|
ffd7ee6013 | ||
|
|
64bb09dbc5 | ||
|
|
35fcbc40ed | ||
|
|
1b55a48680 | ||
|
|
88fbb19d29 | ||
|
|
3dc1501ff7 | ||
|
|
b7576c559a | ||
|
|
69ed2e1d56 | ||
|
|
55f7f3d72a | ||
|
|
055d0b4ea1 | ||
|
|
7735346ed0 | ||
|
|
2a06fdbbe0 | ||
|
|
19169199e9 | ||
|
|
76f3c39b78 | ||
|
|
8da52acc4c | ||
|
|
9253522a3a | ||
|
|
cf39a3e5a5 | ||
|
|
a08877f0ac | ||
|
|
2f0dc1c067 | ||
|
|
535d8c9142 | ||
|
|
6dc2ba3bef | ||
|
|
93cfdc8f98 | ||
|
|
671544349e | ||
|
|
d3c1939692 | ||
|
|
99642aef96 | ||
|
|
ac4942b640 | ||
|
|
23cb004a86 | ||
|
|
4b6de60978 | ||
|
|
de204aa56a | ||
|
|
976f811b36 | ||
|
|
855fc9e602 | ||
|
|
a8848e717c | ||
|
|
90b99faf8b | ||
|
|
d3cfffbbcf | ||
|
|
fade7f9be8 | ||
|
|
b10dd055d3 | ||
|
|
7532f01222 | ||
|
|
2df09efdee | ||
|
|
bed4f49a12 | ||
|
|
2b7fefff8b | ||
|
|
bdcf2519ce | ||
|
|
3f8afb72a6 | ||
|
|
2f834db224 | ||
|
|
3541ce7492 | ||
|
|
b6fae0eb4c | ||
|
|
fbaa282f07 | ||
|
|
6136ae7411 | ||
|
|
f024747299 | ||
|
|
66feffcc49 | ||
|
|
24254df7db | ||
|
|
cae73f1f1b | ||
|
|
073a52213e | ||
|
|
0d34485a00 | ||
|
|
65519d539e | ||
|
|
ec44a8e817 | ||
|
|
920f225cb0 | ||
|
|
d5d4bd61ff | ||
|
|
5656d10b67 | ||
|
|
adb4b6468b | ||
|
|
0a293d7f63 | ||
|
|
27cb5afd5b | ||
|
|
5e58fc6b04 | ||
|
|
e820adfc96 | ||
|
|
5a8a114dcb | ||
|
|
a1c685e820 | ||
|
|
377dcfcc1b | ||
|
|
913e67ca93 | ||
|
|
fb1a97c7d4 | ||
|
|
42eef6945d | ||
|
|
d04b08d640 | ||
|
|
c547dd10d3 | ||
|
|
f4579da9c9 | ||
|
|
37dc585d80 | ||
|
|
bc0a425a0f | ||
|
|
b696f246a1 | ||
|
|
e6e197e140 | ||
|
|
1c0e8a1fd3 | ||
|
|
e3e154fa1a | ||
|
|
73b7c437f9 | ||
|
|
719168be77 | ||
|
|
a2021b175c | ||
|
|
9a388fbd13 | ||
|
|
1ba0452540 | ||
|
|
73df9f18f0 | ||
|
|
0e7521877b | ||
|
|
120b37c192 | ||
|
|
5f3502b838 | ||
|
|
33f99432c5 | ||
|
|
85756ff5df | ||
|
|
84e567ad6a | ||
|
|
39281331fa | ||
|
|
438ce2ce63 | ||
|
|
a13e17e256 | ||
|
|
cd6db2d776 | ||
|
|
a08662b617 | ||
|
|
003ec9de35 | ||
|
|
e7f76ca0b8 | ||
|
|
21111e2927 | ||
|
|
445c3ef32c | ||
|
|
9df5542ee1 | ||
|
|
fffc4a0cd1 | ||
|
|
50a8743be3 | ||
|
|
8480bc7dbd | ||
|
|
72e4546922 | ||
|
|
11be5babca | ||
|
|
17e5db2427 | ||
|
|
465093eb07 | ||
|
|
b430ac1041 | ||
|
|
ea96847c1e | ||
|
|
3b5106a61d | ||
|
|
9f611b0b52 | ||
|
|
18a6b3c3e5 | ||
|
|
d9ed4e18ea | ||
|
|
9e757aa896 | ||
|
|
89b58bb446 | ||
|
|
e80ca583cc | ||
|
|
2ecc81b34f | ||
|
|
60e98ee34f | ||
|
|
538ea89ea9 | ||
|
|
3990e11e0a | ||
|
|
0251f88fe5 | ||
|
|
bbcb959b11 | ||
|
|
b5e928bac9 | ||
|
|
6592dee4a9 | ||
|
|
9b3d72191e | ||
|
|
a92e5b48ff | ||
|
|
e355764ab0 | ||
|
|
c5efd5a8bf | ||
|
|
385461944b | ||
|
|
8385ba3274 | ||
|
|
6ca6a77595 | ||
|
|
14c837e894 | ||
|
|
33346d7cb6 | ||
|
|
05d4f531e2 | ||
|
|
ede2c49b12 | ||
|
|
16acd32c68 | ||
|
|
cc90192860 | ||
|
|
3607005fa8 | ||
|
|
7646a64f94 | ||
|
|
c8ce6ce27b | ||
|
|
1240474c4b | ||
|
|
f5e84441c0 | ||
|
|
6bc19d78bc | ||
|
|
a4437d2873 | ||
|
|
cd19650748 | ||
|
|
253315b3b1 | ||
|
|
4203ad9a13 | ||
|
|
6958202f9d | ||
|
|
386fef063f | ||
|
|
d7246ca427 | ||
|
|
fd024853b6 | ||
|
|
bd53d17876 | ||
|
|
3f87f571f4 | ||
|
|
1c69a6f1b7 | ||
|
|
82419cbb6e | ||
|
|
db65630c8d | ||
|
|
b8e54b947f | ||
|
|
f23897108d | ||
|
|
1efe5b21f0 | ||
|
|
fc71b4d249 | ||
|
|
dc81d46556 | ||
|
|
56c2080f43 | ||
|
|
4cc50fcaa5 | ||
|
|
2d67562576 | ||
|
|
76f2d7afa7 | ||
|
|
80fa9c4f21 | ||
|
|
8f215a5b4b | ||
|
|
bffd9cb52a | ||
|
|
74b1ff5b10 | ||
|
|
3c0079fea0 | ||
|
|
c0a9723d20 | ||
|
|
a4f0a76200 | ||
|
|
eb57b0130b | ||
|
|
f8c37c7abc | ||
|
|
72373f8812 | ||
|
|
b285e99e7d | ||
|
|
f9a6b88bb6 | ||
|
|
4a65d506f2 | ||
|
|
3bc03c90fd | ||
|
|
c35dfa4ac5 | ||
|
|
1d2a9a9dde | ||
|
|
925220bb13 | ||
|
|
16d088bfe3 | ||
|
|
b8e22ee435 | ||
|
|
60dea4b932 | ||
|
|
8ae1a42e4b | ||
|
|
cfdc7a46e6 | ||
|
|
afb23adcbf | ||
|
|
3b84a474b8 | ||
|
|
e96bb04e88 | ||
|
|
2e3b8507b2 | ||
|
|
e12c69f1a6 | ||
|
|
d049a23469 | ||
|
|
2633f427c8 | ||
|
|
ff920f1d7b | ||
|
|
fd69560025 | ||
|
|
ba51e47e05 | ||
|
|
409f552274 | ||
|
|
69a7c184bd | ||
|
|
3039c84738 | ||
|
|
bfa5cd085d | ||
|
|
7c282b30b1 | ||
|
|
06fa3c541e | ||
|
|
c9e31ac1f7 | ||
|
|
e248486d3d | ||
|
|
b32a52d236 | ||
|
|
a24b4d6d4d | ||
|
|
b831aa0075 | ||
|
|
bf4d4b78cb | ||
|
|
496896e36e | ||
|
|
6b88ec1f8a | ||
|
|
3af5f3a96d | ||
|
|
ddc5564515 | ||
|
|
bc5da7ef06 | ||
|
|
45221c0b03 | ||
|
|
d29cf2ffa7 | ||
|
|
f6c0b89d1f | ||
|
|
ecd9e06665 | ||
|
|
9e5b66d5f4 | ||
|
|
8c35c3cdaa | ||
|
|
828a6240fe | ||
|
|
eaad0eaee0 | ||
|
|
db76d4417c | ||
|
|
7a6c6ec210 | ||
|
|
8e034f183b | ||
|
|
5a01b34cce | ||
|
|
1399a9bffe | ||
|
|
653c6ed85a | ||
|
|
ebbb7b58cb | ||
|
|
7164e4e315 | ||
|
|
23398d07f9 | ||
|
|
ec2bc3efa2 | ||
|
|
86d78763c1 | ||
|
|
fb5ae36d7e | ||
|
|
51f812625b | ||
|
|
479bfee647 | ||
|
|
a3501a56cd | ||
|
|
c353e286b0 | ||
|
|
8ed01e8a87 | ||
|
|
36ed21b9f4 | ||
|
|
cca41bb449 | ||
|
|
8f787ad0e6 | ||
|
|
9c1170f100 | ||
|
|
5432be4a3f | ||
|
|
7cae821db5 | ||
|
|
19ebb24f03 | ||
|
|
d07512566e | ||
|
|
61929666f3 | ||
|
|
792ffbfcd7 | ||
|
|
9685271bb4 | ||
|
|
5b1a6cc95e | ||
|
|
bf34075e6a | ||
|
|
f1859eeef2 | ||
|
|
fa12b37e53 | ||
|
|
520a5dc9f2 | ||
|
|
7af949b5a5 | ||
|
|
300612b09b | ||
|
|
6f00e9825c | ||
|
|
6ca9c5300e | ||
|
|
cdeb31051b | ||
|
|
ba90517ad7 | ||
|
|
7aff949f47 | ||
|
|
0e8c0da3dd | ||
|
|
3132a207e1 | ||
|
|
88dd0e06c5 | ||
|
|
f507a2464f | ||
|
|
14baa6ebf8 | ||
|
|
5d32126565 | ||
|
|
484ff7ab4c | ||
|
|
36f86385a2 | ||
|
|
436faa17af | ||
|
|
d205ae206f | ||
|
|
6baa5900fc | ||
|
|
fadb53f075 | ||
|
|
1a63387408 | ||
|
|
a316120b69 | ||
|
|
0d1e5ef119 | ||
|
|
b49cfca39d | ||
|
|
ab58df4c2c | ||
|
|
db20f10bd2 | ||
|
|
444cc5a193 | ||
|
|
6c253bc9b4 | ||
|
|
2fd28e174e | ||
|
|
a188692c88 | ||
|
|
b263419e08 | ||
|
|
826e06c727 | ||
|
|
dfcdfb105f | ||
|
|
0508bbb16f | ||
|
|
dfbfa85fd3 | ||
|
|
b99ad4bdc3 | ||
|
|
e801170496 | ||
|
|
91e7c9c5ad | ||
|
|
ca5162ed32 | ||
|
|
0bf87d0c87 | ||
|
|
ce91eb5bae | ||
|
|
8d68056bca | ||
|
|
d0de8e444a | ||
|
|
dfef1f21cc | ||
|
|
2440ac4e87 | ||
|
|
e90db78697 | ||
|
|
5ae15d429c | ||
|
|
89d6b46f3e | ||
|
|
e086f64779 | ||
|
|
9ed3b4f11e | ||
|
|
ece3fa12b4 | ||
|
|
9a35224535 | ||
|
|
ef3faa58bc | ||
|
|
b6a8f7eeba | ||
|
|
d1203d9c42 | ||
|
|
a834b6ae38 | ||
|
|
e7982a73ad | ||
|
|
717342c80c | ||
|
|
075f0e62fd | ||
|
|
bcca31fbed | ||
|
|
007891fc11 | ||
|
|
f8e41952d1 | ||
|
|
e4d64f8a79 | ||
|
|
1654f69ec1 | ||
|
|
cb16fb5437 | ||
|
|
36f5fa2c47 | ||
|
|
51ad22e72c | ||
|
|
1a355c0c16 | ||
|
|
fe5ba08963 | ||
|
|
7fc994d4af | ||
|
|
a0a8285e02 | ||
|
|
da2e35f613 | ||
|
|
09bdc25352 | ||
|
|
ad263a9c36 | ||
|
|
c8d8d4e43d | ||
|
|
94249b8a93 | ||
|
|
edd2c51eb6 | ||
|
|
1d24e9399f | ||
|
|
3a0062276d | ||
|
|
1993cf3f6c | ||
|
|
c97aac31c6 | ||
|
|
507921cbe8 | ||
|
|
887db675c8 | ||
|
|
3917618e4e | ||
|
|
3c42d2e6a4 | ||
|
|
db8777b7f7 | ||
|
|
18c2cddee2 | ||
|
|
3ff9d3a1fa | ||
|
|
6503667c78 | ||
|
|
0fa95f84d4 | ||
|
|
cf91a90270 | ||
|
|
690052f989 | ||
|
|
b3e935f7e4 | ||
|
|
17314ebd29 | ||
|
|
adc437cd51 | ||
|
|
0e97b74510 | ||
|
|
9ffb475cac | ||
|
|
faa2b030c5 | ||
|
|
e3b3b10e2a | ||
|
|
b569cf268c | ||
|
|
b154b77556 | ||
|
|
84c0f30a7c | ||
|
|
16463ff76d | ||
|
|
8314e9e24b | ||
|
|
a33c557818 | ||
|
|
6fbdc65ad0 | ||
|
|
9c9b6c4711 | ||
|
|
46278d04c3 | ||
|
|
c1c16508b5 | ||
|
|
ed1b983711 | ||
|
|
ec23e28eda | ||
|
|
d48b49e8e4 | ||
|
|
14308970c6 | ||
|
|
38e86e1012 | ||
|
|
e9a33af831 | ||
|
|
6a63e5dbb2 | ||
|
|
1e1892a3d5 | ||
|
|
8bff9a2973 | ||
|
|
cbe753dd29 | ||
|
|
b047845b43 | ||
|
|
1bebc75381 | ||
|
|
93c46bfc8d | ||
|
|
a3d0f5963e | ||
|
|
006b82bf05 | ||
|
|
c36e37ac6b | ||
|
|
3cf6d7385a | ||
|
|
9045b2fa97 | ||
|
|
be6f3b9c6d | ||
|
|
5a699b7ce9 | ||
|
|
f366a78e87 | ||
|
|
c63c7ead51 | ||
|
|
ecfa5902cd | ||
|
|
444027b496 | ||
|
|
9c5dcb93c7 | ||
|
|
9594221271 | ||
|
|
01823d3b75 | ||
|
|
db07a90139 | ||
|
|
962d0928d3 | ||
|
|
e67d50c8e6 | ||
|
|
f9b2f17852 | ||
|
|
9746a9f5ed | ||
|
|
be0877ecb0 | ||
|
|
d2fcdfae43 | ||
|
|
2c9eb46941 | ||
|
|
d30a85fd48 | ||
|
|
9260bed1b1 | ||
|
|
f6d12985a9 | ||
|
|
10c9b1db7c | ||
|
|
4fb17be8de | ||
|
|
b592b1a088 | ||
|
|
0544a6507e | ||
|
|
1e20ff15ed | ||
|
|
04a0ec0645 | ||
|
|
f355292fe3 | ||
|
|
32e4d813de | ||
|
|
f960f5ea87 | ||
|
|
aa6f83e2fa | ||
|
|
c09e1f1895 | ||
|
|
7c311928dd | ||
|
|
5f1c8bcb6b | ||
|
|
93bc20f014 | ||
|
|
d29d9571c6 | ||
|
|
3d47dfc820 | ||
|
|
d7846c9add | ||
|
|
4d6fe9d641 | ||
|
|
205feba75d | ||
|
|
ca7663b94a | ||
|
|
83e45f054b | ||
|
|
783e893a67 | ||
|
|
0a941866a9 | ||
|
|
04edfe0085 | ||
|
|
6cae634eca | ||
|
|
8c7bf278dc | ||
|
|
f6106650b5 | ||
|
|
166e606034 | ||
|
|
c997e6a3e4 | ||
|
|
2a1b6dc9da | ||
|
|
129c33fa12 | ||
|
|
3245987113 | ||
|
|
593ad62cbb | ||
|
|
a625a76e9e | ||
|
|
c2a305304b | ||
|
|
7389c507fb | ||
|
|
68f0f23016 | ||
|
|
dc809dde30 | ||
|
|
80dfa03b94 | ||
|
|
fca7a5350d | ||
|
|
1b693fb57a | ||
|
|
7723bd3b5f | ||
|
|
723fc142ec | ||
|
|
06d4d946d9 | ||
|
|
428b7d976d | ||
|
|
32f2b4e573 | ||
|
|
b3ab983f02 | ||
|
|
e011724af4 | ||
|
|
f11a6cb38a | ||
|
|
adf6d3c60d | ||
|
|
bb8f35ce09 | ||
|
|
ae9ae31ddc | ||
|
|
67893817b5 | ||
|
|
f8da5b153d | ||
|
|
e2a956a088 | ||
|
|
5c5b001fc7 | ||
|
|
e4beafed97 | ||
|
|
553a504140 | ||
|
|
44dd2ee808 | ||
|
|
b36c851b2a | ||
|
|
0502d70cdf | ||
|
|
86546574bb | ||
|
|
f351712130 | ||
|
|
c7f2ae2234 | ||
|
|
436f689115 | ||
|
|
951c7af724 | ||
|
|
53b46f879f | ||
|
|
cbe82112ab | ||
|
|
7f5562ccfe | ||
|
|
76ec946616 | ||
|
|
68bb2edb39 | ||
|
|
9c85618aff | ||
|
|
aebeff8b4c | ||
|
|
8d63125b13 | ||
|
|
2ca97ef586 | ||
|
|
a1a00f0bfb | ||
|
|
6870b135b7 | ||
|
|
a0f1379feb | ||
|
|
9b17322478 | ||
|
|
f562bad286 | ||
|
|
6994cc3d15 | ||
|
|
9b572f9541 | ||
|
|
71f893cb44 | ||
|
|
6b76ea0a6f | ||
|
|
7616d33883 | ||
|
|
3c757bb2b2 | ||
|
|
a502df80ba | ||
|
|
921268ec58 | ||
|
|
7d42d4f973 | ||
|
|
e4e130c5d6 | ||
|
|
bcf7a63118 | ||
|
|
66aac12db7 | ||
|
|
59cd1f8930 | ||
|
|
150e704d20 | ||
|
|
b2d47f0fb8 | ||
|
|
bd3d33296d | ||
|
|
f4c82ced97 | ||
|
|
76188df0d3 | ||
|
|
9a58e4d339 | ||
|
|
f396a5b784 | ||
|
|
e572b853e2 | ||
|
|
726c2f195a | ||
|
|
4599e51b1e | ||
|
|
d93169cc5a | ||
|
|
bdd3c11f1a | ||
|
|
0cec90c7ca | ||
|
|
43def798e1 | ||
|
|
02b0c022ca | ||
|
|
c82d0d1b88 | ||
|
|
e24d7865ce | ||
|
|
a79f95b305 | ||
|
|
49b40b1c3e | ||
|
|
11ee74e224 | ||
|
|
f335246673 | ||
|
|
ccb734aec6 | ||
|
|
568b9e9459 | ||
|
|
a43ea761f5 | ||
|
|
577c77cc30 | ||
|
|
d2f60baef9 | ||
|
|
64acc08cd7 | ||
|
|
a1f0b81dff | ||
|
|
48bb58dc89 | ||
|
|
765cc213d2 | ||
|
|
37f5c0dd76 | ||
|
|
b25d1eaf86 | ||
|
|
248676aa31 | ||
|
|
059c80c05d | ||
|
|
cfd42818b7 | ||
|
|
5e66e0acc4 | ||
|
|
c9fe5ffbcf | ||
|
|
1b630a092f | ||
|
|
09e60284cb | ||
|
|
76b34c62db | ||
|
|
9d7212bc1d | ||
|
|
1b69c9231d | ||
|
|
bcd88f6356 | ||
|
|
2a47f67214 | ||
|
|
5e8dc1b26c | ||
|
|
c591f1f37d | ||
|
|
4db43ccd4e | ||
|
|
ea5d3c2d78 | ||
|
|
700b1f15cd | ||
|
|
485ba174e3 | ||
|
|
32f6f8b941 | ||
|
|
54ad30a7ed | ||
|
|
170d75482e | ||
|
|
a8db2b30f2 | ||
|
|
e3b1b08424 | ||
|
|
8006a1a5e7 | ||
|
|
1ae65dd4a1 | ||
|
|
bff515b63f | ||
|
|
65c3ea826f | ||
|
|
602d5140f9 | ||
|
|
44f0700332 | ||
|
|
c90db020b0 | ||
|
|
ef4094885e | ||
|
|
b52d9d9194 | ||
|
|
d3f2836f48 | ||
|
|
27722f77f9 | ||
|
|
3a0db14c40 | ||
|
|
e0dc1b48ec | ||
|
|
009327c2c4 | ||
|
|
b16d60b52b | ||
|
|
c550fe9283 | ||
|
|
dce4fc70ac | ||
|
|
b3f3ecbf28 | ||
|
|
e8c0ddfc7f | ||
|
|
a002b376af | ||
|
|
2165383da4 | ||
|
|
5fbf6b297f | ||
|
|
9d5ad83ff8 | ||
|
|
07f17dece2 | ||
|
|
f2f467ecb8 | ||
|
|
2ea9e22b52 | ||
|
|
4ee5572d2f | ||
|
|
df7e112d22 | ||
|
|
13ac3ed5b2 | ||
|
|
b7c223bc0d | ||
|
|
0f08121596 | ||
|
|
b15545402a | ||
|
|
b310c97044 | ||
|
|
307c6b05ae | ||
|
|
77a6d21924 | ||
|
|
d22a343378 | ||
|
|
790a5b580d | ||
|
|
6e8f8bbe41 | ||
|
|
cc9d01a9ab | ||
|
|
526520c399 | ||
|
|
acbc31bc35 | ||
|
|
e8e151a926 | ||
|
|
835a537c55 | ||
|
|
23ea9fad49 | ||
|
|
491280935a | ||
|
|
900eda9a8e | ||
|
|
38d0057833 | ||
|
|
3867448aad | ||
|
|
807a76d443 | ||
|
|
3e26a0a3cc | ||
|
|
68729979e3 | ||
|
|
a09ec269b8 | ||
|
|
3f18c927f1 | ||
|
|
9add650b75 |
13
.babelrc
13
.babelrc
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"plugins": [
|
||||
"transform-class-properties",
|
||||
"transform-react-constant-elements",
|
||||
"transform-react-remove-prop-types",
|
||||
[
|
||||
"transform-react-jsx",
|
||||
{
|
||||
"pragma": "h"
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
2
.clang-format
Normal file
2
.clang-format
Normal file
@@ -0,0 +1,2 @@
|
||||
BasedOnStyle: Chromium
|
||||
ColumnLimit: 100
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"projects": {
|
||||
"default": "squoosh-beta"
|
||||
}
|
||||
}
|
||||
36
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
36
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Something is not working as expected
|
||||
labels:
|
||||
|
||||
---
|
||||
|
||||
**Before you start**
|
||||
Please take a look at the [FAQ](https://github.com/GoogleChromeLabs/squoosh/wiki/FAQ) as well as the already opened issues! If nothing fits your problem, go ahead and fill out the following template:
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Version:**
|
||||
- OS w/ version: [e.g. iOS 12]
|
||||
- Browser w/ version [e.g. Chrome 70]
|
||||
- Node version: [e.g. 10.11.0]
|
||||
- npm version: [e.g. 6.4.1]
|
||||
|
||||
**Is your issue related to the quality of image compression?**
|
||||
Please attach original and output images (you can drag & drop to attach).
|
||||
- Original image
|
||||
- Output image from Squoosh
|
||||
|
||||
**Additional context, screenshots, screencasts**
|
||||
Add any other context about the problem here.
|
||||
18
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
18
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
labels:
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Does other service/app have this feature?**
|
||||
Add any service you know/use that has this feature (We want to know for research)
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,3 +3,4 @@ node_modules
|
||||
/*.log
|
||||
*.scss.d.ts
|
||||
*.css.d.ts
|
||||
*.o
|
||||
|
||||
7
.travis.yml
Normal file
7
.travis.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
language: node_js
|
||||
cache: npm
|
||||
script: npm run build
|
||||
after_success: npm run sizereport
|
||||
os:
|
||||
- linux
|
||||
- windows
|
||||
33
README.md
33
README.md
@@ -1,5 +1,32 @@
|
||||
# Squoosh!
|
||||
# [Squoosh]!
|
||||
|
||||
Squoosh will be an image compression web app that allows you to dive into the
|
||||
advanced options provided by various image compressors.
|
||||
[Squoosh] is an image compression web app that allows you to dive into the advanced options provided
|
||||
by various image compressors.
|
||||
|
||||
# Privacy
|
||||
|
||||
Google Analytics is used to record the following:
|
||||
|
||||
* [Basic visit data](https://support.google.com/analytics/answer/6004245?ref_topic=2919631).
|
||||
* Before and after image size once an image is downloaded. These values are rounded to the nearest
|
||||
kilobyte.
|
||||
* If install is available, when Squoosh is installed, and what method was used to install Squoosh.
|
||||
|
||||
Image compression is handled locally; no additional data is sent to the server.
|
||||
|
||||
# Building locally
|
||||
|
||||
Clone the repo, and:
|
||||
|
||||
```sh
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
|
||||
You can run the development server with:
|
||||
|
||||
```sh
|
||||
npm start
|
||||
```
|
||||
|
||||
[Squoosh]: https://squoosh.app
|
||||
|
||||
18
_headers.ejs
Normal file
18
_headers.ejs
Normal file
@@ -0,0 +1,18 @@
|
||||
# Long-term cache by default.
|
||||
/*
|
||||
Cache-Control: max-age=31536000
|
||||
|
||||
# And here are the exceptions:
|
||||
/
|
||||
Cache-Control: no-cache
|
||||
|
||||
/serviceworker.js
|
||||
Cache-Control: no-cache
|
||||
|
||||
/manifest.json
|
||||
Cache-Control: must-revalidate, max-age=3600
|
||||
|
||||
# URLs in /assets do not include a hash and are mutable.
|
||||
# But it isn't a big deal if the user gets an old version.
|
||||
/assets/*
|
||||
Cache-Control: must-revalidate, max-age=3600
|
||||
2
_redirects.ejs
Normal file
2
_redirects.ejs
Normal file
@@ -0,0 +1,2 @@
|
||||
/index.html / 301
|
||||
/* /index.html 301
|
||||
@@ -11,6 +11,6 @@ $ npm install
|
||||
$ npm run build
|
||||
```
|
||||
|
||||
This will build two files: `<codec name>_<enc or dec>.js` and `<codec name>_<enc or dec>.wasm`. It will most likely be necessary to set [`Module["locateFile"]`](https://kripken.github.io/emscripten-site/docs/api_reference/module.html#affecting-execution) to sucessfully load the `.wasm` file. When the `.js` file is loaded, a global `<codec name>_<enc or dec>` is created with the same API as an [Emscripten `Module`](https://kripken.github.io/emscripten-site/docs/api_reference/module.html).
|
||||
This will build two files: `<codec name>_<enc or dec>.js` and `<codec name>_<enc or dec>.wasm`. It will most likely be necessary to set [`Module["locateFile"]`](https://kripken.github.io/emscripten-site/docs/api_reference/module.html#affecting-execution) to successfully load the `.wasm` file. When the `.js` file is loaded, a global `<codec name>_<enc or dec>` is created with the same API as an [Emscripten `Module`](https://kripken.github.io/emscripten-site/docs/api_reference/module.html).
|
||||
|
||||
Each codec will document its API in its README.
|
||||
|
||||
BIN
codecs/example_palette.png
Normal file
BIN
codecs/example_palette.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 239 KiB |
5
codecs/hqx/.gitignore
vendored
Normal file
5
codecs/hqx/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
**/*.rs.bk
|
||||
target
|
||||
Cargo.lock
|
||||
bin/
|
||||
pkg/README.md
|
||||
37
codecs/hqx/Cargo.toml
Normal file
37
codecs/hqx/Cargo.toml
Normal file
@@ -0,0 +1,37 @@
|
||||
[package]
|
||||
name = "squooshhqx"
|
||||
version = "0.1.0"
|
||||
authors = ["Surma <surma@surma.link>"]
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[features]
|
||||
default = ["console_error_panic_hook", "wee_alloc"]
|
||||
|
||||
[dependencies]
|
||||
cfg-if = "0.1.2"
|
||||
wasm-bindgen = "0.2.38"
|
||||
# lazy_static = "1.0.0"
|
||||
hqx = {git = "https://github.com/CryZe/wasmboy-rs", tag="v0.1.2"}
|
||||
|
||||
# The `console_error_panic_hook` crate provides better debugging of panics by
|
||||
# logging them with `console.error`. This is great for development, but requires
|
||||
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
|
||||
# code size when deploying.
|
||||
console_error_panic_hook = { version = "0.1.1", optional = true }
|
||||
|
||||
# `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size
|
||||
# compared to the default allocator's ~10K. It is slower than the default
|
||||
# allocator, however.
|
||||
#
|
||||
# Unfortunately, `wee_alloc` requires nightly Rust when targeting wasm for now.
|
||||
wee_alloc = { version = "0.4.2", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen-test = "0.2"
|
||||
|
||||
[profile.release]
|
||||
# Tell `rustc` to optimize for small code size.
|
||||
opt-level = "s"
|
||||
lto = true
|
||||
12
codecs/hqx/Dockerfile
Normal file
12
codecs/hqx/Dockerfile
Normal file
@@ -0,0 +1,12 @@
|
||||
FROM rust
|
||||
RUN rustup target add wasm32-unknown-unknown
|
||||
RUN curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||
|
||||
RUN mkdir /opt/binaryen && \
|
||||
curl -L https://github.com/WebAssembly/binaryen/releases/download/1.38.32/binaryen-1.38.32-x86-linux.tar.gz | tar -xzf - -C /opt/binaryen --strip 1
|
||||
|
||||
RUN mkdir /opt/wabt && \
|
||||
curl -L https://github.com/WebAssembly/wabt/releases/download/1.0.11/wabt-1.0.11-linux.tar.gz | tar -xzf - -C /opt/wabt --strip 1
|
||||
|
||||
ENV PATH="/opt/binaryen:/opt/wabt:${PATH}"
|
||||
WORKDIR /src
|
||||
25
codecs/hqx/build.sh
Executable file
25
codecs/hqx/build.sh
Executable file
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
echo "============================================="
|
||||
echo "Compiling wasm"
|
||||
echo "============================================="
|
||||
(
|
||||
wasm-pack build
|
||||
wasm-strip pkg/squooshhqx_bg.wasm
|
||||
echo "Optimising Wasm so it doesn't break Chrome (this takes like 10-15mins. get a cup of tea)"
|
||||
echo "Once https://crbug.com/974804 is fixed, we can remove this step"
|
||||
wasm-opt -Os --no-validation -o pkg/squooshhqx_bg.wasm pkg/squooshhqx_bg.wasm
|
||||
rm pkg/.gitignore
|
||||
)
|
||||
echo "============================================="
|
||||
echo "Compiling wasm done"
|
||||
echo "============================================="
|
||||
|
||||
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
||||
echo "Did you update your docker image?"
|
||||
echo "Run \`docker pull ubuntu\`"
|
||||
echo "Run \`docker pull rust\`"
|
||||
echo "Run \`docker build -t squoosh-hqx .\`"
|
||||
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
||||
4
codecs/hqx/package-lock.json
generated
Normal file
4
codecs/hqx/package-lock.json
generated
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "hqx",
|
||||
"lockfileVersion": 1
|
||||
}
|
||||
7
codecs/hqx/package.json
Normal file
7
codecs/hqx/package.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "hqx",
|
||||
"scripts": {
|
||||
"build:image": "docker build -t squoosh-hqx .",
|
||||
"build": "docker run --rm -v $(pwd):/src squoosh-hqx ./build.sh"
|
||||
}
|
||||
}
|
||||
15
codecs/hqx/pkg/package.json
Normal file
15
codecs/hqx/pkg/package.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "squooshhqx",
|
||||
"collaborators": [
|
||||
"Surma <surma@surma.link>"
|
||||
],
|
||||
"version": "0.1.0",
|
||||
"files": [
|
||||
"squooshhqx_bg.wasm",
|
||||
"squooshhqx.js",
|
||||
"squooshhqx.d.ts"
|
||||
],
|
||||
"module": "squooshhqx.js",
|
||||
"types": "squooshhqx.d.ts",
|
||||
"sideEffects": "false"
|
||||
}
|
||||
9
codecs/hqx/pkg/squooshhqx.d.ts
vendored
Normal file
9
codecs/hqx/pkg/squooshhqx.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
/* tslint:disable */
|
||||
/**
|
||||
* @param {Uint32Array} input_image
|
||||
* @param {number} input_width
|
||||
* @param {number} input_height
|
||||
* @param {number} factor
|
||||
* @returns {Uint32Array}
|
||||
*/
|
||||
export function resize(input_image: Uint32Array, input_width: number, input_height: number, factor: number): Uint32Array;
|
||||
46
codecs/hqx/pkg/squooshhqx.js
Normal file
46
codecs/hqx/pkg/squooshhqx.js
Normal file
@@ -0,0 +1,46 @@
|
||||
import * as wasm from './squooshhqx_bg.wasm';
|
||||
|
||||
let cachegetUint32Memory = null;
|
||||
function getUint32Memory() {
|
||||
if (cachegetUint32Memory === null || cachegetUint32Memory.buffer !== wasm.memory.buffer) {
|
||||
cachegetUint32Memory = new Uint32Array(wasm.memory.buffer);
|
||||
}
|
||||
return cachegetUint32Memory;
|
||||
}
|
||||
|
||||
let WASM_VECTOR_LEN = 0;
|
||||
|
||||
function passArray32ToWasm(arg) {
|
||||
const ptr = wasm.__wbindgen_malloc(arg.length * 4);
|
||||
getUint32Memory().set(arg, ptr / 4);
|
||||
WASM_VECTOR_LEN = arg.length;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
let cachegetInt32Memory = null;
|
||||
function getInt32Memory() {
|
||||
if (cachegetInt32Memory === null || cachegetInt32Memory.buffer !== wasm.memory.buffer) {
|
||||
cachegetInt32Memory = new Int32Array(wasm.memory.buffer);
|
||||
}
|
||||
return cachegetInt32Memory;
|
||||
}
|
||||
|
||||
function getArrayU32FromWasm(ptr, len) {
|
||||
return getUint32Memory().subarray(ptr / 4, ptr / 4 + len);
|
||||
}
|
||||
/**
|
||||
* @param {Uint32Array} input_image
|
||||
* @param {number} input_width
|
||||
* @param {number} input_height
|
||||
* @param {number} factor
|
||||
* @returns {Uint32Array}
|
||||
*/
|
||||
export function resize(input_image, input_width, input_height, factor) {
|
||||
const retptr = 8;
|
||||
const ret = wasm.resize(retptr, passArray32ToWasm(input_image), WASM_VECTOR_LEN, input_width, input_height, factor);
|
||||
const memi32 = getInt32Memory();
|
||||
const v0 = getArrayU32FromWasm(memi32[retptr / 4 + 0], memi32[retptr / 4 + 1]).slice();
|
||||
wasm.__wbindgen_free(memi32[retptr / 4 + 0], memi32[retptr / 4 + 1] * 4);
|
||||
return v0;
|
||||
}
|
||||
|
||||
5
codecs/hqx/pkg/squooshhqx_bg.d.ts
vendored
Normal file
5
codecs/hqx/pkg/squooshhqx_bg.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/* tslint:disable */
|
||||
export const memory: WebAssembly.Memory;
|
||||
export function __wbindgen_malloc(a: number): number;
|
||||
export function __wbindgen_free(a: number, b: number): void;
|
||||
export function resize(a: number, b: number, c: number, d: number, e: number, f: number): void;
|
||||
BIN
codecs/hqx/pkg/squooshhqx_bg.wasm
Normal file
BIN
codecs/hqx/pkg/squooshhqx_bg.wasm
Normal file
Binary file not shown.
55
codecs/hqx/src/lib.rs
Normal file
55
codecs/hqx/src/lib.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
extern crate cfg_if;
|
||||
extern crate hqx;
|
||||
extern crate wasm_bindgen;
|
||||
|
||||
mod utils;
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
cfg_if! {
|
||||
// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
|
||||
// allocator.
|
||||
if #[cfg(feature = "wee_alloc")] {
|
||||
extern crate wee_alloc;
|
||||
#[global_allocator]
|
||||
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[no_mangle]
|
||||
pub fn resize(
|
||||
input_image: Vec<u32>,
|
||||
input_width: usize,
|
||||
input_height: usize,
|
||||
factor: usize,
|
||||
) -> Vec<u32> {
|
||||
let num_output_pixels = input_width * input_height * factor * factor;
|
||||
let mut output_image = Vec::<u32>::with_capacity(num_output_pixels * 4);
|
||||
output_image.resize(num_output_pixels, 0);
|
||||
|
||||
match factor {
|
||||
2 => hqx::hq2x(
|
||||
input_image.as_slice(),
|
||||
output_image.as_mut_slice(),
|
||||
input_width,
|
||||
input_height,
|
||||
),
|
||||
3 => hqx::hq3x(
|
||||
input_image.as_slice(),
|
||||
output_image.as_mut_slice(),
|
||||
input_width,
|
||||
input_height,
|
||||
),
|
||||
4 => hqx::hq4x(
|
||||
input_image.as_slice(),
|
||||
output_image.as_mut_slice(),
|
||||
input_width,
|
||||
input_height,
|
||||
),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
return output_image;
|
||||
}
|
||||
17
codecs/hqx/src/utils.rs
Normal file
17
codecs/hqx/src/utils.rs
Normal file
@@ -0,0 +1,17 @@
|
||||
use cfg_if::cfg_if;
|
||||
|
||||
cfg_if! {
|
||||
// When the `console_error_panic_hook` feature is enabled, we can call the
|
||||
// `set_panic_hook` function at least once during initialization, and then
|
||||
// we will get better error messages if our code ever panics.
|
||||
//
|
||||
// For more details see
|
||||
// https://github.com/rustwasm/console_error_panic_hook#readme
|
||||
if #[cfg(feature = "console_error_panic_hook")] {
|
||||
extern crate console_error_panic_hook;
|
||||
pub use self::console_error_panic_hook::set_once as set_panic_hook;
|
||||
} else {
|
||||
#[inline]
|
||||
pub fn set_panic_hook() {}
|
||||
}
|
||||
}
|
||||
30
codecs/imagequant/README.md
Normal file
30
codecs/imagequant/README.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# ImageQuant
|
||||
|
||||
- Source: <https://github.com/ImageOptim/libimagequant>
|
||||
- Version: v2.12.1
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Docker
|
||||
|
||||
## Example
|
||||
|
||||
See `example.html`
|
||||
|
||||
## API
|
||||
|
||||
### `int version()`
|
||||
|
||||
Returns the version of libimagequant as a number. va.b.c is encoded as 0x0a0b0c
|
||||
|
||||
### `RawImage quantize(std::string buffer, int image_width, int image_height, int numColors, float dithering)`
|
||||
|
||||
Quantizes the given images, using at most `numColors`, a value between 2 and 256. `dithering` is a value between 0 and 1 controlling the amount of dithering. `RawImage` is a class with 3 fields: `buffer`, `width`, and `height`.
|
||||
|
||||
### `RawImage zx_quantize(std::string buffer, int image_width, int image_height, float dithering)`
|
||||
|
||||
???
|
||||
|
||||
### `void free_result()`
|
||||
|
||||
Frees the result created by `quantize()`.
|
||||
43
codecs/imagequant/build.sh
Executable file
43
codecs/imagequant/build.sh
Executable file
@@ -0,0 +1,43 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
export EM_CACHE="${PWD}/node_modules/.em_cache"
|
||||
export OPTIMIZE="-Os -flto --llvm-lto 1"
|
||||
export LDFLAGS="${OPTIMIZE}"
|
||||
export CFLAGS="${OPTIMIZE}"
|
||||
export CPPFLAGS="${OPTIMIZE}"
|
||||
|
||||
echo "============================================="
|
||||
echo "Compiling libimagequant"
|
||||
echo "============================================="
|
||||
(
|
||||
cd node_modules/libimagequant
|
||||
emconfigure ./configure --disable-sse
|
||||
emmake make static -j`nproc`
|
||||
)
|
||||
echo "============================================="
|
||||
echo "Compiling wasm module"
|
||||
echo "============================================="
|
||||
(
|
||||
emcc \
|
||||
--bind \
|
||||
${OPTIMIZE} \
|
||||
--closure 1 \
|
||||
-s ALLOW_MEMORY_GROWTH=1 \
|
||||
-s MODULARIZE=1 \
|
||||
-s 'EXPORT_NAME="imagequant"' \
|
||||
-I node_modules/libimagequant \
|
||||
-o ./imagequant.js \
|
||||
--std=c++11 \
|
||||
imagequant.cpp \
|
||||
node_modules/libimagequant/libimagequant.a
|
||||
)
|
||||
echo "============================================="
|
||||
echo "Compiling wasm module done"
|
||||
echo "============================================="
|
||||
|
||||
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
||||
echo "Did you update your docker image?"
|
||||
echo "Run \`docker pull trzeci/emscripten-upstream\`"
|
||||
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
||||
41
codecs/imagequant/example.html
Normal file
41
codecs/imagequant/example.html
Normal file
@@ -0,0 +1,41 @@
|
||||
<!doctype html>
|
||||
<style>
|
||||
canvas {
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
</style>
|
||||
<script src='imagequant.js'></script>
|
||||
<script>
|
||||
const Module = imagequant();
|
||||
|
||||
async function loadImage(src) {
|
||||
// Load image
|
||||
const img = document.createElement('img');
|
||||
img.src = src;
|
||||
await new Promise(resolve => img.onload = resolve);
|
||||
// Make canvas same size as image
|
||||
const canvas = document.createElement('canvas');
|
||||
[canvas.width, canvas.height] = [img.width, img.height];
|
||||
// Draw image onto canvas
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(img, 0, 0);
|
||||
return ctx.getImageData(0, 0, img.width, img.height);
|
||||
}
|
||||
|
||||
Module.onRuntimeInitialized = async _ => {
|
||||
console.log('Version:', Module.version().toString(16));
|
||||
const image = await loadImage('../example.png');
|
||||
// const rawImage = Module.quantize(image.data, image.width, image.height, 256, 1.0);
|
||||
const rawImage = Module.zx_quantize(image.data, image.width, image.height, 1.0);
|
||||
console.log('done');
|
||||
Module.free_result();
|
||||
|
||||
const imageData = new ImageData(new Uint8ClampedArray(rawImage.buffer), rawImage.width, rawImage.height);
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = image.width;
|
||||
canvas.height = image.height;
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.putImageData(imageData, 0, 0);
|
||||
document.body.appendChild(canvas);
|
||||
};
|
||||
</script>
|
||||
245
codecs/imagequant/imagequant.cpp
Normal file
245
codecs/imagequant/imagequant.cpp
Normal file
@@ -0,0 +1,245 @@
|
||||
#include <emscripten/bind.h>
|
||||
#include <emscripten/val.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "libimagequant.h"
|
||||
|
||||
using namespace emscripten;
|
||||
|
||||
int version() {
|
||||
return (((LIQ_VERSION / 10000) % 100) << 16) | (((LIQ_VERSION / 100) % 100) << 8) |
|
||||
(((LIQ_VERSION / 1) % 100) << 0);
|
||||
}
|
||||
|
||||
class RawImage {
|
||||
public:
|
||||
val buffer;
|
||||
int width;
|
||||
int height;
|
||||
|
||||
RawImage(val b, int w, int h) : buffer(b), width(w), height(h) {}
|
||||
};
|
||||
|
||||
liq_attr* attr;
|
||||
liq_image* image;
|
||||
liq_result* res;
|
||||
uint8_t* result;
|
||||
RawImage quantize(std::string rawimage,
|
||||
int image_width,
|
||||
int image_height,
|
||||
int num_colors,
|
||||
float dithering) {
|
||||
const uint8_t* image_buffer = (uint8_t*)rawimage.c_str();
|
||||
int size = image_width * image_height;
|
||||
attr = liq_attr_create();
|
||||
image = liq_image_create_rgba(attr, image_buffer, image_width, image_height, 0);
|
||||
liq_set_max_colors(attr, num_colors);
|
||||
liq_image_quantize(image, attr, &res);
|
||||
liq_set_dithering_level(res, dithering);
|
||||
uint8_t* image8bit = (uint8_t*)malloc(size);
|
||||
result = (uint8_t*)malloc(size * 4);
|
||||
liq_write_remapped_image(res, image, image8bit, size);
|
||||
const liq_palette* pal = liq_get_palette(res);
|
||||
// Turn palletted image back into an RGBA image
|
||||
for (int i = 0; i < size; i++) {
|
||||
result[i * 4 + 0] = pal->entries[image8bit[i]].r;
|
||||
result[i * 4 + 1] = pal->entries[image8bit[i]].g;
|
||||
result[i * 4 + 2] = pal->entries[image8bit[i]].b;
|
||||
result[i * 4 + 3] = pal->entries[image8bit[i]].a;
|
||||
}
|
||||
free(image8bit);
|
||||
liq_result_destroy(res);
|
||||
liq_image_destroy(image);
|
||||
liq_attr_destroy(attr);
|
||||
return {val(typed_memory_view(image_width * image_height * 4, result)), image_width,
|
||||
image_height};
|
||||
}
|
||||
|
||||
const liq_color zx_colors[] = {
|
||||
{.r = 0, .g = 0, .b = 0, .a = 255}, // regular black
|
||||
{.r = 0, .g = 0, .b = 215, .a = 255}, // regular blue
|
||||
{.r = 215, .g = 0, .b = 0, .a = 255}, // regular red
|
||||
{.r = 215, .g = 0, .b = 215, .a = 255}, // regular magenta
|
||||
{.r = 0, .g = 215, .b = 0, .a = 255}, // regular green
|
||||
{.r = 0, .g = 215, .b = 215, .a = 255}, // regular cyan
|
||||
{.r = 215, .g = 215, .b = 0, .a = 255}, // regular yellow
|
||||
{.r = 215, .g = 215, .b = 215, .a = 255}, // regular white
|
||||
{.r = 0, .g = 0, .b = 255, .a = 255}, // bright blue
|
||||
{.r = 255, .g = 0, .b = 0, .a = 255}, // bright red
|
||||
{.r = 255, .g = 0, .b = 255, .a = 255}, // bright magenta
|
||||
{.r = 0, .g = 255, .b = 0, .a = 255}, // bright green
|
||||
{.r = 0, .g = 255, .b = 255, .a = 255}, // bright cyan
|
||||
{.r = 255, .g = 255, .b = 0, .a = 255}, // bright yellow
|
||||
{.r = 255, .g = 255, .b = 255, .a = 255} // bright white
|
||||
};
|
||||
|
||||
uint8_t block[8 * 8 * 4];
|
||||
|
||||
/**
|
||||
* The ZX has one bit per pixel, but can assign two colours to an 8x8 block. The
|
||||
* two colours must both be 'regular' or 'bright'. Black exists as both regular
|
||||
* and bright.
|
||||
*/
|
||||
RawImage zx_quantize(std::string rawimage, int image_width, int image_height, float dithering) {
|
||||
const uint8_t* image_buffer = (uint8_t*)rawimage.c_str();
|
||||
int size = image_width * image_height;
|
||||
int bytes_per_pixel = 4;
|
||||
result = (uint8_t*)malloc(size * bytes_per_pixel);
|
||||
uint8_t* image8bit = (uint8_t*)malloc(8 * 8);
|
||||
|
||||
// For each 8x8 grid
|
||||
for (int block_start_y = 0; block_start_y < image_height; block_start_y += 8) {
|
||||
for (int block_start_x = 0; block_start_x < image_width; block_start_x += 8) {
|
||||
int color_popularity[15] = {0};
|
||||
int block_index = 0;
|
||||
int block_width = 8;
|
||||
int block_height = 8;
|
||||
|
||||
// If the block hangs off the right/bottom of the image dimensions, make
|
||||
// it smaller to fit.
|
||||
if (block_start_y + block_height > image_height) {
|
||||
block_height = image_height - block_start_y;
|
||||
}
|
||||
|
||||
if (block_start_x + block_width > image_width) {
|
||||
block_width = image_width - block_start_x;
|
||||
}
|
||||
|
||||
// For each pixel in that block:
|
||||
for (int y = block_start_y; y < block_start_y + block_height; y++) {
|
||||
for (int x = block_start_x; x < block_start_x + block_width; x++) {
|
||||
int pixel_start = (y * image_width * bytes_per_pixel) + (x * bytes_per_pixel);
|
||||
int smallest_distance = INT_MAX;
|
||||
int winning_index = -1;
|
||||
|
||||
// Copy pixel data for quantizing later
|
||||
block[block_index++] = image_buffer[pixel_start];
|
||||
block[block_index++] = image_buffer[pixel_start + 1];
|
||||
block[block_index++] = image_buffer[pixel_start + 2];
|
||||
block[block_index++] = image_buffer[pixel_start + 3];
|
||||
|
||||
// Which zx color is this pixel closest to?
|
||||
for (int color_index = 0; color_index < 15; color_index++) {
|
||||
liq_color color = zx_colors[color_index];
|
||||
|
||||
// Using Euclidean distance. LibQuant has better methods, but it
|
||||
// requires conversion to LAB, so I don't think it's worth it.
|
||||
int distance = pow(color.r - image_buffer[pixel_start + 0], 2) +
|
||||
pow(color.g - image_buffer[pixel_start + 1], 2) +
|
||||
pow(color.b - image_buffer[pixel_start + 2], 2);
|
||||
|
||||
if (distance < smallest_distance) {
|
||||
winning_index = color_index;
|
||||
smallest_distance = distance;
|
||||
}
|
||||
}
|
||||
color_popularity[winning_index]++;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the three most popular colours for the block.
|
||||
int first_color_index = 0;
|
||||
int second_color_index = 0;
|
||||
int third_color_index = 0;
|
||||
int highest_popularity = -1;
|
||||
int second_highest_popularity = -1;
|
||||
int third_highest_popularity = -1;
|
||||
|
||||
for (int color_index = 0; color_index < 15; color_index++) {
|
||||
if (color_popularity[color_index] > highest_popularity) {
|
||||
// Store this as the most popular pixel, and demote the current
|
||||
// values:
|
||||
third_color_index = second_color_index;
|
||||
third_highest_popularity = second_highest_popularity;
|
||||
second_color_index = first_color_index;
|
||||
second_highest_popularity = highest_popularity;
|
||||
first_color_index = color_index;
|
||||
highest_popularity = color_popularity[color_index];
|
||||
} else if (color_popularity[color_index] > second_highest_popularity) {
|
||||
third_color_index = second_color_index;
|
||||
third_highest_popularity = second_highest_popularity;
|
||||
second_color_index = color_index;
|
||||
second_highest_popularity = color_popularity[color_index];
|
||||
} else if (color_popularity[color_index] > third_highest_popularity) {
|
||||
third_color_index = color_index;
|
||||
third_highest_popularity = color_popularity[color_index];
|
||||
}
|
||||
}
|
||||
|
||||
// ZX images can't mix bright and regular colours, except black which
|
||||
// appears in both. Resolve any conflict:
|
||||
while (1) {
|
||||
// If either colour is black, there's no conflict to resolve.
|
||||
if (first_color_index != 0 && second_color_index != 0) {
|
||||
if (first_color_index >= 8 && second_color_index < 8) {
|
||||
// Make the second color bright
|
||||
second_color_index = second_color_index + 7;
|
||||
} else if (first_color_index < 8 && second_color_index >= 8) {
|
||||
// Make the second color regular
|
||||
second_color_index = second_color_index - 7;
|
||||
}
|
||||
}
|
||||
|
||||
// If, during conflict resolving, we now have two of the same colour
|
||||
// (because we initially selected the bright & regular version of the
|
||||
// same colour), retry again with the third most popular colour.
|
||||
if (first_color_index == second_color_index) {
|
||||
second_color_index = third_color_index;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
// Quantize
|
||||
attr = liq_attr_create();
|
||||
image = liq_image_create_rgba(attr, block, block_width, block_height, 0);
|
||||
liq_set_max_colors(attr, 2);
|
||||
liq_image_add_fixed_color(image, zx_colors[first_color_index]);
|
||||
liq_image_add_fixed_color(image, zx_colors[second_color_index]);
|
||||
liq_image_quantize(image, attr, &res);
|
||||
liq_set_dithering_level(res, dithering);
|
||||
liq_write_remapped_image(res, image, image8bit, size);
|
||||
const liq_palette* pal = liq_get_palette(res);
|
||||
|
||||
// Turn palletted image back into an RGBA image, and write it into the
|
||||
// full size result image.
|
||||
for (int y = 0; y < block_height; y++) {
|
||||
for (int x = 0; x < block_width; x++) {
|
||||
int image8BitPos = y * block_width + x;
|
||||
int resultStartPos = ((block_start_y + y) * bytes_per_pixel * image_width) +
|
||||
((block_start_x + x) * bytes_per_pixel);
|
||||
result[resultStartPos + 0] = pal->entries[image8bit[image8BitPos]].r;
|
||||
result[resultStartPos + 1] = pal->entries[image8bit[image8BitPos]].g;
|
||||
result[resultStartPos + 2] = pal->entries[image8bit[image8BitPos]].b;
|
||||
result[resultStartPos + 3] = pal->entries[image8bit[image8BitPos]].a;
|
||||
}
|
||||
}
|
||||
|
||||
liq_result_destroy(res);
|
||||
liq_image_destroy(image);
|
||||
liq_attr_destroy(attr);
|
||||
}
|
||||
}
|
||||
|
||||
free(image8bit);
|
||||
return {val(typed_memory_view(image_width * image_height * 4, result)), image_width,
|
||||
image_height};
|
||||
}
|
||||
|
||||
void free_result() {
|
||||
free(result);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_BINDINGS(my_module) {
|
||||
class_<RawImage>("RawImage")
|
||||
.property("buffer", &RawImage::buffer)
|
||||
.property("width", &RawImage::width)
|
||||
.property("height", &RawImage::height);
|
||||
|
||||
function("quantize", &quantize);
|
||||
function("zx_quantize", &zx_quantize);
|
||||
function("version", &version);
|
||||
function("free_result", &free_result);
|
||||
}
|
||||
15
codecs/imagequant/imagequant.d.ts
vendored
Normal file
15
codecs/imagequant/imagequant.d.ts
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
interface RawImage {
|
||||
buffer: Uint8Array;
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
interface QuantizerModule extends EmscriptenWasm.Module {
|
||||
quantize(data: BufferSource, width: number, height: number, numColors: number, dither: number): RawImage;
|
||||
zx_quantize(data: BufferSource, width: number, height: number, dither: number): RawImage;
|
||||
free_result(): void;
|
||||
}
|
||||
|
||||
export default function(opts: EmscriptenWasm.ModuleOpts): QuantizerModule;
|
||||
|
||||
|
||||
81
codecs/imagequant/imagequant.js
Normal file
81
codecs/imagequant/imagequant.js
Normal file
@@ -0,0 +1,81 @@
|
||||
|
||||
var imagequant = (function() {
|
||||
var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined;
|
||||
if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename;
|
||||
return (
|
||||
function(imagequant) {
|
||||
imagequant = imagequant || {};
|
||||
|
||||
var e;e||(e=typeof imagequant !== 'undefined' ? imagequant : {});var r={},t;for(t in e)e.hasOwnProperty(t)&&(r[t]=e[t]);var aa=!1,z=!1,ba=!1,ca=!1;aa="object"===typeof window;z="function"===typeof importScripts;ba="object"===typeof process&&"object"===typeof process.versions&&"string"===typeof process.versions.node;ca=!aa&&!ba&&!z;var A="",da,B,ea,ha;
|
||||
if(ba)A=z?require("path").dirname(A)+"/":__dirname+"/",da=function(a,b){ea||(ea=require("fs"));ha||(ha=require("path"));a=ha.normalize(a);return ea.readFileSync(a,b?null:"utf8")},B=function(a){a=da(a,!0);a.buffer||(a=new Uint8Array(a));a.buffer||C("Assertion failed: undefined");return a},1<process.argv.length&&process.argv[1].replace(/\\/g,"/"),process.argv.slice(2),process.on("uncaughtException",function(a){throw a;}),process.on("unhandledRejection",C),e.inspect=function(){return"[Emscripten Module object]"};
|
||||
else if(ca)"undefined"!=typeof read&&(da=function(a){return read(a)}),B=function(a){if("function"===typeof readbuffer)return new Uint8Array(readbuffer(a));a=read(a,"binary");"object"===typeof a||C("Assertion failed: undefined");return a},"undefined"!==typeof print&&("undefined"===typeof console&&(console={}),console.log=print,console.warn=console.error="undefined"!==typeof printErr?printErr:print);else if(aa||z)z?A=self.location.href:document.currentScript&&(A=document.currentScript.src),_scriptDir&&
|
||||
(A=_scriptDir),0!==A.indexOf("blob:")?A=A.substr(0,A.lastIndexOf("/")+1):A="",da=function(a){var b=new XMLHttpRequest;b.open("GET",a,!1);b.send(null);return b.responseText},z&&(B=function(a){var b=new XMLHttpRequest;b.open("GET",a,!1);b.responseType="arraybuffer";b.send(null);return new Uint8Array(b.response)});var ia=e.print||console.log.bind(console),E=e.printErr||console.warn.bind(console);for(t in r)r.hasOwnProperty(t)&&(e[t]=r[t]);r=null;var F;e.wasmBinary&&(F=e.wasmBinary);var noExitRuntime;
|
||||
e.noExitRuntime&&(noExitRuntime=e.noExitRuntime);"object"!==typeof WebAssembly&&E("no native wasm support detected");var G,ja=new WebAssembly.Table({initial:55,maximum:55,element:"anyfunc"}),ka=!1,la="undefined"!==typeof TextDecoder?new TextDecoder("utf8"):void 0;
|
||||
function ma(a,b,c){var d=b+c;for(c=b;a[c]&&!(c>=d);)++c;if(16<c-b&&a.subarray&&la)return la.decode(a.subarray(b,c));for(d="";b<c;){var f=a[b++];if(f&128){var g=a[b++]&63;if(192==(f&224))d+=String.fromCharCode((f&31)<<6|g);else{var n=a[b++]&63;f=224==(f&240)?(f&15)<<12|g<<6|n:(f&7)<<18|g<<12|n<<6|a[b++]&63;65536>f?d+=String.fromCharCode(f):(f-=65536,d+=String.fromCharCode(55296|f>>10,56320|f&1023))}}else d+=String.fromCharCode(f)}return d}
|
||||
function na(a,b,c){var d=H;if(0<c){c=b+c-1;for(var f=0;f<a.length;++f){var g=a.charCodeAt(f);if(55296<=g&&57343>=g){var n=a.charCodeAt(++f);g=65536+((g&1023)<<10)|n&1023}if(127>=g){if(b>=c)break;d[b++]=g}else{if(2047>=g){if(b+1>=c)break;d[b++]=192|g>>6}else{if(65535>=g){if(b+2>=c)break;d[b++]=224|g>>12}else{if(b+3>=c)break;d[b++]=240|g>>18;d[b++]=128|g>>12&63}d[b++]=128|g>>6&63}d[b++]=128|g&63}}d[b]=0}}var oa="undefined"!==typeof TextDecoder?new TextDecoder("utf-16le"):void 0;
|
||||
function pa(a){var b;for(b=a>>1;I[b];)++b;b<<=1;if(32<b-a&&oa)return oa.decode(H.subarray(a,b));b=0;for(var c="";;){var d=I[a+2*b>>1];if(0==d)return c;++b;c+=String.fromCharCode(d)}}function qa(a,b,c){void 0===c&&(c=2147483647);if(2>c)return 0;c-=2;var d=b;c=c<2*a.length?c/2:a.length;for(var f=0;f<c;++f)I[b>>1]=a.charCodeAt(f),b+=2;I[b>>1]=0;return b-d}function ra(a){return 2*a.length}
|
||||
function sa(a){for(var b=0,c="";;){var d=J[a+4*b>>2];if(0==d)return c;++b;65536<=d?(d-=65536,c+=String.fromCharCode(55296|d>>10,56320|d&1023)):c+=String.fromCharCode(d)}}function ta(a,b,c){void 0===c&&(c=2147483647);if(4>c)return 0;var d=b;c=d+c-4;for(var f=0;f<a.length;++f){var g=a.charCodeAt(f);if(55296<=g&&57343>=g){var n=a.charCodeAt(++f);g=65536+((g&1023)<<10)|n&1023}J[b>>2]=g;b+=4;if(b+4>c)break}J[b>>2]=0;return b-d}
|
||||
function ua(a){for(var b=0,c=0;c<a.length;++c){var d=a.charCodeAt(c);55296<=d&&57343>=d&&++c;b+=4}return b}var K,va,H,I,wa,J,L,xa,ya;function za(a){K=a;e.HEAP8=va=new Int8Array(a);e.HEAP16=I=new Int16Array(a);e.HEAP32=J=new Int32Array(a);e.HEAPU8=H=new Uint8Array(a);e.HEAPU16=wa=new Uint16Array(a);e.HEAPU32=L=new Uint32Array(a);e.HEAPF32=xa=new Float32Array(a);e.HEAPF64=ya=new Float64Array(a)}var Aa=e.INITIAL_MEMORY||16777216;e.wasmMemory?G=e.wasmMemory:G=new WebAssembly.Memory({initial:Aa/65536});
|
||||
G&&(K=G.buffer);Aa=K.byteLength;za(K);J[1612]=5249488;function Ba(a){for(;0<a.length;){var b=a.shift();if("function"==typeof b)b();else{var c=b.ta;"number"===typeof c?void 0===b.la?e.dynCall_v(c):e.dynCall_vi(c,b.la):c(void 0===b.la?null:b.la)}}}var Ca=[],Da=[],Ea=[],Fa=[];function Ga(){var a=e.preRun.shift();Ca.unshift(a)}var M=0,Ha=null,N=null;e.preloadedImages={};e.preloadedAudios={};
|
||||
function C(a){if(e.onAbort)e.onAbort(a);ia(a);E(a);ka=!0;throw new WebAssembly.RuntimeError("abort("+a+"). Build with -s ASSERTIONS=1 for more info.");}function Ia(){var a=O;return String.prototype.startsWith?a.startsWith("data:application/octet-stream;base64,"):0===a.indexOf("data:application/octet-stream;base64,")}var O="imagequant.wasm";if(!Ia()){var Ja=O;O=e.locateFile?e.locateFile(Ja,A):A+Ja}
|
||||
function Ka(){try{if(F)return new Uint8Array(F);if(B)return B(O);throw"both async and sync fetching of the wasm failed";}catch(a){C(a)}}function La(){return F||!aa&&!z||"function"!==typeof fetch?new Promise(function(a){a(Ka())}):fetch(O,{credentials:"same-origin"}).then(function(a){if(!a.ok)throw"failed to load wasm binary file at '"+O+"'";return a.arrayBuffer()}).catch(function(){return Ka()})}Da.push({ta:function(){Ma()}});function Na(){return 0<Na.ga}
|
||||
function Oa(a){switch(a){case 1:return 0;case 2:return 1;case 4:return 2;case 8:return 3;default:throw new TypeError("Unknown type size: "+a);}}var Pa=void 0;function P(a){for(var b="";H[a];)b+=Pa[H[a++]];return b}var Q={},R={},Qa={};function Ra(a){if(void 0===a)return"_unknown";a=a.replace(/[^a-zA-Z0-9_]/g,"$");var b=a.charCodeAt(0);return 48<=b&&57>=b?"_"+a:a}
|
||||
function Sa(a,b){a=Ra(a);return(new Function("body","return function "+a+'() {\n "use strict"; return body.apply(this, arguments);\n};\n'))(b)}function Ta(a){var b=Error,c=Sa(a,function(d){this.name=a;this.message=d;d=Error(d).stack;void 0!==d&&(this.stack=this.toString()+"\n"+d.replace(/^Error(:[^\n]*)?\n/,""))});c.prototype=Object.create(b.prototype);c.prototype.constructor=c;c.prototype.toString=function(){return void 0===this.message?this.name:this.name+": "+this.message};return c}
|
||||
var Ua=void 0;function S(a){throw new Ua(a);}var Va=void 0;function Wa(a){throw new Va(a);}function Xa(a,b,c){function d(h){h=c(h);h.length!==a.length&&Wa("Mismatched type converter count");for(var k=0;k<a.length;++k)T(a[k],h[k])}a.forEach(function(h){Qa[h]=b});var f=Array(b.length),g=[],n=0;b.forEach(function(h,k){R.hasOwnProperty(h)?f[k]=R[h]:(g.push(h),Q.hasOwnProperty(h)||(Q[h]=[]),Q[h].push(function(){f[k]=R[h];++n;n===g.length&&d(f)}))});0===g.length&&d(f)}
|
||||
function T(a,b,c){c=c||{};if(!("argPackAdvance"in b))throw new TypeError("registerType registeredInstance requires argPackAdvance");var d=b.name;a||S('type "'+d+'" must have a positive integer typeid pointer');if(R.hasOwnProperty(a)){if(c.wa)return;S("Cannot register type '"+d+"' twice")}R[a]=b;delete Qa[a];Q.hasOwnProperty(a)&&(b=Q[a],delete Q[a],b.forEach(function(f){f()}))}function Ya(a){return{count:a.count,fa:a.fa,ha:a.ha,V:a.V,X:a.X,Y:a.Y,Z:a.Z}}
|
||||
function Za(a){S(a.U.X.W.name+" instance already deleted")}var $a=!1;function ab(){}function bb(a){--a.count.value;0===a.count.value&&(a.Y?a.Z.ea(a.Y):a.X.W.ea(a.V))}function cb(a){if("undefined"===typeof FinalizationGroup)return cb=function(b){return b},a;$a=new FinalizationGroup(function(b){for(var c=b.next();!c.done;c=b.next())c=c.value,c.V?bb(c):console.warn("object already deleted: "+c.V)});cb=function(b){$a.register(b,b.U,b.U);return b};ab=function(b){$a.unregister(b.U)};return cb(a)}
|
||||
var db=void 0,eb=[];function fb(){for(;eb.length;){var a=eb.pop();a.U.fa=!1;a["delete"]()}}function U(){}var gb={};function hb(a,b){var c=e;if(void 0===c[a].aa){var d=c[a];c[a]=function(){c[a].aa.hasOwnProperty(arguments.length)||S("Function '"+b+"' called with an invalid number of arguments ("+arguments.length+") - expects one of ("+c[a].aa+")!");return c[a].aa[arguments.length].apply(this,arguments)};c[a].aa=[];c[a].aa[d.qa]=d}}
|
||||
function ib(a,b,c){e.hasOwnProperty(a)?((void 0===c||void 0!==e[a].aa&&void 0!==e[a].aa[c])&&S("Cannot register public name '"+a+"' twice"),hb(a,a),e.hasOwnProperty(c)&&S("Cannot register multiple overloads of a function with the same number of arguments ("+c+")!"),e[a].aa[c]=b):(e[a]=b,void 0!==c&&(e[a].Ca=c))}function jb(a,b,c,d,f,g,n,h){this.name=a;this.constructor=b;this.da=c;this.ea=d;this.$=f;this.ua=g;this.ia=n;this.sa=h}
|
||||
function kb(a,b,c){for(;b!==c;)b.ia||S("Expected null or instance of "+c.name+", got an instance of "+b.name),a=b.ia(a),b=b.$;return a}function lb(a,b){if(null===b)return this.ma&&S("null is not a valid "+this.name),0;b.U||S('Cannot pass "'+V(b)+'" as a '+this.name);b.U.V||S("Cannot pass deleted object as a pointer of type "+this.name);return kb(b.U.V,b.U.X.W,this.W)}
|
||||
function mb(a,b){if(null===b){this.ma&&S("null is not a valid "+this.name);if(this.ka){var c=this.ya();null!==a&&a.push(this.ea,c);return c}return 0}b.U||S('Cannot pass "'+V(b)+'" as a '+this.name);b.U.V||S("Cannot pass deleted object as a pointer of type "+this.name);!this.ja&&b.U.X.ja&&S("Cannot convert argument of type "+(b.U.Z?b.U.Z.name:b.U.X.name)+" to parameter type "+this.name);c=kb(b.U.V,b.U.X.W,this.W);if(this.ka)switch(void 0===b.U.Y&&S("Passing raw pointer to smart pointer is illegal"),
|
||||
this.Aa){case 0:b.U.Z===this?c=b.U.Y:S("Cannot convert argument of type "+(b.U.Z?b.U.Z.name:b.U.X.name)+" to parameter type "+this.name);break;case 1:c=b.U.Y;break;case 2:if(b.U.Z===this)c=b.U.Y;else{var d=b.clone();c=this.za(c,nb(function(){d["delete"]()}));null!==a&&a.push(this.ea,c)}break;default:S("Unsupporting sharing policy")}return c}
|
||||
function ob(a,b){if(null===b)return this.ma&&S("null is not a valid "+this.name),0;b.U||S('Cannot pass "'+V(b)+'" as a '+this.name);b.U.V||S("Cannot pass deleted object as a pointer of type "+this.name);b.U.X.ja&&S("Cannot convert argument of type "+b.U.X.name+" to parameter type "+this.name);return kb(b.U.V,b.U.X.W,this.W)}function pb(a){return this.fromWireType(L[a>>2])}function rb(a,b,c){if(b===c)return a;if(void 0===c.$)return null;a=rb(a,b,c.$);return null===a?null:c.sa(a)}var sb={};
|
||||
function tb(a,b){for(void 0===b&&S("ptr should not be undefined");a.$;)b=a.ia(b),a=a.$;return sb[b]}function ub(a,b){b.X&&b.V||Wa("makeClassHandle requires ptr and ptrType");!!b.Z!==!!b.Y&&Wa("Both smartPtrType and smartPtr must be specified");b.count={value:1};return cb(Object.create(a,{U:{value:b}}))}
|
||||
function W(a,b,c,d){this.name=a;this.W=b;this.ma=c;this.ja=d;this.ka=!1;this.ea=this.za=this.ya=this.pa=this.Aa=this.xa=void 0;void 0!==b.$?this.toWireType=mb:(this.toWireType=d?lb:ob,this.ba=null)}function vb(a,b,c){e.hasOwnProperty(a)||Wa("Replacing nonexistant public symbol");void 0!==e[a].aa&&void 0!==c?e[a].aa[c]=b:(e[a]=b,e[a].qa=c)}
|
||||
function X(a,b){a=P(a);var c=e["dynCall_"+a];for(var d=[],f=1;f<a.length;++f)d.push("a"+f);f="return function dynCall_"+(a+"_"+b)+"("+d.join(", ")+") {\n";f+=" return dynCall(rawFunction"+(d.length?", ":"")+d.join(", ")+");\n";c=(new Function("dynCall","rawFunction",f+"};\n"))(c,b);"function"!==typeof c&&S("unknown function pointer with signature "+a+": "+b);return c}var wb=void 0;function xb(a){a=yb(a);var b=P(a);Y(a);return b}
|
||||
function zb(a,b){function c(g){f[g]||R[g]||(Qa[g]?Qa[g].forEach(c):(d.push(g),f[g]=!0))}var d=[],f={};b.forEach(c);throw new wb(a+": "+d.map(xb).join([", "]));}function Ab(a){for(;a.length;){var b=a.pop();a.pop()(b)}}function Bb(a,b,c){a instanceof Object||S(c+' with invalid "this": '+a);a instanceof b.W.constructor||S(c+' incompatible with "this" of type '+a.constructor.name);a.U.V||S("cannot call emscripten binding method "+c+" on deleted object");return kb(a.U.V,a.U.X.W,b.W)}
|
||||
var Cb=[],Z=[{},{value:void 0},{value:null},{value:!0},{value:!1}];function Db(a){4<a&&0===--Z[a].na&&(Z[a]=void 0,Cb.push(a))}function nb(a){switch(a){case void 0:return 1;case null:return 2;case !0:return 3;case !1:return 4;default:var b=Cb.length?Cb.pop():Z.length;Z[b]={na:1,value:a};return b}}function V(a){if(null===a)return"null";var b=typeof a;return"object"===b||"array"===b||"function"===b?a.toString():""+a}
|
||||
function Eb(a,b){switch(b){case 2:return function(c){return this.fromWireType(xa[c>>2])};case 3:return function(c){return this.fromWireType(ya[c>>3])};default:throw new TypeError("Unknown float type: "+a);}}function Fb(a){var b=Function;if(!(b instanceof Function))throw new TypeError("new_ called with constructor type "+typeof b+" which is not a function");var c=Sa(b.name||"unknownFunctionName",function(){});c.prototype=b.prototype;c=new c;a=b.apply(c,a);return a instanceof Object?a:c}
|
||||
function Gb(a,b){for(var c=[],d=0;d<a;d++)c.push(J[(b>>2)+d]);return c}function Hb(a,b,c){switch(b){case 0:return c?function(d){return va[d]}:function(d){return H[d]};case 1:return c?function(d){return I[d>>1]}:function(d){return wa[d>>1]};case 2:return c?function(d){return J[d>>2]}:function(d){return L[d>>2]};default:throw new TypeError("Unknown integer type: "+a);}}for(var Ib=[null,[],[]],Jb=Array(256),Kb=0;256>Kb;++Kb)Jb[Kb]=String.fromCharCode(Kb);Pa=Jb;Ua=e.BindingError=Ta("BindingError");
|
||||
Va=e.InternalError=Ta("InternalError");U.prototype.isAliasOf=function(a){if(!(this instanceof U&&a instanceof U))return!1;var b=this.U.X.W,c=this.U.V,d=a.U.X.W;for(a=a.U.V;b.$;)c=b.ia(c),b=b.$;for(;d.$;)a=d.ia(a),d=d.$;return b===d&&c===a};U.prototype.clone=function(){this.U.V||Za(this);if(this.U.ha)return this.U.count.value+=1,this;var a=cb(Object.create(Object.getPrototypeOf(this),{U:{value:Ya(this.U)}}));a.U.count.value+=1;a.U.fa=!1;return a};
|
||||
U.prototype["delete"]=function(){this.U.V||Za(this);this.U.fa&&!this.U.ha&&S("Object already scheduled for deletion");ab(this);bb(this.U);this.U.ha||(this.U.Y=void 0,this.U.V=void 0)};U.prototype.isDeleted=function(){return!this.U.V};U.prototype.deleteLater=function(){this.U.V||Za(this);this.U.fa&&!this.U.ha&&S("Object already scheduled for deletion");eb.push(this);1===eb.length&&db&&db(fb);this.U.fa=!0;return this};W.prototype.va=function(a){this.pa&&(a=this.pa(a));return a};
|
||||
W.prototype.oa=function(a){this.ea&&this.ea(a)};W.prototype.argPackAdvance=8;W.prototype.readValueFromPointer=pb;W.prototype.deleteObject=function(a){if(null!==a)a["delete"]()};
|
||||
W.prototype.fromWireType=function(a){function b(){return this.ka?ub(this.W.da,{X:this.xa,V:c,Z:this,Y:a}):ub(this.W.da,{X:this,V:a})}var c=this.va(a);if(!c)return this.oa(a),null;var d=tb(this.W,c);if(void 0!==d){if(0===d.U.count.value)return d.U.V=c,d.U.Y=a,d.clone();d=d.clone();this.oa(a);return d}d=this.W.ua(c);d=gb[d];if(!d)return b.call(this);d=this.ja?d.ra:d.pointerType;var f=rb(c,this.W,d.W);return null===f?b.call(this):this.ka?ub(d.W.da,{X:d,V:f,Z:this,Y:a}):ub(d.W.da,{X:d,V:f})};
|
||||
e.getInheritedInstanceCount=function(){return Object.keys(sb).length};e.getLiveInheritedInstances=function(){var a=[],b;for(b in sb)sb.hasOwnProperty(b)&&a.push(sb[b]);return a};e.flushPendingDeletes=fb;e.setDelayFunction=function(a){db=a;eb.length&&db&&db(fb)};wb=e.UnboundTypeError=Ta("UnboundTypeError");e.count_emval_handles=function(){for(var a=0,b=5;b<Z.length;++b)void 0!==Z[b]&&++a;return a};e.get_first_emval=function(){for(var a=5;a<Z.length;++a)if(void 0!==Z[a])return Z[a];return null};
|
||||
var Mb={o:function(a){return Lb(a)},n:function(a){"uncaught_exception"in Na?Na.ga++:Na.ga=1;throw a;},u:function(a,b,c,d,f){var g=Oa(c);b=P(b);T(a,{name:b,fromWireType:function(n){return!!n},toWireType:function(n,h){return h?d:f},argPackAdvance:8,readValueFromPointer:function(n){if(1===c)var h=va;else if(2===c)h=I;else if(4===c)h=J;else throw new TypeError("Unknown boolean type size: "+b);return this.fromWireType(h[n>>g])},ba:null})},p:function(a,b,c,d,f,g,n,h,k,l,m,q,v){m=P(m);g=X(f,g);h&&(h=X(n,
|
||||
h));l&&(l=X(k,l));v=X(q,v);var u=Ra(m);ib(u,function(){zb("Cannot construct "+m+" due to unbound types",[d])});Xa([a,b,c],d?[d]:[],function(p){p=p[0];if(d){var w=p.W;var x=w.da}else x=U.prototype;p=Sa(u,function(){if(Object.getPrototypeOf(this)!==y)throw new Ua("Use 'new' to construct "+m);if(void 0===D.ga)throw new Ua(m+" has no accessible constructor");var qb=D.ga[arguments.length];if(void 0===qb)throw new Ua("Tried to invoke ctor of "+m+" with invalid number of parameters ("+arguments.length+") - expected ("+
|
||||
Object.keys(D.ga).toString()+") parameters instead!");return qb.apply(this,arguments)});var y=Object.create(x,{constructor:{value:p}});p.prototype=y;var D=new jb(m,p,y,v,w,g,h,l);w=new W(m,D,!0,!1);x=new W(m+"*",D,!1,!1);var fa=new W(m+" const*",D,!1,!0);gb[a]={pointerType:x,ra:fa};vb(u,p);return[w,x,fa]})},e:function(a,b,c,d,f,g,n,h,k,l){b=P(b);f=X(d,f);Xa([],[a],function(m){m=m[0];var q=m.name+"."+b,v={get:function(){zb("Cannot access "+q+" due to unbound types",[c,n])},enumerable:!0,configurable:!0};
|
||||
k?v.set=function(){zb("Cannot access "+q+" due to unbound types",[c,n])}:v.set=function(){S(q+" is a read-only property")};Object.defineProperty(m.W.da,b,v);Xa([],k?[c,n]:[c],function(u){var p=u[0],w={get:function(){var y=Bb(this,m,q+" getter");return p.fromWireType(f(g,y))},enumerable:!0};if(k){k=X(h,k);var x=u[1];w.set=function(y){var D=Bb(this,m,q+" setter"),fa=[];k(l,D,x.toWireType(fa,y));Ab(fa)}}Object.defineProperty(m.W.da,b,w);return[]});return[]})},t:function(a,b){b=P(b);T(a,{name:b,fromWireType:function(c){var d=
|
||||
Z[c].value;Db(c);return d},toWireType:function(c,d){return nb(d)},argPackAdvance:8,readValueFromPointer:pb,ba:null})},h:function(a,b,c){c=Oa(c);b=P(b);T(a,{name:b,fromWireType:function(d){return d},toWireType:function(d,f){if("number"!==typeof f&&"boolean"!==typeof f)throw new TypeError('Cannot convert "'+V(f)+'" to '+this.name);return f},argPackAdvance:8,readValueFromPointer:Eb(b,c),ba:null})},d:function(a,b,c,d,f,g){var n=Gb(b,c);a=P(a);f=X(d,f);ib(a,function(){zb("Cannot call "+a+" due to unbound types",
|
||||
n)},b-1);Xa([],n,function(h){var k=[h[0],null].concat(h.slice(1)),l=h=a,m=f,q=k.length;2>q&&S("argTypes array size mismatch! Must at least get return value and 'this' types!");for(var v=null!==k[1]&&!1,u=!1,p=1;p<k.length;++p)if(null!==k[p]&&void 0===k[p].ba){u=!0;break}var w="void"!==k[0].name,x="",y="";for(p=0;p<q-2;++p)x+=(0!==p?", ":"")+"arg"+p,y+=(0!==p?", ":"")+"arg"+p+"Wired";l="return function "+Ra(l)+"("+x+") {\nif (arguments.length !== "+(q-2)+") {\nthrowBindingError('function "+l+" called with ' + arguments.length + ' arguments, expected "+
|
||||
(q-2)+" args!');\n}\n";u&&(l+="var destructors = [];\n");var D=u?"destructors":"null";x="throwBindingError invoker fn runDestructors retType classParam".split(" ");m=[S,m,g,Ab,k[0],k[1]];v&&(l+="var thisWired = classParam.toWireType("+D+", this);\n");for(p=0;p<q-2;++p)l+="var arg"+p+"Wired = argType"+p+".toWireType("+D+", arg"+p+"); // "+k[p+2].name+"\n",x.push("argType"+p),m.push(k[p+2]);v&&(y="thisWired"+(0<y.length?", ":"")+y);l+=(w?"var rv = ":"")+"invoker(fn"+(0<y.length?", ":"")+y+");\n";if(u)l+=
|
||||
"runDestructors(destructors);\n";else for(p=v?1:2;p<k.length;++p)q=1===p?"thisWired":"arg"+(p-2)+"Wired",null!==k[p].ba&&(l+=q+"_dtor("+q+"); // "+k[p].name+"\n",x.push(q+"_dtor"),m.push(k[p].ba));w&&(l+="var ret = retType.fromWireType(rv);\nreturn ret;\n");x.push(l+"}\n");k=Fb(x).apply(null,m);vb(h,k,b-1);return[]})},b:function(a,b,c,d,f){function g(l){return l}b=P(b);-1===f&&(f=4294967295);var n=Oa(c);if(0===d){var h=32-8*c;g=function(l){return l<<h>>>h}}var k=-1!=b.indexOf("unsigned");T(a,{name:b,
|
||||
fromWireType:g,toWireType:function(l,m){if("number"!==typeof m&&"boolean"!==typeof m)throw new TypeError('Cannot convert "'+V(m)+'" to '+this.name);if(m<d||m>f)throw new TypeError('Passing a number "'+V(m)+'" from JS side to C/C++ side to an argument of type "'+b+'", which is outside the valid range ['+d+", "+f+"]!");return k?m>>>0:m|0},argPackAdvance:8,readValueFromPointer:Hb(b,n,0!==d),ba:null})},a:function(a,b,c){function d(g){g>>=2;var n=L;return new f(K,n[g+1],n[g])}var f=[Int8Array,Uint8Array,
|
||||
Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array][b];c=P(c);T(a,{name:c,fromWireType:d,argPackAdvance:8,readValueFromPointer:d},{wa:!0})},i:function(a,b){b=P(b);var c="std::string"===b;T(a,{name:b,fromWireType:function(d){var f=L[d>>2];if(c){var g=H[d+4+f],n=0;0!=g&&(n=g,H[d+4+f]=0);var h=d+4;for(g=0;g<=f;++g){var k=d+4+g;if(0==H[k]){h=h?ma(H,h,void 0):"";if(void 0===l)var l=h;else l+=String.fromCharCode(0),l+=h;h=k+1}}0!=n&&(H[d+4+f]=n)}else{l=Array(f);for(g=0;g<f;++g)l[g]=
|
||||
String.fromCharCode(H[d+4+g]);l=l.join("")}Y(d);return l},toWireType:function(d,f){f instanceof ArrayBuffer&&(f=new Uint8Array(f));var g="string"===typeof f;g||f instanceof Uint8Array||f instanceof Uint8ClampedArray||f instanceof Int8Array||S("Cannot pass non-string to std::string");var n=(c&&g?function(){for(var l=0,m=0;m<f.length;++m){var q=f.charCodeAt(m);55296<=q&&57343>=q&&(q=65536+((q&1023)<<10)|f.charCodeAt(++m)&1023);127>=q?++l:l=2047>=q?l+2:65535>=q?l+3:l+4}return l}:function(){return f.length})(),
|
||||
h=Lb(4+n+1);L[h>>2]=n;if(c&&g)na(f,h+4,n+1);else if(g)for(g=0;g<n;++g){var k=f.charCodeAt(g);255<k&&(Y(h),S("String has UTF-16 code units that do not fit in 8 bits"));H[h+4+g]=k}else for(g=0;g<n;++g)H[h+4+g]=f[g];null!==d&&d.push(Y,h);return h},argPackAdvance:8,readValueFromPointer:pb,ba:function(d){Y(d)}})},f:function(a,b,c){c=P(c);if(2===b){var d=pa;var f=qa;var g=ra;var n=function(){return wa};var h=1}else 4===b&&(d=sa,f=ta,g=ua,n=function(){return L},h=2);T(a,{name:c,fromWireType:function(k){var l=
|
||||
L[k>>2],m=n(),q=m[k+4+l*b>>h],v=0;0!=q&&(v=q,m[k+4+l*b>>h]=0);var u=k+4;for(q=0;q<=l;++q){var p=k+4+q*b;if(0==m[p>>h]){u=d(u);if(void 0===w)var w=u;else w+=String.fromCharCode(0),w+=u;u=p+b}}0!=v&&(m[k+4+l*b>>h]=v);Y(k);return w},toWireType:function(k,l){"string"!==typeof l&&S("Cannot pass non-string to C++ string type "+c);var m=g(l),q=Lb(4+m+b);L[q>>2]=m>>h;f(l,q+4,m+b);null!==k&&k.push(Y,q);return q},argPackAdvance:8,readValueFromPointer:pb,ba:function(k){Y(k)}})},v:function(a,b){b=P(b);T(a,{Ba:!0,
|
||||
name:b,argPackAdvance:0,fromWireType:function(){},toWireType:function(){}})},g:Db,w:function(a){4<a&&(Z[a].na+=1)},k:function(a,b){var c=R[a];void 0===c&&S("_emval_take_value has unknown type "+xb(a));a=c.readValueFromPointer(b);return nb(a)},m:function(){C()},s:function(a,b,c){H.copyWithin(a,b,b+c)},c:function(a){var b=H.length;if(2147418112<a)return!1;for(var c=1;4>=c;c*=2){var d=b*(1+.2/c);d=Math.min(d,a+100663296);d=Math.max(16777216,a,d);0<d%65536&&(d+=65536-d%65536);a:{try{G.grow(Math.min(2147418112,
|
||||
d)-K.byteLength+65535>>16);za(G.buffer);var f=1;break a}catch(g){}f=void 0}if(f)return!0}return!1},l:function(){return 0},q:function(){},j:function(a,b,c,d){for(var f=0,g=0;g<c;g++){for(var n=J[b+8*g>>2],h=J[b+(8*g+4)>>2],k=0;k<h;k++){var l=H[n+k],m=Ib[a];0===l||10===l?((1===a?ia:E)(ma(m,0)),m.length=0):m.push(l)}f+=h}J[d>>2]=f;return 0},memory:G,r:function(){},table:ja},Nb=function(){function a(f){e.asm=f.exports;M--;e.monitorRunDependencies&&e.monitorRunDependencies(M);0==M&&(null!==Ha&&(clearInterval(Ha),
|
||||
Ha=null),N&&(f=N,N=null,f()))}function b(f){a(f.instance)}function c(f){return La().then(function(g){return WebAssembly.instantiate(g,d)}).then(f,function(g){E("failed to asynchronously prepare wasm: "+g);C(g)})}var d={a:Mb};M++;e.monitorRunDependencies&&e.monitorRunDependencies(M);if(e.instantiateWasm)try{return e.instantiateWasm(d,a)}catch(f){return E("Module.instantiateWasm callback failed with error: "+f),!1}(function(){if(F||"function"!==typeof WebAssembly.instantiateStreaming||Ia()||"function"!==
|
||||
typeof fetch)return c(b);fetch(O,{credentials:"same-origin"}).then(function(f){return WebAssembly.instantiateStreaming(f,d).then(b,function(g){E("wasm streaming compile failed: "+g);E("falling back to ArrayBuffer instantiation");c(b)})})})();return{}}();e.asm=Nb;
|
||||
var Ma=e.___wasm_call_ctors=function(){return(Ma=e.___wasm_call_ctors=e.asm.x).apply(null,arguments)},Lb=e._malloc=function(){return(Lb=e._malloc=e.asm.y).apply(null,arguments)},Y=e._free=function(){return(Y=e._free=e.asm.z).apply(null,arguments)},yb=e.___getTypeName=function(){return(yb=e.___getTypeName=e.asm.A).apply(null,arguments)};e.___embind_register_native_and_builtin_types=function(){return(e.___embind_register_native_and_builtin_types=e.asm.B).apply(null,arguments)};
|
||||
e.dynCall_ii=function(){return(e.dynCall_ii=e.asm.C).apply(null,arguments)};e.dynCall_vi=function(){return(e.dynCall_vi=e.asm.D).apply(null,arguments)};e.dynCall_iii=function(){return(e.dynCall_iii=e.asm.E).apply(null,arguments)};e.dynCall_viii=function(){return(e.dynCall_viii=e.asm.F).apply(null,arguments)};e.dynCall_iiiiiif=function(){return(e.dynCall_iiiiiif=e.asm.G).apply(null,arguments)};e.dynCall_viiiiif=function(){return(e.dynCall_viiiiif=e.asm.H).apply(null,arguments)};
|
||||
e.dynCall_iiiiif=function(){return(e.dynCall_iiiiif=e.asm.I).apply(null,arguments)};e.dynCall_viiiif=function(){return(e.dynCall_viiiif=e.asm.J).apply(null,arguments)};e.dynCall_i=function(){return(e.dynCall_i=e.asm.K).apply(null,arguments)};e.dynCall_v=function(){return(e.dynCall_v=e.asm.L).apply(null,arguments)};e.dynCall_vif=function(){return(e.dynCall_vif=e.asm.M).apply(null,arguments)};e.dynCall_iidiiii=function(){return(e.dynCall_iidiiii=e.asm.N).apply(null,arguments)};
|
||||
e.dynCall_vii=function(){return(e.dynCall_vii=e.asm.O).apply(null,arguments)};e.dynCall_iiii=function(){return(e.dynCall_iiii=e.asm.P).apply(null,arguments)};e.dynCall_jiji=function(){return(e.dynCall_jiji=e.asm.Q).apply(null,arguments)};e.dynCall_viiiiii=function(){return(e.dynCall_viiiiii=e.asm.R).apply(null,arguments)};e.dynCall_viiiii=function(){return(e.dynCall_viiiii=e.asm.S).apply(null,arguments)};e.dynCall_viiii=function(){return(e.dynCall_viiii=e.asm.T).apply(null,arguments)};e.asm=Nb;var Ob;
|
||||
e.then=function(a){if(Ob)a(e);else{var b=e.onRuntimeInitialized;e.onRuntimeInitialized=function(){b&&b();a(e)}}return e};N=function Pb(){Ob||Qb();Ob||(N=Pb)};
|
||||
function Qb(){function a(){if(!Ob&&(Ob=!0,e.calledRun=!0,!ka)){Ba(Da);Ba(Ea);if(e.onRuntimeInitialized)e.onRuntimeInitialized();if(e.postRun)for("function"==typeof e.postRun&&(e.postRun=[e.postRun]);e.postRun.length;){var b=e.postRun.shift();Fa.unshift(b)}Ba(Fa)}}if(!(0<M)){if(e.preRun)for("function"==typeof e.preRun&&(e.preRun=[e.preRun]);e.preRun.length;)Ga();Ba(Ca);0<M||(e.setStatus?(e.setStatus("Running..."),setTimeout(function(){setTimeout(function(){e.setStatus("")},1);a()},1)):a())}}
|
||||
e.run=Qb;if(e.preInit)for("function"==typeof e.preInit&&(e.preInit=[e.preInit]);0<e.preInit.length;)e.preInit.pop()();noExitRuntime=!0;Qb();
|
||||
|
||||
|
||||
return imagequant
|
||||
}
|
||||
);
|
||||
})();
|
||||
if (typeof exports === 'object' && typeof module === 'object')
|
||||
module.exports = imagequant;
|
||||
else if (typeof define === 'function' && define['amd'])
|
||||
define([], function() { return imagequant; });
|
||||
else if (typeof exports === 'object')
|
||||
exports["imagequant"] = imagequant;
|
||||
|
||||
BIN
codecs/imagequant/imagequant.wasm
Normal file
BIN
codecs/imagequant/imagequant.wasm
Normal file
Binary file not shown.
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "webp_enc",
|
||||
"name": "imagequant",
|
||||
"requires": true,
|
||||
"lockfileVersion": 1,
|
||||
"dependencies": {
|
||||
13
codecs/imagequant/package.json
Normal file
13
codecs/imagequant/package.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "imagequant",
|
||||
"scripts": {
|
||||
"install": "napa",
|
||||
"build": "docker run --rm -v $(pwd):/src trzeci/emscripten-upstream ./build.sh"
|
||||
},
|
||||
"napa": {
|
||||
"libimagequant": "ImageOptim/libimagequant#2.12.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"napa": "3.0.0"
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,6 @@
|
||||
## Dependencies
|
||||
|
||||
- Docker
|
||||
- Automake
|
||||
- pkg-config
|
||||
|
||||
## Example
|
||||
|
||||
@@ -19,26 +17,31 @@ See `example.html`
|
||||
|
||||
Returns the version of MozJPEG as a number. va.b.c is encoded as 0x0a0b0c
|
||||
|
||||
### `uint8_t* create_buffer(int width, int height)`
|
||||
|
||||
Allocates an RGBA buffer for an image with the given dimension.
|
||||
|
||||
### `void destroy_buffer(uint8_t* p)`
|
||||
|
||||
Frees a buffer created with `create_buffer`.
|
||||
|
||||
### `void encode(uint8_t* image_buffer, int image_width, int image_height, int quality)`
|
||||
|
||||
Encodes the given image with given dimension to JPEG. `quality` is a number between 0 and 100. The higher the number, the better the quality of the encoded image. The result is implicitly stored and can be accessed using the `get_result_*()` functions.
|
||||
|
||||
### `void free_result()`
|
||||
|
||||
Frees the result created by `encode()`.
|
||||
|
||||
### `int get_result_pointer()`
|
||||
### `Uint8Array encode(std::string image_in, int image_width, int image_height, MozJpegOptions opts)`
|
||||
|
||||
Returns the pointer to the start of the buffer holding the encoded data.
|
||||
Encodes the given image with given dimension to JPEG. Options looks like this:
|
||||
|
||||
### `int get_result_size()`
|
||||
|
||||
Returns the length of the buffer holding the encoded data.
|
||||
```c++
|
||||
struct MozJpegOptions {
|
||||
int quality;
|
||||
bool baseline;
|
||||
bool arithmetic;
|
||||
bool progressive;
|
||||
bool optimize_coding;
|
||||
int smoothing;
|
||||
int color_space;
|
||||
int quant_table;
|
||||
bool trellis_multipass;
|
||||
bool trellis_opt_zero;
|
||||
bool trellis_opt_table;
|
||||
int trellis_loops;
|
||||
bool auto_subsample;
|
||||
int chroma_subsample;
|
||||
bool separate_chroma_quality;
|
||||
int chroma_quality;
|
||||
};
|
||||
```
|
||||
|
||||
52
codecs/mozjpeg_enc/build.sh
Executable file
52
codecs/mozjpeg_enc/build.sh
Executable file
@@ -0,0 +1,52 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
export EM_CACHE="${PWD}/node_modules/.em_cache"
|
||||
export OPTIMIZE="-Os -flto --llvm-lto 1"
|
||||
export LDFLAGS="${OPTIMIZE}"
|
||||
export CFLAGS="${OPTIMIZE}"
|
||||
export CPPFLAGS="${OPTIMIZE}"
|
||||
|
||||
apt-get update
|
||||
apt-get install -qqy autoconf libtool libpng-dev pkg-config
|
||||
|
||||
echo "============================================="
|
||||
echo "Compiling mozjpeg"
|
||||
echo "============================================="
|
||||
(
|
||||
cd node_modules/mozjpeg
|
||||
autoreconf -iv
|
||||
emconfigure ./configure -C --without-simd
|
||||
emmake make libjpeg.la rdswitch.o -j`nproc`
|
||||
)
|
||||
echo "============================================="
|
||||
echo "Compiling mozjpeg done"
|
||||
echo "============================================="
|
||||
|
||||
echo "============================================="
|
||||
echo "Compiling wasm bindings"
|
||||
echo "============================================="
|
||||
(
|
||||
emcc \
|
||||
--bind \
|
||||
${OPTIMIZE} \
|
||||
--closure 1 \
|
||||
-s ALLOW_MEMORY_GROWTH=1 \
|
||||
-s MODULARIZE=1 \
|
||||
-s 'EXPORT_NAME="mozjpeg_enc"' \
|
||||
-I node_modules/mozjpeg \
|
||||
-o ./mozjpeg_enc.js \
|
||||
-std=c++11 \
|
||||
mozjpeg_enc.cpp \
|
||||
node_modules/mozjpeg/.libs/libjpeg.a \
|
||||
node_modules/mozjpeg/rdswitch.o
|
||||
)
|
||||
echo "============================================="
|
||||
echo "Compiling wasm bindings done"
|
||||
echo "============================================="
|
||||
|
||||
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
||||
echo "Did you update your docker image?"
|
||||
echo "Run \`docker pull trzeci/emscripten-upstream\`"
|
||||
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
||||
@@ -1,7 +1,7 @@
|
||||
<!doctype html>
|
||||
<script src='mozjpeg_enc.js'></script>
|
||||
<script>
|
||||
const Module = mozjpeg_enc();
|
||||
const module = mozjpeg_enc();
|
||||
|
||||
async function loadImage(src) {
|
||||
// Load image
|
||||
@@ -17,27 +17,27 @@
|
||||
return ctx.getImageData(0, 0, img.width, img.height);
|
||||
}
|
||||
|
||||
Module.onRuntimeInitialized = async _ => {
|
||||
const api = {
|
||||
version: Module.cwrap('version', 'number', []),
|
||||
create_buffer: Module.cwrap('create_buffer', 'number', ['number', 'number']),
|
||||
destroy_buffer: Module.cwrap('destroy_buffer', '', ['number']),
|
||||
encode: Module.cwrap('encode', '', ['number', 'number', 'number', 'number']),
|
||||
free_result: Module.cwrap('free_result', '', ['number']),
|
||||
get_result_pointer: Module.cwrap('get_result_pointer', 'number', []),
|
||||
get_result_size: Module.cwrap('get_result_size', 'number', []),
|
||||
};
|
||||
console.log('Version:', api.version().toString(16));
|
||||
module.onRuntimeInitialized = async _ => {
|
||||
console.log('Version:', module.version().toString(16));
|
||||
const image = await loadImage('../example.png');
|
||||
const p = api.create_buffer(image.width, image.height);
|
||||
Module.HEAP8.set(image.data, p);
|
||||
api.encode(p, image.width, image.height, 2);
|
||||
const resultPointer = api.get_result_pointer();
|
||||
const resultSize = api.get_result_size();
|
||||
const resultView = new Uint8Array(Module.HEAP8.buffer, resultPointer, resultSize);
|
||||
const result = new Uint8Array(resultView);
|
||||
api.free_result(resultPointer);
|
||||
api.destroy_buffer(p);
|
||||
const result = module.encode(image.data, image.width, image.height, {
|
||||
quality: 75,
|
||||
baseline: false,
|
||||
arithmetic: false,
|
||||
progressive: true,
|
||||
optimize_coding: true,
|
||||
smoothing: 0,
|
||||
color_space: 3,
|
||||
quant_table: 3,
|
||||
trellis_multipass: false,
|
||||
trellis_opt_zero: false,
|
||||
trellis_opt_table: false,
|
||||
trellis_loops: 1,
|
||||
auto_subsample: true,
|
||||
chroma_subsample: 2,
|
||||
separate_chroma_quality: false,
|
||||
chroma_quality: 75,
|
||||
});
|
||||
|
||||
const blob = new Blob([result], {type: 'image/jpeg'});
|
||||
const blobURL = URL.createObjectURL(blob);
|
||||
|
||||
@@ -1,17 +1,44 @@
|
||||
#include "emscripten.h"
|
||||
#include <stdlib.h>
|
||||
#include <emscripten/bind.h>
|
||||
#include <emscripten/val.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <setjmp.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "jpeglib.h"
|
||||
#include "config.h"
|
||||
#include "jpeglib.h"
|
||||
|
||||
// MozJPEG doesn’t expose a numeric version, so I have to do some fun C macro hackery to turn it into a string. More details here: https://gcc.gnu.org/onlinedocs/cpp/Stringizing.html
|
||||
extern "C" {
|
||||
#include "cdjpeg.h"
|
||||
}
|
||||
|
||||
using namespace emscripten;
|
||||
|
||||
// MozJPEG doesn’t expose a numeric version, so I have to do some fun C macro
|
||||
// hackery to turn it into a string. More details here:
|
||||
// https://gcc.gnu.org/onlinedocs/cpp/Stringizing.html
|
||||
#define xstr(s) str(s)
|
||||
#define str(s) #s
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
struct MozJpegOptions {
|
||||
int quality;
|
||||
bool baseline;
|
||||
bool arithmetic;
|
||||
bool progressive;
|
||||
bool optimize_coding;
|
||||
int smoothing;
|
||||
int color_space;
|
||||
int quant_table;
|
||||
bool trellis_multipass;
|
||||
bool trellis_opt_zero;
|
||||
bool trellis_opt_table;
|
||||
int trellis_loops;
|
||||
bool auto_subsample;
|
||||
int chroma_subsample;
|
||||
bool separate_chroma_quality;
|
||||
int chroma_quality;
|
||||
};
|
||||
|
||||
int version() {
|
||||
char buffer[] = xstr(MOZJPEG_VERSION);
|
||||
int version = 0;
|
||||
@@ -28,40 +55,22 @@ int version() {
|
||||
return version;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
uint8_t* create_buffer(int width, int height) {
|
||||
return malloc(width * height * 4 * sizeof(uint8_t));
|
||||
}
|
||||
uint8_t* last_result;
|
||||
struct jpeg_compress_struct cinfo;
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
void destroy_buffer(uint8_t* p) {
|
||||
free(p);
|
||||
}
|
||||
|
||||
int result[2];
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
void encode(uint8_t* image_buffer, int image_width, int image_height, int quality) {
|
||||
// Manually convert RGBA data into RGB
|
||||
for(int y = 0; y < image_height; y++) {
|
||||
for(int x = 0; x < image_width; x++) {
|
||||
image_buffer[(y*image_width + x)*3 + 0] = image_buffer[(y*image_width + x)*4 + 0];
|
||||
image_buffer[(y*image_width + x)*3 + 1] = image_buffer[(y*image_width + x)*4 + 1];
|
||||
image_buffer[(y*image_width + x)*3 + 2] = image_buffer[(y*image_width + x)*4 + 2];
|
||||
}
|
||||
}
|
||||
val encode(std::string image_in, int image_width, int image_height, MozJpegOptions opts) {
|
||||
uint8_t* image_buffer = (uint8_t*)image_in.c_str();
|
||||
|
||||
// The code below is basically the `write_JPEG_file` function from
|
||||
// https://github.com/mozilla/mozjpeg/blob/master/example.c
|
||||
// I just write to memory instead of a file.
|
||||
|
||||
|
||||
/* This struct contains the JPEG compression parameters and pointers to
|
||||
* working space (which is allocated as needed by the JPEG library).
|
||||
* It is possible to have several such structures, representing multiple
|
||||
* compression/decompression processes, in existence at once. We refer
|
||||
* to any one struct (and its associated working data) as a "JPEG object".
|
||||
*/
|
||||
struct jpeg_compress_struct cinfo;
|
||||
/* This struct represents a JPEG error handler. It is declared separately
|
||||
* because applications often want to supply a specialized error handler
|
||||
* (see the second half of this file for an example). But here we just
|
||||
@@ -109,18 +118,57 @@ void encode(uint8_t* image_buffer, int image_width, int image_height, int qualit
|
||||
*/
|
||||
cinfo.image_width = image_width; /* image width and height, in pixels */
|
||||
cinfo.image_height = image_height;
|
||||
cinfo.input_components = 3; /* # of color components per pixel */
|
||||
cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
|
||||
cinfo.input_components = 4; /* # of color components per pixel */
|
||||
cinfo.in_color_space = JCS_EXT_RGBA; /* colorspace of input image */
|
||||
/* Now use the library's routine to set default compression parameters.
|
||||
* (You must set at least cinfo.in_color_space before calling this,
|
||||
* since the defaults depend on the source color space.)
|
||||
*/
|
||||
jpeg_set_defaults(&cinfo);
|
||||
/* Now you can set any non-default parameters you wish to.
|
||||
* Here we just illustrate the use of quality (quantization table) scaling:
|
||||
*/
|
||||
jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
|
||||
|
||||
jpeg_set_colorspace(&cinfo, (J_COLOR_SPACE)opts.color_space);
|
||||
|
||||
if (opts.quant_table != -1) {
|
||||
jpeg_c_set_int_param(&cinfo, JINT_BASE_QUANT_TBL_IDX, opts.quant_table);
|
||||
}
|
||||
|
||||
cinfo.optimize_coding = opts.optimize_coding;
|
||||
|
||||
if (opts.arithmetic) {
|
||||
cinfo.arith_code = TRUE;
|
||||
cinfo.optimize_coding = FALSE;
|
||||
}
|
||||
|
||||
cinfo.smoothing_factor = opts.smoothing;
|
||||
|
||||
jpeg_c_set_bool_param(&cinfo, JBOOLEAN_USE_SCANS_IN_TRELLIS, opts.trellis_multipass);
|
||||
jpeg_c_set_bool_param(&cinfo, JBOOLEAN_TRELLIS_EOB_OPT, opts.trellis_opt_zero);
|
||||
jpeg_c_set_bool_param(&cinfo, JBOOLEAN_TRELLIS_Q_OPT, opts.trellis_opt_table);
|
||||
jpeg_c_set_int_param(&cinfo, JINT_TRELLIS_NUM_LOOPS, opts.trellis_loops);
|
||||
|
||||
// A little hacky to build a string for this, but it means we can use
|
||||
// set_quality_ratings which does some useful heuristic stuff.
|
||||
std::string quality_str = std::to_string(opts.quality);
|
||||
|
||||
if (opts.separate_chroma_quality && opts.color_space == JCS_YCbCr) {
|
||||
quality_str += "," + std::to_string(opts.chroma_quality);
|
||||
}
|
||||
|
||||
char const* pqual = quality_str.c_str();
|
||||
|
||||
set_quality_ratings(&cinfo, (char*)pqual, opts.baseline);
|
||||
|
||||
if (!opts.auto_subsample && opts.color_space == JCS_YCbCr) {
|
||||
cinfo.comp_info[0].h_samp_factor = opts.chroma_subsample;
|
||||
cinfo.comp_info[0].v_samp_factor = opts.chroma_subsample;
|
||||
}
|
||||
|
||||
if (!opts.baseline && opts.progressive) {
|
||||
jpeg_simple_progression(&cinfo);
|
||||
} else {
|
||||
cinfo.num_scans = 0;
|
||||
cinfo.scan_info = NULL;
|
||||
}
|
||||
/* Step 4: Start compressor */
|
||||
|
||||
/* TRUE ensures that we will write a complete interchange-JPEG file.
|
||||
@@ -136,7 +184,7 @@ void encode(uint8_t* image_buffer, int image_width, int image_height, int qualit
|
||||
* To keep things simple, we pass one scanline per call; you can pass
|
||||
* more if you wish, though.
|
||||
*/
|
||||
row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */
|
||||
row_stride = image_width * 4; /* JSAMPLEs per row in image_buffer */
|
||||
|
||||
while (cinfo.next_scanline < cinfo.image_height) {
|
||||
/* jpeg_write_scanlines expects an array of pointers to scanlines.
|
||||
@@ -152,27 +200,37 @@ void encode(uint8_t* image_buffer, int image_width, int image_height, int qualit
|
||||
jpeg_finish_compress(&cinfo);
|
||||
/* Step 7: release JPEG compression object */
|
||||
|
||||
result[0] = (int)output;
|
||||
result[1] = size;
|
||||
|
||||
/* This is an important step since it will release a good deal of memory. */
|
||||
jpeg_destroy_compress(&cinfo);
|
||||
last_result = output;
|
||||
|
||||
/* And we're done! */
|
||||
return val(typed_memory_view(size, output));
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
void free_result() {
|
||||
free(result[0]); // not sure if this is right with mozjpeg
|
||||
/* This is an important step since it will release a good deal of memory. */
|
||||
jpeg_destroy_compress(&cinfo);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
int get_result_pointer() {
|
||||
return result[0];
|
||||
}
|
||||
EMSCRIPTEN_BINDINGS(my_module) {
|
||||
value_object<MozJpegOptions>("MozJpegOptions")
|
||||
.field("quality", &MozJpegOptions::quality)
|
||||
.field("baseline", &MozJpegOptions::baseline)
|
||||
.field("arithmetic", &MozJpegOptions::arithmetic)
|
||||
.field("progressive", &MozJpegOptions::progressive)
|
||||
.field("optimize_coding", &MozJpegOptions::optimize_coding)
|
||||
.field("smoothing", &MozJpegOptions::smoothing)
|
||||
.field("color_space", &MozJpegOptions::color_space)
|
||||
.field("quant_table", &MozJpegOptions::quant_table)
|
||||
.field("trellis_multipass", &MozJpegOptions::trellis_multipass)
|
||||
.field("trellis_opt_zero", &MozJpegOptions::trellis_opt_zero)
|
||||
.field("trellis_opt_table", &MozJpegOptions::trellis_opt_table)
|
||||
.field("trellis_loops", &MozJpegOptions::trellis_loops)
|
||||
.field("chroma_subsample", &MozJpegOptions::chroma_subsample)
|
||||
.field("auto_subsample", &MozJpegOptions::auto_subsample)
|
||||
.field("separate_chroma_quality", &MozJpegOptions::separate_chroma_quality)
|
||||
.field("chroma_quality", &MozJpegOptions::chroma_quality);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
int get_result_size() {
|
||||
return result[1];
|
||||
function("version", &version);
|
||||
function("encode", &encode);
|
||||
function("free_result", &free_result);
|
||||
}
|
||||
|
||||
9
codecs/mozjpeg_enc/mozjpeg_enc.d.ts
vendored
9
codecs/mozjpeg_enc/mozjpeg_enc.d.ts
vendored
@@ -1 +1,8 @@
|
||||
export default function(opts: EmscriptenWasm.ModuleOpts): EmscriptenWasm.Module;
|
||||
import { EncodeOptions } from '../../src/codecs/mozjpeg/encoder-meta';
|
||||
|
||||
interface MozJPEGModule extends EmscriptenWasm.Module {
|
||||
encode(data: BufferSource, width: number, height: number, options: EncodeOptions): Uint8Array;
|
||||
free_result(): void;
|
||||
}
|
||||
|
||||
export default function(opts: EmscriptenWasm.ModuleOpts): MozJPEGModule;
|
||||
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -2,14 +2,12 @@
|
||||
"name": "mozjpeg_enc",
|
||||
"scripts": {
|
||||
"install": "napa",
|
||||
"build": "npm run build:library && npm run build:wasm",
|
||||
"build:library": "cd node_modules/mozjpeg && autoreconf -fiv && docker run --rm -v $(pwd):/src trzeci/emscripten emconfigure ./configure --without-simd && docker run --rm -v $(pwd):/src trzeci/emscripten emmake make libjpeg.la",
|
||||
"build:wasm": "docker run --rm -v $(pwd):/src trzeci/emscripten emcc -O3 -s WASM=1 -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"cwrap\"]' -s ALLOW_MEMORY_GROWTH=1 -s MODULARIZE=1 -s 'EXPORT_NAME=\"mozjpeg_enc\"' -I node_modules/mozjpeg -o ./mozjpeg_enc.js mozjpeg_enc.c node_modules/mozjpeg/.libs/libjpeg.a"
|
||||
"build": "docker run --rm -v $(pwd):/src trzeci/emscripten-upstream ./build.sh"
|
||||
},
|
||||
"napa": {
|
||||
"mozjpeg": "mozilla/mozjpeg#v3.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"napa": "^3.0.0"
|
||||
"napa": "3.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
1
codecs/oxipng/.gitignore
vendored
Normal file
1
codecs/oxipng/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
502
codecs/oxipng/Cargo.lock
generated
Normal file
502
codecs/oxipng/Cargo.lock
generated
Normal file
@@ -0,0 +1,502 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "adler32"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bit-vec"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "build_const"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cloudflare-zlib"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cloudflare-zlib-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cloudflare-zlib-sys"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memoffset 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-queue"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deflate"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.23.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bytemuck 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-iter 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-rational 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"png 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inflate"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libdeflater"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "maybe-uninit"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-iter"
|
||||
version = "0.1.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oxipng"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"oxipng 2.3.0 (git+https://github.com/shssoichiro/oxipng.git)",
|
||||
"wasm-bindgen 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oxipng"
|
||||
version = "2.3.0"
|
||||
source = "git+https://github.com/shssoichiro/oxipng.git#ec8ecf5a800dfb41359d9cf41eed8a730062b9a8"
|
||||
dependencies = [
|
||||
"bit-vec 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cloudflare-zlib 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"image 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"indexmap 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libdeflater 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"miniz_oxide 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rgb 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"zopfli 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"deflate 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rgb"
|
||||
version = "0.8.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typed-arena"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen-macro 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bumpalo 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen-shared 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen-macro-support 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen-backend 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen-shared 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "zopfli"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"typed-arena 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[metadata]
|
||||
"checksum adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2"
|
||||
"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
||||
"checksum bit-vec 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a4523a10839ffae575fb08aa3423026c8cb4687eef43952afb956229d4f246f7"
|
||||
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39"
|
||||
"checksum bumpalo 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "12ae9db68ad7fac5fe51304d20f016c911539251075a214f8e663babefa35187"
|
||||
"checksum bytemuck 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37fa13df2292ecb479ec23aa06f4507928bef07839be9ef15281411076629431"
|
||||
"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
||||
"checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd"
|
||||
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
"checksum cloudflare-zlib 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f5ed63a019d55bacd15cadcbcb96bf41b16281417fff393bdb55fa84255fe4b9"
|
||||
"checksum cloudflare-zlib-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7e195cb274a0d6ee87e718838a09baecd7cbc9f6075dac256a84cb5842739c06"
|
||||
"checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb"
|
||||
"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
|
||||
"checksum crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285"
|
||||
"checksum crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
|
||||
"checksum crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db"
|
||||
"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
||||
"checksum deflate 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "050ef6de42a33903b30a7497b76b40d3d58691d4d3eec355348c122444a388f0"
|
||||
"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
|
||||
"checksum hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e"
|
||||
"checksum image 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9062b90712d25bc6bb165d110aa59c6b47c849246e341e7b86a98daff9d49f60"
|
||||
"checksum indexmap 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "076f042c5b7b98f31d205f1249267e12a6518c1481e9dae9764af19b707d2292"
|
||||
"checksum inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff"
|
||||
"checksum itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
|
||||
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
"checksum libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0"
|
||||
"checksum libdeflater 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "66dca08b13369865b2f6dca1dd05f833985cbe6c12a676b04d55f78b85e80246"
|
||||
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
||||
"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
||||
"checksum memoffset 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b4fc2c02a7e374099d4ee95a193111f72d2110197fe200272371758f6c3643d8"
|
||||
"checksum miniz_oxide 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aa679ff6578b1cddee93d7e82e263b94a575e0bfced07284eb0c037c1d2416a5"
|
||||
"checksum num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba"
|
||||
"checksum num-iter 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "dfb0800a0291891dd9f4fe7bd9c19384f98f7fbe0cd0f39a2c6b88b9868bbc00"
|
||||
"checksum num-rational 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef"
|
||||
"checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
|
||||
"checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6"
|
||||
"checksum oxipng 2.3.0 (git+https://github.com/shssoichiro/oxipng.git)" = "<none>"
|
||||
"checksum png 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46060468187c21c00ffa2a920690b29997d7fd543f5a4d400461e4a7d4fccde8"
|
||||
"checksum proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3"
|
||||
"checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f"
|
||||
"checksum rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db6ce3297f9c85e16621bb8cca38a06779ffc31bb8184e1be4bed2be4678a098"
|
||||
"checksum rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08a89b46efaf957e52b18062fb2f4660f8b8a4dde1807ca002690868ef2c85a9"
|
||||
"checksum rgb 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)" = "a85b83fd629b0ce765f45316774fa6aaa95947fd74c8e4bbf3c6d1e349701d95"
|
||||
"checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
"checksum syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03"
|
||||
"checksum typed-arena 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b2228007eba4120145f785df0f6c92ea538f5a3635a612ecf4e334c8c1446d"
|
||||
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||
"checksum wasm-bindgen 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "2cc57ce05287f8376e998cbddfb4c8cb43b84a7ec55cf4551d7c00eef317a47f"
|
||||
"checksum wasm-bindgen-backend 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "d967d37bf6c16cca2973ca3af071d0a2523392e4a594548155d89a678f4237cd"
|
||||
"checksum wasm-bindgen-macro 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "8bd151b63e1ea881bb742cd20e1d6127cef28399558f3b5d415289bc41eee3a4"
|
||||
"checksum wasm-bindgen-macro-support 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "d68a5b36eef1be7868f668632863292e37739656a80fc4b9acec7b0bd35a4931"
|
||||
"checksum wasm-bindgen-shared 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "daf76fe7d25ac79748a37538b7daeed1c7a6867c92d3245c12c6222e4a20d639"
|
||||
"checksum zopfli 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4079b79464426ade2a1b0177fb0ce8396ba6b4084267407e333573c666073964"
|
||||
21
codecs/oxipng/Cargo.toml
Normal file
21
codecs/oxipng/Cargo.toml
Normal file
@@ -0,0 +1,21 @@
|
||||
[package]
|
||||
name = "oxipng"
|
||||
version = "0.1.0"
|
||||
authors = ["Ingvar Stepanyan <me@rreverser.com>"]
|
||||
edition = "2018"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
oxipng = { version = "2.3.0", default-features = false }
|
||||
wasm-bindgen = "0.2.48"
|
||||
log = { version = "0.4", features = ["release_max_level_off"] }
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
opt-level = "s"
|
||||
|
||||
[patch.crates-io]
|
||||
oxipng = { git = "https://github.com/shssoichiro/oxipng.git", branch = "master" }
|
||||
12
codecs/oxipng/Dockerfile
Normal file
12
codecs/oxipng/Dockerfile
Normal file
@@ -0,0 +1,12 @@
|
||||
FROM rust
|
||||
RUN rustup target add wasm32-unknown-unknown
|
||||
RUN curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||
|
||||
RUN mkdir /opt/wabt && \
|
||||
curl -L https://github.com/WebAssembly/wabt/releases/download/1.0.11/wabt-1.0.11-linux.tar.gz | tar -xzf - -C /opt/wabt --strip 1
|
||||
|
||||
RUN mkdir /opt/wasi-sdk && \
|
||||
curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-8/wasi-sdk-8.0-linux.tar.gz | tar -xzf - -C /opt/wasi-sdk --strip 1
|
||||
|
||||
ENV PATH="/opt/wabt:/opt/wasi-sdk/bin:${PATH}"
|
||||
WORKDIR /src
|
||||
22
codecs/oxipng/build.sh
Normal file
22
codecs/oxipng/build.sh
Normal file
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
echo "============================================="
|
||||
echo "Compiling wasm"
|
||||
echo "============================================="
|
||||
(
|
||||
wasm-pack build
|
||||
wasm-strip pkg/oxipng_bg.wasm
|
||||
rm pkg/.gitignore
|
||||
)
|
||||
echo "============================================="
|
||||
echo "Compiling wasm done"
|
||||
echo "============================================="
|
||||
|
||||
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
||||
echo "Did you update your docker image?"
|
||||
echo "Run \`docker pull ubuntu\`"
|
||||
echo "Run \`docker pull rust\`"
|
||||
echo "Run \`docker build -t squoosh-oxipng .\`"
|
||||
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
||||
4
codecs/oxipng/package-lock.json
generated
Normal file
4
codecs/oxipng/package-lock.json
generated
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "oxipng",
|
||||
"lockfileVersion": 1
|
||||
}
|
||||
7
codecs/oxipng/package.json
Normal file
7
codecs/oxipng/package.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "oxipng",
|
||||
"scripts": {
|
||||
"build:image": "docker build -t squoosh-oxipng .",
|
||||
"build": "docker run --rm -v $(pwd):/src squoosh-oxipng ./build.sh"
|
||||
}
|
||||
}
|
||||
8
codecs/oxipng/pkg/oxipng.d.ts
vendored
Normal file
8
codecs/oxipng/pkg/oxipng.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* @param {Uint8Array} data
|
||||
* @param {number} level
|
||||
* @returns {Uint8Array}
|
||||
*/
|
||||
export function optimise(data: Uint8Array, level: number): Uint8Array;
|
||||
60
codecs/oxipng/pkg/oxipng.js
Normal file
60
codecs/oxipng/pkg/oxipng.js
Normal file
@@ -0,0 +1,60 @@
|
||||
import * as wasm from './oxipng_bg.wasm';
|
||||
|
||||
const lTextDecoder = typeof TextDecoder === 'undefined' ? require('util').TextDecoder : TextDecoder;
|
||||
|
||||
let cachedTextDecoder = new lTextDecoder('utf-8', { ignoreBOM: true, fatal: true });
|
||||
|
||||
cachedTextDecoder.decode();
|
||||
|
||||
let cachegetUint8Memory0 = null;
|
||||
function getUint8Memory0() {
|
||||
if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== wasm.memory.buffer) {
|
||||
cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer);
|
||||
}
|
||||
return cachegetUint8Memory0;
|
||||
}
|
||||
|
||||
function getStringFromWasm0(ptr, len) {
|
||||
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
|
||||
}
|
||||
|
||||
let WASM_VECTOR_LEN = 0;
|
||||
|
||||
function passArray8ToWasm0(arg, malloc) {
|
||||
const ptr = malloc(arg.length * 1);
|
||||
getUint8Memory0().set(arg, ptr / 1);
|
||||
WASM_VECTOR_LEN = arg.length;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
let cachegetInt32Memory0 = null;
|
||||
function getInt32Memory0() {
|
||||
if (cachegetInt32Memory0 === null || cachegetInt32Memory0.buffer !== wasm.memory.buffer) {
|
||||
cachegetInt32Memory0 = new Int32Array(wasm.memory.buffer);
|
||||
}
|
||||
return cachegetInt32Memory0;
|
||||
}
|
||||
|
||||
function getArrayU8FromWasm0(ptr, len) {
|
||||
return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len);
|
||||
}
|
||||
/**
|
||||
* @param {Uint8Array} data
|
||||
* @param {number} level
|
||||
* @returns {Uint8Array}
|
||||
*/
|
||||
export function optimise(data, level) {
|
||||
var ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_malloc);
|
||||
var len0 = WASM_VECTOR_LEN;
|
||||
wasm.optimise(8, ptr0, len0, level);
|
||||
var r0 = getInt32Memory0()[8 / 4 + 0];
|
||||
var r1 = getInt32Memory0()[8 / 4 + 1];
|
||||
var v1 = getArrayU8FromWasm0(r0, r1).slice();
|
||||
wasm.__wbindgen_free(r0, r1 * 1);
|
||||
return v1;
|
||||
}
|
||||
|
||||
export const __wbindgen_throw = function(arg0, arg1) {
|
||||
throw new Error(getStringFromWasm0(arg0, arg1));
|
||||
};
|
||||
|
||||
8
codecs/oxipng/pkg/oxipng_bg.d.ts
vendored
Normal file
8
codecs/oxipng/pkg/oxipng_bg.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export const memory: WebAssembly.Memory;
|
||||
export function optimise(a: number, b: number, c: number, d: number): void;
|
||||
export function malloc(a: number): number;
|
||||
export function free(a: number): void;
|
||||
export function __wbindgen_malloc(a: number): number;
|
||||
export function __wbindgen_free(a: number, b: number): void;
|
||||
BIN
codecs/oxipng/pkg/oxipng_bg.wasm
Normal file
BIN
codecs/oxipng/pkg/oxipng_bg.wasm
Normal file
Binary file not shown.
15
codecs/oxipng/pkg/package.json
Normal file
15
codecs/oxipng/pkg/package.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "oxipng",
|
||||
"collaborators": [
|
||||
"Ingvar Stepanyan <me@rreverser.com>"
|
||||
],
|
||||
"version": "0.1.0",
|
||||
"files": [
|
||||
"oxipng_bg.wasm",
|
||||
"oxipng.js",
|
||||
"oxipng.d.ts"
|
||||
],
|
||||
"module": "oxipng.js",
|
||||
"types": "oxipng.d.ts",
|
||||
"sideEffects": false
|
||||
}
|
||||
10
codecs/oxipng/src/lib.rs
Normal file
10
codecs/oxipng/src/lib.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
mod malloc_shim;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen(catch)]
|
||||
pub fn optimise(data: &[u8], level: u8) -> Vec<u8> {
|
||||
let mut options = oxipng::Options::from_preset(level);
|
||||
options.deflate = oxipng::Deflaters::Libdeflater;
|
||||
oxipng::optimize_from_memory(data, &options).unwrap_throw()
|
||||
}
|
||||
47
codecs/oxipng/src/malloc_shim.rs
Normal file
47
codecs/oxipng/src/malloc_shim.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
//! This is a module that provides `malloc` and `free` for `libdeflate`.
|
||||
//! These implementations are compatible with the standard signatures
|
||||
//! but use Rust allocator instead of including libc one as well.
|
||||
//!
|
||||
//! Rust allocator APIs requires passing size and alignment to the
|
||||
//! `dealloc` function. This is different from C API, which only
|
||||
//! expects a pointer in `free` and expects allocators to take care of
|
||||
//! storing any necessary information elsewhere.
|
||||
//!
|
||||
//! In order to simulate C API, we allocate a `size_and_data_ptr`
|
||||
//! of size `sizeof(usize) + size` where `size` is the requested number
|
||||
//! of bytes. Then, we store `size` at the beginning of the allocated
|
||||
//! chunk (within those `sizeof(usize)` bytes) and return
|
||||
//! `data_ptr = size_and_data_ptr + sizeof(usize)` to the calleer:
|
||||
//!
|
||||
//! [`size`][...actual data]
|
||||
//! -^------------------ `size_and_data_ptr`
|
||||
//! ---------^---------- `data_ptr`
|
||||
//!
|
||||
//! Then, in `free`, the caller gives us `data_ptr`. We can subtract
|
||||
//! `sizeof(usize)` back and get the original `size_and_data_ptr`.
|
||||
//! At this point we can read `size` back and call the Rust `dealloc`
|
||||
//! for the whole allocated chunk.
|
||||
//!
|
||||
//! I've raised an upstream issue to hopefully make this easier in
|
||||
//! future: https://github.com/ebiggers/libdeflate/issues/62
|
||||
|
||||
use std::alloc::*;
|
||||
use std::mem::{align_of, size_of};
|
||||
|
||||
unsafe fn layout_for(size: usize) -> Layout {
|
||||
Layout::from_size_align_unchecked(size_of::<usize>() + size, align_of::<usize>())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn malloc(size: usize) -> *mut u8 {
|
||||
let size_and_data_ptr = alloc(layout_for(size));
|
||||
*(size_and_data_ptr as *mut usize) = size;
|
||||
size_and_data_ptr.add(size_of::<usize>())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn free(data_ptr: *mut u8) {
|
||||
let size_and_data_ptr = data_ptr.sub(size_of::<usize>());
|
||||
let size = *(size_and_data_ptr as *const usize);
|
||||
dealloc(size_and_data_ptr, layout_for(size))
|
||||
}
|
||||
6
codecs/resize/.gitignore
vendored
Normal file
6
codecs/resize/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
**/*.rs.bk
|
||||
target
|
||||
Cargo.lock
|
||||
bin/
|
||||
pkg/README.md
|
||||
lut.inc
|
||||
37
codecs/resize/Cargo.toml
Normal file
37
codecs/resize/Cargo.toml
Normal file
@@ -0,0 +1,37 @@
|
||||
[package]
|
||||
name = "resize"
|
||||
version = "0.1.0"
|
||||
authors = ["Surma <surma@surma.link>"]
|
||||
|
||||
[lib]
|
||||
#crate-type = ["cdylib", "rlib"]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[features]
|
||||
default = ["console_error_panic_hook", "wee_alloc"]
|
||||
|
||||
[dependencies]
|
||||
cfg-if = "0.1.2"
|
||||
wasm-bindgen = "0.2.38"
|
||||
resize = "0.3.0"
|
||||
|
||||
# The `console_error_panic_hook` crate provides better debugging of panics by
|
||||
# logging them with `console.error`. This is great for development, but requires
|
||||
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
|
||||
# code size when deploying.
|
||||
console_error_panic_hook = { version = "0.1.1", optional = true }
|
||||
|
||||
# `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size
|
||||
# compared to the default allocator's ~10K. It is slower than the default
|
||||
# allocator, however.
|
||||
#
|
||||
# Unfortunately, `wee_alloc` requires nightly Rust when targeting wasm for now.
|
||||
wee_alloc = { version = "0.4.2", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen-test = "0.2"
|
||||
|
||||
[profile.release]
|
||||
# Tell `rustc` to optimize for small code size.
|
||||
opt-level = "s"
|
||||
lto = true
|
||||
9
codecs/resize/Dockerfile
Normal file
9
codecs/resize/Dockerfile
Normal file
@@ -0,0 +1,9 @@
|
||||
FROM rust
|
||||
RUN rustup target add wasm32-unknown-unknown
|
||||
RUN curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||
|
||||
RUN mkdir /opt/wabt && \
|
||||
curl -L https://github.com/WebAssembly/wabt/releases/download/1.0.11/wabt-1.0.11-linux.tar.gz | tar -xzf - -C /opt/wabt --strip 1
|
||||
|
||||
ENV PATH="/opt/wabt:${PATH}"
|
||||
WORKDIR /src
|
||||
23
codecs/resize/build.rs
Normal file
23
codecs/resize/build.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
include!("./src/srgb.rs");
|
||||
|
||||
use std::io::Write;
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
let mut srgb_to_linear_lut = String::from("static SRGB_TO_LINEAR_LUT: [f32; 256] = [");
|
||||
let mut linear_to_srgb_lut = String::from("static LINEAR_TO_SRGB_LUT: [f32; 256] = [");
|
||||
for i in 0..256 {
|
||||
srgb_to_linear_lut.push_str(&format!("{0:.7}", srgb_to_linear((i as f32) / 255.0)));
|
||||
srgb_to_linear_lut.push_str(",");
|
||||
linear_to_srgb_lut.push_str(&format!("{0:.7}", linear_to_srgb((i as f32) / 255.0)));
|
||||
linear_to_srgb_lut.push_str(",");
|
||||
}
|
||||
srgb_to_linear_lut.pop().unwrap();
|
||||
linear_to_srgb_lut.pop().unwrap();
|
||||
srgb_to_linear_lut.push_str("];");
|
||||
linear_to_srgb_lut.push_str("];");
|
||||
|
||||
let mut file = std::fs::File::create("src/lut.inc")?;
|
||||
file.write_all(srgb_to_linear_lut.as_bytes())?;
|
||||
file.write_all(linear_to_srgb_lut.as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
22
codecs/resize/build.sh
Executable file
22
codecs/resize/build.sh
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
echo "============================================="
|
||||
echo "Compiling wasm"
|
||||
echo "============================================="
|
||||
(
|
||||
wasm-pack build
|
||||
wasm-strip pkg/resize_bg.wasm
|
||||
rm pkg/.gitignore
|
||||
)
|
||||
echo "============================================="
|
||||
echo "Compiling wasm done"
|
||||
echo "============================================="
|
||||
|
||||
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
||||
echo "Did you update your docker image?"
|
||||
echo "Run \`docker pull ubuntu\`"
|
||||
echo "Run \`docker pull rust\`"
|
||||
echo "Run \`docker build -t squoosh-resize .\`"
|
||||
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
||||
4
codecs/resize/package-lock.json
generated
Normal file
4
codecs/resize/package-lock.json
generated
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "resize",
|
||||
"lockfileVersion": 1
|
||||
}
|
||||
7
codecs/resize/package.json
Normal file
7
codecs/resize/package.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "resize",
|
||||
"scripts": {
|
||||
"build:image": "docker build -t squoosh-resize .",
|
||||
"build": "docker run --rm -v $(pwd):/src squoosh-resize ./build.sh"
|
||||
}
|
||||
}
|
||||
15
codecs/resize/pkg/package.json
Normal file
15
codecs/resize/pkg/package.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "resize",
|
||||
"collaborators": [
|
||||
"Surma <surma@surma.link>"
|
||||
],
|
||||
"version": "0.1.0",
|
||||
"files": [
|
||||
"resize_bg.wasm",
|
||||
"resize.js",
|
||||
"resize.d.ts"
|
||||
],
|
||||
"module": "resize.js",
|
||||
"types": "resize.d.ts",
|
||||
"sideEffects": "false"
|
||||
}
|
||||
13
codecs/resize/pkg/resize.d.ts
vendored
Normal file
13
codecs/resize/pkg/resize.d.ts
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
/* tslint:disable */
|
||||
/**
|
||||
* @param {Uint8Array} input_image
|
||||
* @param {number} input_width
|
||||
* @param {number} input_height
|
||||
* @param {number} output_width
|
||||
* @param {number} output_height
|
||||
* @param {number} typ_idx
|
||||
* @param {boolean} premultiply
|
||||
* @param {boolean} color_space_conversion
|
||||
* @returns {Uint8Array}
|
||||
*/
|
||||
export function resize(input_image: Uint8Array, input_width: number, input_height: number, output_width: number, output_height: number, typ_idx: number, premultiply: boolean, color_space_conversion: boolean): Uint8Array;
|
||||
50
codecs/resize/pkg/resize.js
Normal file
50
codecs/resize/pkg/resize.js
Normal file
@@ -0,0 +1,50 @@
|
||||
import * as wasm from './resize_bg.wasm';
|
||||
|
||||
let cachegetUint8Memory = null;
|
||||
function getUint8Memory() {
|
||||
if (cachegetUint8Memory === null || cachegetUint8Memory.buffer !== wasm.memory.buffer) {
|
||||
cachegetUint8Memory = new Uint8Array(wasm.memory.buffer);
|
||||
}
|
||||
return cachegetUint8Memory;
|
||||
}
|
||||
|
||||
let WASM_VECTOR_LEN = 0;
|
||||
|
||||
function passArray8ToWasm(arg) {
|
||||
const ptr = wasm.__wbindgen_malloc(arg.length * 1);
|
||||
getUint8Memory().set(arg, ptr / 1);
|
||||
WASM_VECTOR_LEN = arg.length;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
let cachegetInt32Memory = null;
|
||||
function getInt32Memory() {
|
||||
if (cachegetInt32Memory === null || cachegetInt32Memory.buffer !== wasm.memory.buffer) {
|
||||
cachegetInt32Memory = new Int32Array(wasm.memory.buffer);
|
||||
}
|
||||
return cachegetInt32Memory;
|
||||
}
|
||||
|
||||
function getArrayU8FromWasm(ptr, len) {
|
||||
return getUint8Memory().subarray(ptr / 1, ptr / 1 + len);
|
||||
}
|
||||
/**
|
||||
* @param {Uint8Array} input_image
|
||||
* @param {number} input_width
|
||||
* @param {number} input_height
|
||||
* @param {number} output_width
|
||||
* @param {number} output_height
|
||||
* @param {number} typ_idx
|
||||
* @param {boolean} premultiply
|
||||
* @param {boolean} color_space_conversion
|
||||
* @returns {Uint8Array}
|
||||
*/
|
||||
export function resize(input_image, input_width, input_height, output_width, output_height, typ_idx, premultiply, color_space_conversion) {
|
||||
const retptr = 8;
|
||||
const ret = wasm.resize(retptr, passArray8ToWasm(input_image), WASM_VECTOR_LEN, input_width, input_height, output_width, output_height, typ_idx, premultiply, color_space_conversion);
|
||||
const memi32 = getInt32Memory();
|
||||
const v0 = getArrayU8FromWasm(memi32[retptr / 4 + 0], memi32[retptr / 4 + 1]).slice();
|
||||
wasm.__wbindgen_free(memi32[retptr / 4 + 0], memi32[retptr / 4 + 1] * 1);
|
||||
return v0;
|
||||
}
|
||||
|
||||
5
codecs/resize/pkg/resize_bg.d.ts
vendored
Normal file
5
codecs/resize/pkg/resize_bg.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/* tslint:disable */
|
||||
export const memory: WebAssembly.Memory;
|
||||
export function __wbindgen_malloc(a: number): number;
|
||||
export function __wbindgen_free(a: number, b: number): void;
|
||||
export function resize(a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number): void;
|
||||
BIN
codecs/resize/pkg/resize_bg.wasm
Normal file
BIN
codecs/resize/pkg/resize_bg.wasm
Normal file
Binary file not shown.
121
codecs/resize/src/lib.rs
Normal file
121
codecs/resize/src/lib.rs
Normal file
@@ -0,0 +1,121 @@
|
||||
extern crate cfg_if;
|
||||
extern crate resize;
|
||||
extern crate wasm_bindgen;
|
||||
|
||||
mod utils;
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
use resize::Pixel::RGBA;
|
||||
use resize::Type;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
mod srgb;
|
||||
use srgb::Clamp;
|
||||
|
||||
cfg_if! {
|
||||
// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
|
||||
// allocator.
|
||||
if #[cfg(feature = "wee_alloc")] {
|
||||
extern crate wee_alloc;
|
||||
#[global_allocator]
|
||||
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
|
||||
}
|
||||
}
|
||||
|
||||
include!("./lut.inc");
|
||||
|
||||
// If `with_space_conversion` is true, this function returns 2 functions that
|
||||
// convert from sRGB to linear RGB and vice versa. If `with_space_conversion` is
|
||||
// false, the 2 functions returned do nothing.
|
||||
fn converter_funcs(with_space_conversion: bool) -> ((fn(u8) -> f32), (fn(f32) -> u8)) {
|
||||
if with_space_conversion {
|
||||
(
|
||||
|v| SRGB_TO_LINEAR_LUT[v as usize] * 255.0,
|
||||
|v| (LINEAR_TO_SRGB_LUT[v as usize] * 255.0) as u8,
|
||||
)
|
||||
} else {
|
||||
(|v| v as f32, |v| v as u8)
|
||||
}
|
||||
}
|
||||
|
||||
// If `with_alpha_premultiplication` is true, this function returns a function
|
||||
// that premultiply the alpha channel with the given channel value and another
|
||||
// function that reverses that process. If `with_alpha_premultiplication` is
|
||||
// false, the functions just return the channel value.
|
||||
fn alpha_multiplier_funcs(
|
||||
with_alpha_premultiplication: bool,
|
||||
) -> ((fn(f32, u8) -> u8), (fn(u8, u8) -> f32)) {
|
||||
if with_alpha_premultiplication {
|
||||
(
|
||||
|v, a| (v * (a as f32) / 255.0) as u8,
|
||||
|v, a| (v as f32) * 255.0 / (a as f32).clamp(0.0, 255.0),
|
||||
)
|
||||
} else {
|
||||
(|v, _a| v as u8, |v, _a| v as f32)
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[no_mangle]
|
||||
pub fn resize(
|
||||
mut input_image: Vec<u8>,
|
||||
input_width: usize,
|
||||
input_height: usize,
|
||||
output_width: usize,
|
||||
output_height: usize,
|
||||
typ_idx: usize,
|
||||
premultiply: bool,
|
||||
color_space_conversion: bool,
|
||||
) -> Vec<u8> {
|
||||
let typ = match typ_idx {
|
||||
0 => Type::Triangle,
|
||||
1 => Type::Catrom,
|
||||
2 => Type::Mitchell,
|
||||
3 => Type::Lanczos3,
|
||||
_ => panic!("Nope"),
|
||||
};
|
||||
let num_input_pixels = input_width * input_height;
|
||||
let num_output_pixels = output_width * output_height;
|
||||
|
||||
let (to_linear, to_color_space) = converter_funcs(color_space_conversion);
|
||||
let (premultiplier, demultiplier) = alpha_multiplier_funcs(premultiply);
|
||||
|
||||
// If both options are false, there is no preprocessing on the pixel valus
|
||||
// and we can skip the loop.
|
||||
if premultiply || color_space_conversion {
|
||||
for i in 0..num_input_pixels {
|
||||
for j in 0..3 {
|
||||
input_image[4 * i + j] =
|
||||
premultiplier(to_linear(input_image[4 * i + j]), input_image[4 * i + 3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut resizer = resize::new(
|
||||
input_width,
|
||||
input_height,
|
||||
output_width,
|
||||
output_height,
|
||||
RGBA,
|
||||
typ,
|
||||
);
|
||||
let mut output_image = Vec::<u8>::with_capacity(num_output_pixels * 4);
|
||||
output_image.resize(num_output_pixels * 4, 0);
|
||||
resizer.resize(input_image.as_slice(), output_image.as_mut_slice());
|
||||
|
||||
if premultiply || color_space_conversion {
|
||||
for i in 0..num_output_pixels {
|
||||
for j in 0..3 {
|
||||
// We don’t need to worry about division by zero, as division by zero
|
||||
// is well-defined on floats to return ±Inf. ±Inf is converted to 0
|
||||
// when casting to integers.
|
||||
output_image[4 * i + j] = to_color_space(demultiplier(
|
||||
output_image[4 * i + j],
|
||||
output_image[4 * i + 3],
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return output_image;
|
||||
}
|
||||
29
codecs/resize/src/srgb.rs
Normal file
29
codecs/resize/src/srgb.rs
Normal file
@@ -0,0 +1,29 @@
|
||||
pub trait Clamp: std::cmp::PartialOrd + Sized {
|
||||
fn clamp(self, min: Self, max: Self) -> Self {
|
||||
if self.lt(&min) {
|
||||
min
|
||||
} else if self.gt(&max) {
|
||||
max
|
||||
} else {
|
||||
self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clamp for f32 {}
|
||||
|
||||
pub fn srgb_to_linear(v: f32) -> f32 {
|
||||
if v < 0.04045 {
|
||||
v / 12.92
|
||||
} else {
|
||||
((v + 0.055) / 1.055).powf(2.4).clamp(0.0, 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn linear_to_srgb(v: f32) -> f32 {
|
||||
if v < 0.0031308 {
|
||||
v * 12.92
|
||||
} else {
|
||||
(1.055 * v.powf(1.0 / 2.4) - 0.055).clamp(0.0, 1.0)
|
||||
}
|
||||
}
|
||||
17
codecs/resize/src/utils.rs
Normal file
17
codecs/resize/src/utils.rs
Normal file
@@ -0,0 +1,17 @@
|
||||
use cfg_if::cfg_if;
|
||||
|
||||
cfg_if! {
|
||||
// When the `console_error_panic_hook` feature is enabled, we can call the
|
||||
// `set_panic_hook` function at least once during initialization, and then
|
||||
// we will get better error messages if our code ever panics.
|
||||
//
|
||||
// For more details see
|
||||
// https://github.com/rustwasm/console_error_panic_hook#readme
|
||||
if #[cfg(feature = "console_error_panic_hook")] {
|
||||
extern crate console_error_panic_hook;
|
||||
pub use self::console_error_panic_hook::set_once as set_panic_hook;
|
||||
} else {
|
||||
#[inline]
|
||||
pub fn set_panic_hook() {}
|
||||
}
|
||||
}
|
||||
2
codecs/rotate/.gitignore
vendored
Normal file
2
codecs/rotate/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
target
|
||||
Cargo.lock
|
||||
14
codecs/rotate/Cargo.toml
Normal file
14
codecs/rotate/Cargo.toml
Normal file
@@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "rotate"
|
||||
version = "0.1.0"
|
||||
authors = ["Surma <surma@google.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
name = "rotate"
|
||||
path = "rotate.rs"
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
opt-level = "s"
|
||||
8
codecs/rotate/Dockerfile
Normal file
8
codecs/rotate/Dockerfile
Normal file
@@ -0,0 +1,8 @@
|
||||
FROM rust
|
||||
RUN rustup target add wasm32-unknown-unknown
|
||||
|
||||
RUN mkdir /opt/wabt && \
|
||||
curl -L https://github.com/WebAssembly/wabt/releases/download/1.0.11/wabt-1.0.11-linux.tar.gz | tar -xzf - -C /opt/wabt --strip 1
|
||||
|
||||
ENV PATH="/opt/wabt:${PATH}"
|
||||
WORKDIR /src
|
||||
45
codecs/rotate/benchmark.js
Normal file
45
codecs/rotate/benchmark.js
Normal file
@@ -0,0 +1,45 @@
|
||||
// THIS IS NOT A NODE SCRIPT
|
||||
// This is a d8 script. Please install jsvu[1] and install v8.
|
||||
// Then run `npm run --silent benchmark`.
|
||||
// [1]: https://github.com/GoogleChromeLabs/jsvu
|
||||
async function init() {
|
||||
// Adjustable constants.
|
||||
const imageDimensions = 4096;
|
||||
const iterations = new Array(100);
|
||||
|
||||
// Constants. Don’t change.
|
||||
const imageByteSize = imageDimensions * imageDimensions * 4;
|
||||
const wasmPageSize = 64 * 1024;
|
||||
|
||||
const buffer = readbuffer("rotate.wasm");
|
||||
const { instance } = await WebAssembly.instantiate(buffer);
|
||||
|
||||
const pagesAvailable = Math.floor(
|
||||
instance.exports.memory.buffer.byteLength / wasmPageSize
|
||||
);
|
||||
const pagesNeeded = Math.floor((imageByteSize * 2 + 4) / wasmPageSize) + 1;
|
||||
const additionalPagesNeeded = pagesNeeded - pagesAvailable;
|
||||
if (additionalPagesNeeded > 0) {
|
||||
instance.exports.memory.grow(additionalPagesNeeded);
|
||||
}
|
||||
|
||||
[0, 90, 180, 270].forEach(rotation => {
|
||||
print(`\n${rotation} degrees`);
|
||||
print(`==============================`);
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const start = Date.now();
|
||||
instance.exports.rotate(imageDimensions, imageDimensions, rotation);
|
||||
iterations[i] = Date.now() - start;
|
||||
}
|
||||
const average = iterations.reduce((sum, c) => sum + c) / iterations.length;
|
||||
const stddev = Math.sqrt(
|
||||
iterations
|
||||
.map(i => Math.pow(i - average, 2))
|
||||
.reduce((sum, c) => sum + c) / iterations.length
|
||||
);
|
||||
print(`n = ${iterations.length}`);
|
||||
print(`Average: ${average}`);
|
||||
print(`StdDev: ${stddev}`);
|
||||
});
|
||||
}
|
||||
init().catch(e => console.error(e.stack));
|
||||
24
codecs/rotate/build.sh
Executable file
24
codecs/rotate/build.sh
Executable file
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
echo "============================================="
|
||||
echo "Compiling wasm"
|
||||
echo "============================================="
|
||||
(
|
||||
cargo build \
|
||||
--target wasm32-unknown-unknown \
|
||||
--release
|
||||
cp target/wasm32-unknown-unknown/release/rotate.wasm .
|
||||
wasm-strip rotate.wasm
|
||||
)
|
||||
echo "============================================="
|
||||
echo "Compiling wasm done"
|
||||
echo "============================================="
|
||||
|
||||
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
||||
echo "Did you update your docker image?"
|
||||
echo "Run \`docker pull ubuntu\`"
|
||||
echo "Run \`docker pull rust\`"
|
||||
echo "Run \`docker build -t squoosh-rotate .\`"
|
||||
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
||||
11
codecs/rotate/package.json
Normal file
11
codecs/rotate/package.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "rotate",
|
||||
"scripts": {
|
||||
"build:image": "docker build -t squoosh-rotate .",
|
||||
"build": "docker run --rm -v $(pwd):/src squoosh-rotate ./build.sh",
|
||||
"benchmark": "echo File size after gzip && npm run benchmark:filesize && echo Optimizing && npm run -s benchmark:optimizing",
|
||||
"benchmark:baseline": "v8 --liftoff --no-wasm-tier-up --no-opt ./benchmark.js",
|
||||
"benchmark:optimizing": "v8 --no-liftoff --no-wasm-tier-up ./benchmark.js",
|
||||
"benchmark:filesize": "cat rotate.wasm | gzip -c9n | wc -c"
|
||||
}
|
||||
}
|
||||
113
codecs/rotate/rotate.rs
Normal file
113
codecs/rotate/rotate.rs
Normal file
@@ -0,0 +1,113 @@
|
||||
use std::slice::{from_raw_parts, from_raw_parts_mut};
|
||||
|
||||
// This function is taken from Zachary Dremann
|
||||
// https://github.com/GoogleChromeLabs/squoosh/pull/462
|
||||
trait HardUnwrap<T> {
|
||||
fn unwrap_hard(self) -> T;
|
||||
}
|
||||
|
||||
impl<T> HardUnwrap<T> for Option<T> {
|
||||
#[cfg(not(debug_assertions))]
|
||||
#[inline]
|
||||
fn unwrap_hard(self) -> T {
|
||||
match self {
|
||||
Some(t) => t,
|
||||
None => std::process::abort(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
fn unwrap_hard(self) -> T {
|
||||
self.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
const TILE_SIZE: usize = 16;
|
||||
|
||||
fn get_buffers<'a>(width: usize, height: usize) -> (&'a [u32], &'a mut [u32]) {
|
||||
let num_pixels = width * height;
|
||||
let in_b: &[u32];
|
||||
let out_b: &mut [u32];
|
||||
unsafe {
|
||||
in_b = from_raw_parts::<u32>(8 as *const u32, num_pixels);
|
||||
out_b = from_raw_parts_mut::<u32>((num_pixels * 4 + 8) as *mut u32, num_pixels);
|
||||
}
|
||||
return (in_b, out_b);
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn rotate_0(width: usize, height: usize) {
|
||||
let (in_b, out_b) = get_buffers(width, height);
|
||||
for (in_p, out_p) in in_b.iter().zip(out_b.iter_mut()) {
|
||||
*out_p = *in_p;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn rotate_90(width: usize, height: usize) {
|
||||
let (in_b, out_b) = get_buffers(width, height);
|
||||
let new_width = height;
|
||||
let _new_height = width;
|
||||
for y_start in (0..height).step_by(TILE_SIZE) {
|
||||
for x_start in (0..width).step_by(TILE_SIZE) {
|
||||
for y in y_start..(y_start + TILE_SIZE).min(height) {
|
||||
let in_offset = y * width;
|
||||
let in_bounds = if x_start + TILE_SIZE < width {
|
||||
(in_offset + x_start)..(in_offset + x_start + TILE_SIZE)
|
||||
} else {
|
||||
(in_offset + x_start)..(in_offset + width)
|
||||
};
|
||||
let in_chunk = in_b.get(in_bounds).unwrap_hard();
|
||||
for (x, in_p) in in_chunk.iter().enumerate() {
|
||||
let new_x = (new_width - 1) - y;
|
||||
let new_y = x + x_start;
|
||||
*out_b.get_mut(new_y * new_width + new_x).unwrap_hard() = *in_p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn rotate_180(width: usize, height: usize) {
|
||||
let (in_b, out_b) = get_buffers(width, height);
|
||||
for (in_p, out_p) in in_b.iter().zip(out_b.iter_mut().rev()) {
|
||||
*out_p = *in_p;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn rotate_270(width: usize, height: usize) {
|
||||
let (in_b, out_b) = get_buffers(width, height);
|
||||
let new_width = height;
|
||||
let new_height = width;
|
||||
for y_start in (0..height).step_by(TILE_SIZE) {
|
||||
for x_start in (0..width).step_by(TILE_SIZE) {
|
||||
for y in y_start..(y_start + TILE_SIZE).min(height) {
|
||||
let in_offset = y * width;
|
||||
let in_bounds = if x_start + TILE_SIZE < width {
|
||||
(in_offset + x_start)..(in_offset + x_start + TILE_SIZE)
|
||||
} else {
|
||||
(in_offset + x_start)..(in_offset + width)
|
||||
};
|
||||
let in_chunk = in_b.get(in_bounds).unwrap_hard();
|
||||
for (x, in_p) in in_chunk.iter().enumerate() {
|
||||
let new_x = y;
|
||||
let new_y = new_height - 1 - (x_start + x);
|
||||
*out_b.get_mut(new_y * new_width + new_x).unwrap_hard() = *in_p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
fn rotate(width: usize, height: usize, rotate: usize) {
|
||||
match rotate {
|
||||
0 => rotate_0(width, height),
|
||||
90 => rotate_90(width, height),
|
||||
180 => rotate_180(width, height),
|
||||
270 => rotate_270(width, height),
|
||||
_ => std::process::abort(),
|
||||
}
|
||||
}
|
||||
BIN
codecs/rotate/rotate.wasm
Executable file
BIN
codecs/rotate/rotate.wasm
Executable file
Binary file not shown.
71
codecs/webp/build.sh
Normal file
71
codecs/webp/build.sh
Normal file
@@ -0,0 +1,71 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
export EM_CACHE="${PWD}/node_modules/.em_cache"
|
||||
export OPTIMIZE="-Os -flto --llvm-lto 1"
|
||||
export LDFLAGS="${OPTIMIZE}"
|
||||
export CFLAGS="${OPTIMIZE}"
|
||||
export CPPFLAGS="${OPTIMIZE}"
|
||||
apt-get update
|
||||
apt-get install -qqy autoconf libtool pkg-config
|
||||
|
||||
echo "============================================="
|
||||
echo "Compiling libwebp"
|
||||
echo "============================================="
|
||||
test -n "$SKIP_LIBWEBP" || (
|
||||
cd node_modules/libwebp
|
||||
autoreconf -iv
|
||||
emconfigure ./configure -C \
|
||||
--disable-libwebpdemux \
|
||||
--disable-wic \
|
||||
--disable-gif \
|
||||
--disable-tiff \
|
||||
--disable-jpeg \
|
||||
--disable-png \
|
||||
--disable-sdl \
|
||||
--disable-gl \
|
||||
--disable-threading \
|
||||
--disable-neon-rtcd \
|
||||
--disable-neon \
|
||||
--disable-sse2 \
|
||||
--disable-sse4.1
|
||||
emmake make -j`nproc`
|
||||
)
|
||||
echo "============================================="
|
||||
echo "Compiling wasm bindings"
|
||||
echo "============================================="
|
||||
(
|
||||
emcc \
|
||||
${OPTIMIZE} \
|
||||
--closure 1 \
|
||||
--bind \
|
||||
-s ALLOW_MEMORY_GROWTH=1 \
|
||||
-s MODULARIZE=1 \
|
||||
-s 'EXPORT_NAME="webp_dec"' \
|
||||
-I node_modules/libwebp \
|
||||
-o dec/webp_dec.js \
|
||||
dec/webp_dec.cpp \
|
||||
node_modules/libwebp/src/.libs/libwebp.a
|
||||
)
|
||||
(
|
||||
emcc \
|
||||
${OPTIMIZE} \
|
||||
--closure 1 \
|
||||
--bind \
|
||||
-s ALLOW_MEMORY_GROWTH=1 \
|
||||
-s MODULARIZE=1 \
|
||||
-s 'EXPORT_NAME="webp_enc"' \
|
||||
-I node_modules/libwebp \
|
||||
-o enc/webp_enc.js \
|
||||
enc/webp_enc.cpp \
|
||||
node_modules/libwebp/src/.libs/libwebp.a
|
||||
)
|
||||
echo "============================================="
|
||||
echo "Compiling wasm bindings done"
|
||||
echo "============================================="
|
||||
|
||||
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
||||
echo "Did you update your docker image?"
|
||||
echo "Run \`docker pull trzeci/emscripten-upstream\`"
|
||||
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
||||
22
codecs/webp/dec/README.md
Normal file
22
codecs/webp/dec/README.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# WebP decoder
|
||||
|
||||
- Source: <https://github.com/webmproject/libwebp>
|
||||
- Version: v1.0.2
|
||||
|
||||
## Example
|
||||
|
||||
See `example.html`
|
||||
|
||||
## API
|
||||
|
||||
### `int version()`
|
||||
|
||||
Returns the version of libwebp as a number. va.b.c is encoded as 0x0a0b0c
|
||||
|
||||
### `RawImage decode(std::string buffer)`
|
||||
|
||||
Decodes the given webp buffer into raw RGBA. `RawImage` is a class with 3 fields: `buffer`, `width`, and `height`.
|
||||
|
||||
### `void free_result()`
|
||||
|
||||
Frees the result created by `decode()`.
|
||||
24
codecs/webp/dec/example.html
Normal file
24
codecs/webp/dec/example.html
Normal file
@@ -0,0 +1,24 @@
|
||||
<!doctype html>
|
||||
<script src='webp_dec.js'></script>
|
||||
<script>
|
||||
const Module = webp_dec();
|
||||
|
||||
async function loadFile(src) {
|
||||
const resp = await fetch(src);
|
||||
return await resp.arrayBuffer();
|
||||
}
|
||||
|
||||
Module.onRuntimeInitialized = async _ => {
|
||||
console.log('Version:', Module.version().toString(16));
|
||||
const image = await loadFile('../../example.webp');
|
||||
const result = Module.decode(image);
|
||||
const imageData = new ImageData(new Uint8ClampedArray(result.buffer), result.width, result.height);
|
||||
Module.free_result();
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = result.width;
|
||||
canvas.height = result.height;
|
||||
document.body.appendChild(canvas);
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.putImageData(imageData, 0, 0);
|
||||
};
|
||||
</script>
|
||||
42
codecs/webp/dec/webp_dec.cpp
Normal file
42
codecs/webp/dec/webp_dec.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
#include <string>
|
||||
#include "emscripten/bind.h"
|
||||
#include "emscripten/val.h"
|
||||
#include "src/webp/decode.h"
|
||||
#include "src/webp/demux.h"
|
||||
|
||||
using namespace emscripten;
|
||||
|
||||
int version() {
|
||||
return WebPGetDecoderVersion();
|
||||
}
|
||||
|
||||
class RawImage {
|
||||
public:
|
||||
val buffer;
|
||||
int width;
|
||||
int height;
|
||||
|
||||
RawImage(val b, int w, int h) : buffer(b), width(w), height(h) {}
|
||||
};
|
||||
|
||||
uint8_t* last_result;
|
||||
RawImage decode(std::string buffer) {
|
||||
int width, height;
|
||||
last_result = WebPDecodeRGBA((const uint8_t*)buffer.c_str(), buffer.size(), &width, &height);
|
||||
return RawImage(val(typed_memory_view(width * height * 4, last_result)), width, height);
|
||||
}
|
||||
|
||||
void free_result() {
|
||||
free(last_result);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_BINDINGS(my_module) {
|
||||
class_<RawImage>("RawImage")
|
||||
.property("buffer", &RawImage::buffer)
|
||||
.property("width", &RawImage::width)
|
||||
.property("height", &RawImage::height);
|
||||
|
||||
function("decode", &decode);
|
||||
function("version", &version);
|
||||
function("free_result", &free_result);
|
||||
}
|
||||
13
codecs/webp/dec/webp_dec.d.ts
vendored
Normal file
13
codecs/webp/dec/webp_dec.d.ts
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
interface RawImage {
|
||||
buffer: Uint8Array;
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
interface WebPModule extends EmscriptenWasm.Module {
|
||||
decode(data: BufferSource): RawImage;
|
||||
free_result(): void;
|
||||
}
|
||||
|
||||
export default function(opts: EmscriptenWasm.ModuleOpts): WebPModule;
|
||||
|
||||
79
codecs/webp/dec/webp_dec.js
Normal file
79
codecs/webp/dec/webp_dec.js
Normal file
@@ -0,0 +1,79 @@
|
||||
|
||||
var webp_dec = (function() {
|
||||
var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined;
|
||||
if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename;
|
||||
return (
|
||||
function(webp_dec) {
|
||||
webp_dec = webp_dec || {};
|
||||
|
||||
var e;e||(e=typeof webp_dec !== 'undefined' ? webp_dec : {});var r={},w;for(w in e)e.hasOwnProperty(w)&&(r[w]=e[w]);var aa=!1,z=!1,ba=!1,ca=!1;aa="object"===typeof window;z="function"===typeof importScripts;ba="object"===typeof process&&"object"===typeof process.versions&&"string"===typeof process.versions.node;ca=!aa&&!ba&&!z;var A="",da,B,ea,ha;
|
||||
if(ba)A=z?require("path").dirname(A)+"/":__dirname+"/",da=function(a,b){ea||(ea=require("fs"));ha||(ha=require("path"));a=ha.normalize(a);return ea.readFileSync(a,b?null:"utf8")},B=function(a){a=da(a,!0);a.buffer||(a=new Uint8Array(a));a.buffer||D("Assertion failed: undefined");return a},1<process.argv.length&&process.argv[1].replace(/\\/g,"/"),process.argv.slice(2),process.on("uncaughtException",function(a){throw a;}),process.on("unhandledRejection",D),e.inspect=function(){return"[Emscripten Module object]"};
|
||||
else if(ca)"undefined"!=typeof read&&(da=function(a){return read(a)}),B=function(a){if("function"===typeof readbuffer)return new Uint8Array(readbuffer(a));a=read(a,"binary");"object"===typeof a||D("Assertion failed: undefined");return a},"undefined"!==typeof print&&("undefined"===typeof console&&(console={}),console.log=print,console.warn=console.error="undefined"!==typeof printErr?printErr:print);else if(aa||z)z?A=self.location.href:document.currentScript&&(A=document.currentScript.src),_scriptDir&&
|
||||
(A=_scriptDir),0!==A.indexOf("blob:")?A=A.substr(0,A.lastIndexOf("/")+1):A="",da=function(a){var b=new XMLHttpRequest;b.open("GET",a,!1);b.send(null);return b.responseText},z&&(B=function(a){var b=new XMLHttpRequest;b.open("GET",a,!1);b.responseType="arraybuffer";b.send(null);return new Uint8Array(b.response)});var ia=e.print||console.log.bind(console),E=e.printErr||console.warn.bind(console);for(w in r)r.hasOwnProperty(w)&&(e[w]=r[w]);r=null;var F;e.wasmBinary&&(F=e.wasmBinary);var noExitRuntime;
|
||||
e.noExitRuntime&&(noExitRuntime=e.noExitRuntime);"object"!==typeof WebAssembly&&E("no native wasm support detected");var G,ja=new WebAssembly.Table({initial:138,maximum:138,element:"anyfunc"}),ka=!1,la="undefined"!==typeof TextDecoder?new TextDecoder("utf8"):void 0;
|
||||
function ma(a,b,c){var d=H;if(0<c){c=b+c-1;for(var f=0;f<a.length;++f){var g=a.charCodeAt(f);if(55296<=g&&57343>=g){var q=a.charCodeAt(++f);g=65536+((g&1023)<<10)|q&1023}if(127>=g){if(b>=c)break;d[b++]=g}else{if(2047>=g){if(b+1>=c)break;d[b++]=192|g>>6}else{if(65535>=g){if(b+2>=c)break;d[b++]=224|g>>12}else{if(b+3>=c)break;d[b++]=240|g>>18;d[b++]=128|g>>12&63}d[b++]=128|g>>6&63}d[b++]=128|g&63}}d[b]=0}}var na="undefined"!==typeof TextDecoder?new TextDecoder("utf-16le"):void 0;
|
||||
function oa(a){var b;for(b=a>>1;I[b];)++b;b<<=1;if(32<b-a&&na)return na.decode(H.subarray(a,b));b=0;for(var c="";;){var d=I[a+2*b>>1];if(0==d)return c;++b;c+=String.fromCharCode(d)}}function pa(a,b,c){void 0===c&&(c=2147483647);if(2>c)return 0;c-=2;var d=b;c=c<2*a.length?c/2:a.length;for(var f=0;f<c;++f)I[b>>1]=a.charCodeAt(f),b+=2;I[b>>1]=0;return b-d}function qa(a){return 2*a.length}
|
||||
function ra(a){for(var b=0,c="";;){var d=J[a+4*b>>2];if(0==d)return c;++b;65536<=d?(d-=65536,c+=String.fromCharCode(55296|d>>10,56320|d&1023)):c+=String.fromCharCode(d)}}function sa(a,b,c){void 0===c&&(c=2147483647);if(4>c)return 0;var d=b;c=d+c-4;for(var f=0;f<a.length;++f){var g=a.charCodeAt(f);if(55296<=g&&57343>=g){var q=a.charCodeAt(++f);g=65536+((g&1023)<<10)|q&1023}J[b>>2]=g;b+=4;if(b+4>c)break}J[b>>2]=0;return b-d}
|
||||
function ta(a){for(var b=0,c=0;c<a.length;++c){var d=a.charCodeAt(c);55296<=d&&57343>=d&&++c;b+=4}return b}var K,ua,H,I,va,J,L,wa,xa;function ya(a){K=a;e.HEAP8=ua=new Int8Array(a);e.HEAP16=I=new Int16Array(a);e.HEAP32=J=new Int32Array(a);e.HEAPU8=H=new Uint8Array(a);e.HEAPU16=va=new Uint16Array(a);e.HEAPU32=L=new Uint32Array(a);e.HEAPF32=wa=new Float32Array(a);e.HEAPF64=xa=new Float64Array(a)}var za=e.INITIAL_MEMORY||16777216;e.wasmMemory?G=e.wasmMemory:G=new WebAssembly.Memory({initial:za/65536});
|
||||
G&&(K=G.buffer);za=K.byteLength;ya(K);J[3336]=5256384;function Aa(a){for(;0<a.length;){var b=a.shift();if("function"==typeof b)b();else{var c=b.ka;"number"===typeof c?void 0===b.ba?e.dynCall_v(c):e.dynCall_vi(c,b.ba):c(void 0===b.ba?null:b.ba)}}}var Ba=[],Ca=[],Da=[],Ea=[];function Fa(){var a=e.preRun.shift();Ba.unshift(a)}var M=0,Ga=null,N=null;e.preloadedImages={};e.preloadedAudios={};
|
||||
function D(a){if(e.onAbort)e.onAbort(a);ia(a);E(a);ka=!0;throw new WebAssembly.RuntimeError("abort("+a+"). Build with -s ASSERTIONS=1 for more info.");}function Ha(){var a=O;return String.prototype.startsWith?a.startsWith("data:application/octet-stream;base64,"):0===a.indexOf("data:application/octet-stream;base64,")}var O="webp_dec.wasm";if(!Ha()){var Ia=O;O=e.locateFile?e.locateFile(Ia,A):A+Ia}
|
||||
function Ja(){try{if(F)return new Uint8Array(F);if(B)return B(O);throw"both async and sync fetching of the wasm failed";}catch(a){D(a)}}function Ka(){return F||!aa&&!z||"function"!==typeof fetch?new Promise(function(a){a(Ja())}):fetch(O,{credentials:"same-origin"}).then(function(a){if(!a.ok)throw"failed to load wasm binary file at '"+O+"'";return a.arrayBuffer()}).catch(function(){return Ja()})}Ca.push({ka:function(){La()}});function Ma(){return 0<Ma.X}
|
||||
function Na(a){switch(a){case 1:return 0;case 2:return 1;case 4:return 2;case 8:return 3;default:throw new TypeError("Unknown type size: "+a);}}var Oa=void 0;function P(a){for(var b="";H[a];)b+=Oa[H[a++]];return b}var Q={},R={},Pa={};function Qa(a){if(void 0===a)return"_unknown";a=a.replace(/[^a-zA-Z0-9_]/g,"$");var b=a.charCodeAt(0);return 48<=b&&57>=b?"_"+a:a}
|
||||
function Ra(a,b){a=Qa(a);return(new Function("body","return function "+a+'() {\n "use strict"; return body.apply(this, arguments);\n};\n'))(b)}function Sa(a){var b=Error,c=Ra(a,function(d){this.name=a;this.message=d;d=Error(d).stack;void 0!==d&&(this.stack=this.toString()+"\n"+d.replace(/^Error(:[^\n]*)?\n/,""))});c.prototype=Object.create(b.prototype);c.prototype.constructor=c;c.prototype.toString=function(){return void 0===this.message?this.name:this.name+": "+this.message};return c}
|
||||
var Ta=void 0;function S(a){throw new Ta(a);}var Ua=void 0;function Va(a){throw new Ua(a);}function Wa(a,b,c){function d(h){h=c(h);h.length!==a.length&&Va("Mismatched type converter count");for(var l=0;l<a.length;++l)T(a[l],h[l])}a.forEach(function(h){Pa[h]=b});var f=Array(b.length),g=[],q=0;b.forEach(function(h,l){R.hasOwnProperty(h)?f[l]=R[h]:(g.push(h),Q.hasOwnProperty(h)||(Q[h]=[]),Q[h].push(function(){f[l]=R[h];++q;q===g.length&&d(f)}))});0===g.length&&d(f)}
|
||||
function T(a,b,c){c=c||{};if(!("argPackAdvance"in b))throw new TypeError("registerType registeredInstance requires argPackAdvance");var d=b.name;a||S('type "'+d+'" must have a positive integer typeid pointer');if(R.hasOwnProperty(a)){if(c.na)return;S("Cannot register type '"+d+"' twice")}R[a]=b;delete Pa[a];Q.hasOwnProperty(a)&&(b=Q[a],delete Q[a],b.forEach(function(f){f()}))}function Xa(a){return{count:a.count,W:a.W,Y:a.Y,L:a.L,N:a.N,O:a.O,P:a.P}}
|
||||
function Ya(a){S(a.K.N.M.name+" instance already deleted")}var Za=!1;function $a(){}function ab(a){--a.count.value;0===a.count.value&&(a.O?a.P.V(a.O):a.N.M.V(a.L))}function bb(a){if("undefined"===typeof FinalizationGroup)return bb=function(b){return b},a;Za=new FinalizationGroup(function(b){for(var c=b.next();!c.done;c=b.next())c=c.value,c.L?ab(c):console.warn("object already deleted: "+c.L)});bb=function(b){Za.register(b,b.K,b.K);return b};$a=function(b){Za.unregister(b.K)};return bb(a)}
|
||||
var cb=void 0,db=[];function eb(){for(;db.length;){var a=db.pop();a.K.W=!1;a["delete"]()}}function U(){}var fb={};function gb(a,b){var c=e;if(void 0===c[a].S){var d=c[a];c[a]=function(){c[a].S.hasOwnProperty(arguments.length)||S("Function '"+b+"' called with an invalid number of arguments ("+arguments.length+") - expects one of ("+c[a].S+")!");return c[a].S[arguments.length].apply(this,arguments)};c[a].S=[];c[a].S[d.ha]=d}}
|
||||
function hb(a,b,c){e.hasOwnProperty(a)?((void 0===c||void 0!==e[a].S&&void 0!==e[a].S[c])&&S("Cannot register public name '"+a+"' twice"),gb(a,a),e.hasOwnProperty(c)&&S("Cannot register multiple overloads of a function with the same number of arguments ("+c+")!"),e[a].S[c]=b):(e[a]=b,void 0!==c&&(e[a].ta=c))}function ib(a,b,c,d,f,g,q,h){this.name=a;this.constructor=b;this.U=c;this.V=d;this.R=f;this.la=g;this.Z=q;this.ja=h}
|
||||
function jb(a,b,c){for(;b!==c;)b.Z||S("Expected null or instance of "+c.name+", got an instance of "+b.name),a=b.Z(a),b=b.R;return a}function kb(a,b){if(null===b)return this.da&&S("null is not a valid "+this.name),0;b.K||S('Cannot pass "'+V(b)+'" as a '+this.name);b.K.L||S("Cannot pass deleted object as a pointer of type "+this.name);return jb(b.K.L,b.K.N.M,this.M)}
|
||||
function lb(a,b){if(null===b){this.da&&S("null is not a valid "+this.name);if(this.aa){var c=this.pa();null!==a&&a.push(this.V,c);return c}return 0}b.K||S('Cannot pass "'+V(b)+'" as a '+this.name);b.K.L||S("Cannot pass deleted object as a pointer of type "+this.name);!this.$&&b.K.N.$&&S("Cannot convert argument of type "+(b.K.P?b.K.P.name:b.K.N.name)+" to parameter type "+this.name);c=jb(b.K.L,b.K.N.M,this.M);if(this.aa)switch(void 0===b.K.O&&S("Passing raw pointer to smart pointer is illegal"),this.ra){case 0:b.K.P===
|
||||
this?c=b.K.O:S("Cannot convert argument of type "+(b.K.P?b.K.P.name:b.K.N.name)+" to parameter type "+this.name);break;case 1:c=b.K.O;break;case 2:if(b.K.P===this)c=b.K.O;else{var d=b.clone();c=this.qa(c,mb(function(){d["delete"]()}));null!==a&&a.push(this.V,c)}break;default:S("Unsupporting sharing policy")}return c}
|
||||
function nb(a,b){if(null===b)return this.da&&S("null is not a valid "+this.name),0;b.K||S('Cannot pass "'+V(b)+'" as a '+this.name);b.K.L||S("Cannot pass deleted object as a pointer of type "+this.name);b.K.N.$&&S("Cannot convert argument of type "+b.K.N.name+" to parameter type "+this.name);return jb(b.K.L,b.K.N.M,this.M)}function pb(a){return this.fromWireType(L[a>>2])}function qb(a,b,c){if(b===c)return a;if(void 0===c.R)return null;a=qb(a,b,c.R);return null===a?null:c.ja(a)}var rb={};
|
||||
function sb(a,b){for(void 0===b&&S("ptr should not be undefined");a.R;)b=a.Z(b),a=a.R;return rb[b]}function tb(a,b){b.N&&b.L||Va("makeClassHandle requires ptr and ptrType");!!b.P!==!!b.O&&Va("Both smartPtrType and smartPtr must be specified");b.count={value:1};return bb(Object.create(a,{K:{value:b}}))}function W(a,b,c,d){this.name=a;this.M=b;this.da=c;this.$=d;this.aa=!1;this.V=this.qa=this.pa=this.ga=this.ra=this.oa=void 0;void 0!==b.R?this.toWireType=lb:(this.toWireType=d?kb:nb,this.T=null)}
|
||||
function ub(a,b,c){e.hasOwnProperty(a)||Va("Replacing nonexistant public symbol");void 0!==e[a].S&&void 0!==c?e[a].S[c]=b:(e[a]=b,e[a].ha=c)}
|
||||
function X(a,b){a=P(a);var c=e["dynCall_"+a];for(var d=[],f=1;f<a.length;++f)d.push("a"+f);f="return function dynCall_"+(a+"_"+b)+"("+d.join(", ")+") {\n";f+=" return dynCall(rawFunction"+(d.length?", ":"")+d.join(", ")+");\n";c=(new Function("dynCall","rawFunction",f+"};\n"))(c,b);"function"!==typeof c&&S("unknown function pointer with signature "+a+": "+b);return c}var vb=void 0;function wb(a){a=xb(a);var b=P(a);Y(a);return b}
|
||||
function yb(a,b){function c(g){f[g]||R[g]||(Pa[g]?Pa[g].forEach(c):(d.push(g),f[g]=!0))}var d=[],f={};b.forEach(c);throw new vb(a+": "+d.map(wb).join([", "]));}function zb(a){for(;a.length;){var b=a.pop();a.pop()(b)}}function Ab(a,b,c){a instanceof Object||S(c+' with invalid "this": '+a);a instanceof b.M.constructor||S(c+' incompatible with "this" of type '+a.constructor.name);a.K.L||S("cannot call emscripten binding method "+c+" on deleted object");return jb(a.K.L,a.K.N.M,b.M)}
|
||||
var Bb=[],Z=[{},{value:void 0},{value:null},{value:!0},{value:!1}];function Cb(a){4<a&&0===--Z[a].ea&&(Z[a]=void 0,Bb.push(a))}function mb(a){switch(a){case void 0:return 1;case null:return 2;case !0:return 3;case !1:return 4;default:var b=Bb.length?Bb.pop():Z.length;Z[b]={ea:1,value:a};return b}}function V(a){if(null===a)return"null";var b=typeof a;return"object"===b||"array"===b||"function"===b?a.toString():""+a}
|
||||
function Db(a,b){switch(b){case 2:return function(c){return this.fromWireType(wa[c>>2])};case 3:return function(c){return this.fromWireType(xa[c>>3])};default:throw new TypeError("Unknown float type: "+a);}}function Eb(a){var b=Function;if(!(b instanceof Function))throw new TypeError("new_ called with constructor type "+typeof b+" which is not a function");var c=Ra(b.name||"unknownFunctionName",function(){});c.prototype=b.prototype;c=new c;a=b.apply(c,a);return a instanceof Object?a:c}
|
||||
function Fb(a,b){for(var c=[],d=0;d<a;d++)c.push(J[(b>>2)+d]);return c}function Gb(a,b,c){switch(b){case 0:return c?function(d){return ua[d]}:function(d){return H[d]};case 1:return c?function(d){return I[d>>1]}:function(d){return va[d>>1]};case 2:return c?function(d){return J[d>>2]}:function(d){return L[d>>2]};default:throw new TypeError("Unknown integer type: "+a);}}for(var Hb=Array(256),Ib=0;256>Ib;++Ib)Hb[Ib]=String.fromCharCode(Ib);Oa=Hb;Ta=e.BindingError=Sa("BindingError");
|
||||
Ua=e.InternalError=Sa("InternalError");U.prototype.isAliasOf=function(a){if(!(this instanceof U&&a instanceof U))return!1;var b=this.K.N.M,c=this.K.L,d=a.K.N.M;for(a=a.K.L;b.R;)c=b.Z(c),b=b.R;for(;d.R;)a=d.Z(a),d=d.R;return b===d&&c===a};U.prototype.clone=function(){this.K.L||Ya(this);if(this.K.Y)return this.K.count.value+=1,this;var a=bb(Object.create(Object.getPrototypeOf(this),{K:{value:Xa(this.K)}}));a.K.count.value+=1;a.K.W=!1;return a};
|
||||
U.prototype["delete"]=function(){this.K.L||Ya(this);this.K.W&&!this.K.Y&&S("Object already scheduled for deletion");$a(this);ab(this.K);this.K.Y||(this.K.O=void 0,this.K.L=void 0)};U.prototype.isDeleted=function(){return!this.K.L};U.prototype.deleteLater=function(){this.K.L||Ya(this);this.K.W&&!this.K.Y&&S("Object already scheduled for deletion");db.push(this);1===db.length&&cb&&cb(eb);this.K.W=!0;return this};W.prototype.ma=function(a){this.ga&&(a=this.ga(a));return a};
|
||||
W.prototype.fa=function(a){this.V&&this.V(a)};W.prototype.argPackAdvance=8;W.prototype.readValueFromPointer=pb;W.prototype.deleteObject=function(a){if(null!==a)a["delete"]()};
|
||||
W.prototype.fromWireType=function(a){function b(){return this.aa?tb(this.M.U,{N:this.oa,L:c,P:this,O:a}):tb(this.M.U,{N:this,L:a})}var c=this.ma(a);if(!c)return this.fa(a),null;var d=sb(this.M,c);if(void 0!==d){if(0===d.K.count.value)return d.K.L=c,d.K.O=a,d.clone();d=d.clone();this.fa(a);return d}d=this.M.la(c);d=fb[d];if(!d)return b.call(this);d=this.$?d.ia:d.pointerType;var f=qb(c,this.M,d.M);return null===f?b.call(this):this.aa?tb(d.M.U,{N:d,L:f,P:this,O:a}):tb(d.M.U,{N:d,L:f})};
|
||||
e.getInheritedInstanceCount=function(){return Object.keys(rb).length};e.getLiveInheritedInstances=function(){var a=[],b;for(b in rb)rb.hasOwnProperty(b)&&a.push(rb[b]);return a};e.flushPendingDeletes=eb;e.setDelayFunction=function(a){cb=a;db.length&&cb&&cb(eb)};vb=e.UnboundTypeError=Sa("UnboundTypeError");e.count_emval_handles=function(){for(var a=0,b=5;b<Z.length;++b)void 0!==Z[b]&&++a;return a};e.get_first_emval=function(){for(var a=5;a<Z.length;++a)if(void 0!==Z[a])return Z[a];return null};
|
||||
var Kb={n:function(a){return Jb(a)},m:function(a){"uncaught_exception"in Ma?Ma.X++:Ma.X=1;throw a;},k:function(a,b,c,d,f){var g=Na(c);b=P(b);T(a,{name:b,fromWireType:function(q){return!!q},toWireType:function(q,h){return h?d:f},argPackAdvance:8,readValueFromPointer:function(q){if(1===c)var h=ua;else if(2===c)h=I;else if(4===c)h=J;else throw new TypeError("Unknown boolean type size: "+b);return this.fromWireType(h[q>>g])},T:null})},o:function(a,b,c,d,f,g,q,h,l,m,k,p,t){k=P(k);g=X(f,g);h&&(h=X(q,h));
|
||||
m&&(m=X(l,m));t=X(p,t);var v=Qa(k);hb(v,function(){yb("Cannot construct "+k+" due to unbound types",[d])});Wa([a,b,c],d?[d]:[],function(n){n=n[0];if(d){var u=n.M;var x=u.U}else x=U.prototype;n=Ra(v,function(){if(Object.getPrototypeOf(this)!==y)throw new Ta("Use 'new' to construct "+k);if(void 0===C.X)throw new Ta(k+" has no accessible constructor");var ob=C.X[arguments.length];if(void 0===ob)throw new Ta("Tried to invoke ctor of "+k+" with invalid number of parameters ("+arguments.length+") - expected ("+
|
||||
Object.keys(C.X).toString()+") parameters instead!");return ob.apply(this,arguments)});var y=Object.create(x,{constructor:{value:n}});n.prototype=y;var C=new ib(k,n,y,t,u,g,h,m);u=new W(k,C,!0,!1);x=new W(k+"*",C,!1,!1);var fa=new W(k+" const*",C,!1,!0);fb[a]={pointerType:x,ia:fa};ub(v,n);return[u,x,fa]})},e:function(a,b,c,d,f,g,q,h,l,m){b=P(b);f=X(d,f);Wa([],[a],function(k){k=k[0];var p=k.name+"."+b,t={get:function(){yb("Cannot access "+p+" due to unbound types",[c,q])},enumerable:!0,configurable:!0};
|
||||
l?t.set=function(){yb("Cannot access "+p+" due to unbound types",[c,q])}:t.set=function(){S(p+" is a read-only property")};Object.defineProperty(k.M.U,b,t);Wa([],l?[c,q]:[c],function(v){var n=v[0],u={get:function(){var y=Ab(this,k,p+" getter");return n.fromWireType(f(g,y))},enumerable:!0};if(l){l=X(h,l);var x=v[1];u.set=function(y){var C=Ab(this,k,p+" setter"),fa=[];l(m,C,x.toWireType(fa,y));zb(fa)}}Object.defineProperty(k.M.U,b,u);return[]});return[]})},q:function(a,b){b=P(b);T(a,{name:b,fromWireType:function(c){var d=
|
||||
Z[c].value;Cb(c);return d},toWireType:function(c,d){return mb(d)},argPackAdvance:8,readValueFromPointer:pb,T:null})},h:function(a,b,c){c=Na(c);b=P(b);T(a,{name:b,fromWireType:function(d){return d},toWireType:function(d,f){if("number"!==typeof f&&"boolean"!==typeof f)throw new TypeError('Cannot convert "'+V(f)+'" to '+this.name);return f},argPackAdvance:8,readValueFromPointer:Db(b,c),T:null})},d:function(a,b,c,d,f,g){var q=Fb(b,c);a=P(a);f=X(d,f);hb(a,function(){yb("Cannot call "+a+" due to unbound types",
|
||||
q)},b-1);Wa([],q,function(h){var l=[h[0],null].concat(h.slice(1)),m=h=a,k=f,p=l.length;2>p&&S("argTypes array size mismatch! Must at least get return value and 'this' types!");for(var t=null!==l[1]&&!1,v=!1,n=1;n<l.length;++n)if(null!==l[n]&&void 0===l[n].T){v=!0;break}var u="void"!==l[0].name,x="",y="";for(n=0;n<p-2;++n)x+=(0!==n?", ":"")+"arg"+n,y+=(0!==n?", ":"")+"arg"+n+"Wired";m="return function "+Qa(m)+"("+x+") {\nif (arguments.length !== "+(p-2)+") {\nthrowBindingError('function "+m+" called with ' + arguments.length + ' arguments, expected "+
|
||||
(p-2)+" args!');\n}\n";v&&(m+="var destructors = [];\n");var C=v?"destructors":"null";x="throwBindingError invoker fn runDestructors retType classParam".split(" ");k=[S,k,g,zb,l[0],l[1]];t&&(m+="var thisWired = classParam.toWireType("+C+", this);\n");for(n=0;n<p-2;++n)m+="var arg"+n+"Wired = argType"+n+".toWireType("+C+", arg"+n+"); // "+l[n+2].name+"\n",x.push("argType"+n),k.push(l[n+2]);t&&(y="thisWired"+(0<y.length?", ":"")+y);m+=(u?"var rv = ":"")+"invoker(fn"+(0<y.length?", ":"")+y+");\n";if(v)m+=
|
||||
"runDestructors(destructors);\n";else for(n=t?1:2;n<l.length;++n)p=1===n?"thisWired":"arg"+(n-2)+"Wired",null!==l[n].T&&(m+=p+"_dtor("+p+"); // "+l[n].name+"\n",x.push(p+"_dtor"),k.push(l[n].T));u&&(m+="var ret = retType.fromWireType(rv);\nreturn ret;\n");x.push(m+"}\n");l=Eb(x).apply(null,k);ub(h,l,b-1);return[]})},b:function(a,b,c,d,f){function g(m){return m}b=P(b);-1===f&&(f=4294967295);var q=Na(c);if(0===d){var h=32-8*c;g=function(m){return m<<h>>>h}}var l=-1!=b.indexOf("unsigned");T(a,{name:b,
|
||||
fromWireType:g,toWireType:function(m,k){if("number"!==typeof k&&"boolean"!==typeof k)throw new TypeError('Cannot convert "'+V(k)+'" to '+this.name);if(k<d||k>f)throw new TypeError('Passing a number "'+V(k)+'" from JS side to C/C++ side to an argument of type "'+b+'", which is outside the valid range ['+d+", "+f+"]!");return l?k>>>0:k|0},argPackAdvance:8,readValueFromPointer:Gb(b,q,0!==d),T:null})},a:function(a,b,c){function d(g){g>>=2;var q=L;return new f(K,q[g+1],q[g])}var f=[Int8Array,Uint8Array,
|
||||
Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array][b];c=P(c);T(a,{name:c,fromWireType:d,argPackAdvance:8,readValueFromPointer:d},{na:!0})},i:function(a,b){b=P(b);var c="std::string"===b;T(a,{name:b,fromWireType:function(d){var f=L[d>>2];if(c){var g=H[d+4+f],q=0;0!=g&&(q=g,H[d+4+f]=0);var h=d+4;for(g=0;g<=f;++g){var l=d+4+g;if(0==H[l]){if(h){for(var m=H,k=h+NaN,p=h;m[p]&&!(p>=k);)++p;if(16<p-h&&m.subarray&&la)h=la.decode(m.subarray(h,p));else{for(k="";h<p;){var t=m[h++];if(t&
|
||||
128){var v=m[h++]&63;if(192==(t&224))k+=String.fromCharCode((t&31)<<6|v);else{var n=m[h++]&63;t=224==(t&240)?(t&15)<<12|v<<6|n:(t&7)<<18|v<<12|n<<6|m[h++]&63;65536>t?k+=String.fromCharCode(t):(t-=65536,k+=String.fromCharCode(55296|t>>10,56320|t&1023))}}else k+=String.fromCharCode(t)}h=k}}else h="";if(void 0===u)var u=h;else u+=String.fromCharCode(0),u+=h;h=l+1}}0!=q&&(H[d+4+f]=q)}else{u=Array(f);for(g=0;g<f;++g)u[g]=String.fromCharCode(H[d+4+g]);u=u.join("")}Y(d);return u},toWireType:function(d,f){f instanceof
|
||||
ArrayBuffer&&(f=new Uint8Array(f));var g="string"===typeof f;g||f instanceof Uint8Array||f instanceof Uint8ClampedArray||f instanceof Int8Array||S("Cannot pass non-string to std::string");var q=(c&&g?function(){for(var m=0,k=0;k<f.length;++k){var p=f.charCodeAt(k);55296<=p&&57343>=p&&(p=65536+((p&1023)<<10)|f.charCodeAt(++k)&1023);127>=p?++m:m=2047>=p?m+2:65535>=p?m+3:m+4}return m}:function(){return f.length})(),h=Jb(4+q+1);L[h>>2]=q;if(c&&g)ma(f,h+4,q+1);else if(g)for(g=0;g<q;++g){var l=f.charCodeAt(g);
|
||||
255<l&&(Y(h),S("String has UTF-16 code units that do not fit in 8 bits"));H[h+4+g]=l}else for(g=0;g<q;++g)H[h+4+g]=f[g];null!==d&&d.push(Y,h);return h},argPackAdvance:8,readValueFromPointer:pb,T:function(d){Y(d)}})},f:function(a,b,c){c=P(c);if(2===b){var d=oa;var f=pa;var g=qa;var q=function(){return va};var h=1}else 4===b&&(d=ra,f=sa,g=ta,q=function(){return L},h=2);T(a,{name:c,fromWireType:function(l){var m=L[l>>2],k=q(),p=k[l+4+m*b>>h],t=0;0!=p&&(t=p,k[l+4+m*b>>h]=0);var v=l+4;for(p=0;p<=m;++p){var n=
|
||||
l+4+p*b;if(0==k[n>>h]){v=d(v);if(void 0===u)var u=v;else u+=String.fromCharCode(0),u+=v;v=n+b}}0!=t&&(k[l+4+m*b>>h]=t);Y(l);return u},toWireType:function(l,m){"string"!==typeof m&&S("Cannot pass non-string to C++ string type "+c);var k=g(m),p=Jb(4+k+b);L[p>>2]=k>>h;f(m,p+4,k+b);null!==l&&l.push(Y,p);return p},argPackAdvance:8,readValueFromPointer:pb,T:function(l){Y(l)}})},l:function(a,b){b=P(b);T(a,{sa:!0,name:b,argPackAdvance:0,fromWireType:function(){},toWireType:function(){}})},g:Cb,r:function(a){4<
|
||||
a&&(Z[a].ea+=1)},j:function(a,b){var c=R[a];void 0===c&&S("_emval_take_value has unknown type "+wb(a));a=c.readValueFromPointer(b);return mb(a)},p:function(a,b,c){H.copyWithin(a,b,b+c)},c:function(a){var b=H.length;if(2147418112<a)return!1;for(var c=1;4>=c;c*=2){var d=b*(1+.2/c);d=Math.min(d,a+100663296);d=Math.max(16777216,a,d);0<d%65536&&(d+=65536-d%65536);a:{try{G.grow(Math.min(2147418112,d)-K.byteLength+65535>>16);ya(G.buffer);var f=1;break a}catch(g){}f=void 0}if(f)return!0}return!1},memory:G,
|
||||
table:ja},Lb=function(){function a(f){e.asm=f.exports;M--;e.monitorRunDependencies&&e.monitorRunDependencies(M);0==M&&(null!==Ga&&(clearInterval(Ga),Ga=null),N&&(f=N,N=null,f()))}function b(f){a(f.instance)}function c(f){return Ka().then(function(g){return WebAssembly.instantiate(g,d)}).then(f,function(g){E("failed to asynchronously prepare wasm: "+g);D(g)})}var d={a:Kb};M++;e.monitorRunDependencies&&e.monitorRunDependencies(M);if(e.instantiateWasm)try{return e.instantiateWasm(d,a)}catch(f){return E("Module.instantiateWasm callback failed with error: "+
|
||||
f),!1}(function(){if(F||"function"!==typeof WebAssembly.instantiateStreaming||Ha()||"function"!==typeof fetch)return c(b);fetch(O,{credentials:"same-origin"}).then(function(f){return WebAssembly.instantiateStreaming(f,d).then(b,function(g){E("wasm streaming compile failed: "+g);E("falling back to ArrayBuffer instantiation");c(b)})})})();return{}}();e.asm=Lb;
|
||||
var La=e.___wasm_call_ctors=function(){return(La=e.___wasm_call_ctors=e.asm.s).apply(null,arguments)},Y=e._free=function(){return(Y=e._free=e.asm.t).apply(null,arguments)},Jb=e._malloc=function(){return(Jb=e._malloc=e.asm.u).apply(null,arguments)},xb=e.___getTypeName=function(){return(xb=e.___getTypeName=e.asm.v).apply(null,arguments)};e.___embind_register_native_and_builtin_types=function(){return(e.___embind_register_native_and_builtin_types=e.asm.w).apply(null,arguments)};
|
||||
e.dynCall_ii=function(){return(e.dynCall_ii=e.asm.x).apply(null,arguments)};e.dynCall_vi=function(){return(e.dynCall_vi=e.asm.y).apply(null,arguments)};e.dynCall_iii=function(){return(e.dynCall_iii=e.asm.z).apply(null,arguments)};e.dynCall_viii=function(){return(e.dynCall_viii=e.asm.A).apply(null,arguments)};e.dynCall_vii=function(){return(e.dynCall_vii=e.asm.B).apply(null,arguments)};e.dynCall_i=function(){return(e.dynCall_i=e.asm.C).apply(null,arguments)};
|
||||
e.dynCall_v=function(){return(e.dynCall_v=e.asm.D).apply(null,arguments)};e.dynCall_iiii=function(){return(e.dynCall_iiii=e.asm.E).apply(null,arguments)};e.dynCall_iiiiiii=function(){return(e.dynCall_iiiiiii=e.asm.F).apply(null,arguments)};e.dynCall_viiii=function(){return(e.dynCall_viiii=e.asm.G).apply(null,arguments)};e.dynCall_viiiii=function(){return(e.dynCall_viiiii=e.asm.H).apply(null,arguments)};e.dynCall_viiiiiiiii=function(){return(e.dynCall_viiiiiiiii=e.asm.I).apply(null,arguments)};
|
||||
e.dynCall_viiiiii=function(){return(e.dynCall_viiiiii=e.asm.J).apply(null,arguments)};e.asm=Lb;var Mb;e.then=function(a){if(Mb)a(e);else{var b=e.onRuntimeInitialized;e.onRuntimeInitialized=function(){b&&b();a(e)}}return e};N=function Nb(){Mb||Ob();Mb||(N=Nb)};
|
||||
function Ob(){function a(){if(!Mb&&(Mb=!0,e.calledRun=!0,!ka)){Aa(Ca);Aa(Da);if(e.onRuntimeInitialized)e.onRuntimeInitialized();if(e.postRun)for("function"==typeof e.postRun&&(e.postRun=[e.postRun]);e.postRun.length;){var b=e.postRun.shift();Ea.unshift(b)}Aa(Ea)}}if(!(0<M)){if(e.preRun)for("function"==typeof e.preRun&&(e.preRun=[e.preRun]);e.preRun.length;)Fa();Aa(Ba);0<M||(e.setStatus?(e.setStatus("Running..."),setTimeout(function(){setTimeout(function(){e.setStatus("")},1);a()},1)):a())}}
|
||||
e.run=Ob;if(e.preInit)for("function"==typeof e.preInit&&(e.preInit=[e.preInit]);0<e.preInit.length;)e.preInit.pop()();noExitRuntime=!0;Ob();
|
||||
|
||||
|
||||
return webp_dec
|
||||
}
|
||||
);
|
||||
})();
|
||||
if (typeof exports === 'object' && typeof module === 'object')
|
||||
module.exports = webp_dec;
|
||||
else if (typeof define === 'function' && define['amd'])
|
||||
define([], function() { return webp_dec; });
|
||||
else if (typeof exports === 'object')
|
||||
exports["webp_dec"] = webp_dec;
|
||||
|
||||
BIN
codecs/webp/dec/webp_dec.wasm
Normal file
BIN
codecs/webp/dec/webp_dec.wasm
Normal file
Binary file not shown.
26
codecs/webp/enc/README.md
Normal file
26
codecs/webp/enc/README.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# WebP encoder
|
||||
|
||||
- Source: <https://github.com/webmproject/libwebp>
|
||||
- Version: v1.0.2
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Docker
|
||||
|
||||
## Example
|
||||
|
||||
See `example.html`
|
||||
|
||||
## API
|
||||
|
||||
### `int version()`
|
||||
|
||||
Returns the version of libwebp as a number. va.b.c is encoded as 0x0a0b0c
|
||||
|
||||
### `UInt8Array encode(uint8_t* image_buffer, int image_width, int image_height, WebPConfig config)`
|
||||
|
||||
Encodes the given image with given dimension to WebP.
|
||||
|
||||
### `void free_result()`
|
||||
|
||||
Frees the last result created by `encode()`.
|
||||
62
codecs/webp/enc/example.html
Normal file
62
codecs/webp/enc/example.html
Normal file
@@ -0,0 +1,62 @@
|
||||
<!doctype html>
|
||||
<script src='webp_enc.js'></script>
|
||||
<script>
|
||||
const module = webp_enc();
|
||||
|
||||
async function loadImage(src) {
|
||||
// Load image
|
||||
const img = document.createElement('img');
|
||||
img.src = src;
|
||||
await new Promise(resolve => img.onload = resolve);
|
||||
// Make canvas same size as image
|
||||
const canvas = document.createElement('canvas');
|
||||
[canvas.width, canvas.height] = [img.width, img.height];
|
||||
// Draw image onto canvas
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(img, 0, 0);
|
||||
return ctx.getImageData(0, 0, img.width, img.height);
|
||||
}
|
||||
|
||||
module.onRuntimeInitialized = async _ => {
|
||||
console.log('Version:', module.version().toString(16));
|
||||
const image = await loadImage('../../example.png');
|
||||
const result = module.encode(image.data, image.width, image.height, {
|
||||
quality: 75,
|
||||
target_size: 0,
|
||||
target_PSNR: 0,
|
||||
method: 4,
|
||||
sns_strength: 50,
|
||||
filter_strength: 60,
|
||||
filter_sharpness: 0,
|
||||
filter_type: 1,
|
||||
partitions: 0,
|
||||
segments: 4,
|
||||
pass: 1,
|
||||
show_compressed: 0,
|
||||
preprocessing: 0,
|
||||
autofilter: 0,
|
||||
partition_limit: 0,
|
||||
alpha_compression: 1,
|
||||
alpha_filtering: 1,
|
||||
alpha_quality: 100,
|
||||
lossless: 0,
|
||||
exact: 0,
|
||||
image_hint: 0,
|
||||
emulate_jpeg_size: 0,
|
||||
thread_level: 0,
|
||||
low_memory: 0,
|
||||
near_lossless: 100,
|
||||
use_delta_palette: 0,
|
||||
use_sharp_yuv: 0,
|
||||
});
|
||||
console.log('size', result.length);
|
||||
const blob = new Blob([result], {type: 'image/webp'});
|
||||
|
||||
module.free_result();
|
||||
|
||||
const blobURL = URL.createObjectURL(blob);
|
||||
const img = document.createElement('img');
|
||||
img.src = blobURL;
|
||||
document.body.appendChild(img);
|
||||
};
|
||||
</script>
|
||||
93
codecs/webp/enc/webp_enc.cpp
Normal file
93
codecs/webp/enc/webp_enc.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
#include <emscripten/bind.h>
|
||||
#include <emscripten/val.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdexcept>
|
||||
#include "src/webp/encode.h"
|
||||
|
||||
using namespace emscripten;
|
||||
|
||||
int version() {
|
||||
return WebPGetEncoderVersion();
|
||||
}
|
||||
|
||||
uint8_t* last_result;
|
||||
|
||||
val encode(std::string img, int width, int height, WebPConfig config) {
|
||||
uint8_t* img_in = (uint8_t*)img.c_str();
|
||||
|
||||
// A lot of this is duplicated from Encode in picture_enc.c
|
||||
WebPPicture pic;
|
||||
WebPMemoryWriter wrt;
|
||||
int ok;
|
||||
|
||||
if (!WebPPictureInit(&pic)) {
|
||||
// shouldn't happen, except if system installation is broken
|
||||
throw std::runtime_error("Unexpected error");
|
||||
}
|
||||
|
||||
// Only use use_argb if we really need it, as it's slower.
|
||||
pic.use_argb = config.lossless || config.use_sharp_yuv || config.preprocessing > 0;
|
||||
pic.width = width;
|
||||
pic.height = height;
|
||||
pic.writer = WebPMemoryWrite;
|
||||
pic.custom_ptr = &wrt;
|
||||
|
||||
WebPMemoryWriterInit(&wrt);
|
||||
|
||||
ok = WebPPictureImportRGBA(&pic, (uint8_t*)img_in, width * 4) && WebPEncode(&config, &pic);
|
||||
WebPPictureFree(&pic);
|
||||
if (!ok) {
|
||||
WebPMemoryWriterClear(&wrt);
|
||||
throw std::runtime_error("Encode failed");
|
||||
}
|
||||
|
||||
last_result = wrt.mem;
|
||||
|
||||
return val(typed_memory_view(wrt.size, wrt.mem));
|
||||
}
|
||||
|
||||
void free_result() {
|
||||
WebPFree(last_result);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_BINDINGS(my_module) {
|
||||
enum_<WebPImageHint>("WebPImageHint")
|
||||
.value("WEBP_HINT_DEFAULT", WebPImageHint::WEBP_HINT_DEFAULT)
|
||||
.value("WEBP_HINT_PICTURE", WebPImageHint::WEBP_HINT_PICTURE)
|
||||
.value("WEBP_HINT_PHOTO", WebPImageHint::WEBP_HINT_PHOTO)
|
||||
.value("WEBP_HINT_GRAPH", WebPImageHint::WEBP_HINT_GRAPH);
|
||||
|
||||
value_object<WebPConfig>("WebPConfig")
|
||||
.field("lossless", &WebPConfig::lossless)
|
||||
.field("quality", &WebPConfig::quality)
|
||||
.field("method", &WebPConfig::method)
|
||||
.field("image_hint", &WebPConfig::image_hint)
|
||||
.field("target_size", &WebPConfig::target_size)
|
||||
.field("target_PSNR", &WebPConfig::target_PSNR)
|
||||
.field("segments", &WebPConfig::segments)
|
||||
.field("sns_strength", &WebPConfig::sns_strength)
|
||||
.field("filter_strength", &WebPConfig::filter_strength)
|
||||
.field("filter_sharpness", &WebPConfig::filter_sharpness)
|
||||
.field("filter_type", &WebPConfig::filter_type)
|
||||
.field("autofilter", &WebPConfig::autofilter)
|
||||
.field("alpha_compression", &WebPConfig::alpha_compression)
|
||||
.field("alpha_filtering", &WebPConfig::alpha_filtering)
|
||||
.field("alpha_quality", &WebPConfig::alpha_quality)
|
||||
.field("pass", &WebPConfig::pass)
|
||||
.field("show_compressed", &WebPConfig::show_compressed)
|
||||
.field("preprocessing", &WebPConfig::preprocessing)
|
||||
.field("partitions", &WebPConfig::partitions)
|
||||
.field("partition_limit", &WebPConfig::partition_limit)
|
||||
.field("emulate_jpeg_size", &WebPConfig::emulate_jpeg_size)
|
||||
.field("thread_level", &WebPConfig::thread_level)
|
||||
.field("low_memory", &WebPConfig::low_memory)
|
||||
.field("near_lossless", &WebPConfig::near_lossless)
|
||||
.field("exact", &WebPConfig::exact)
|
||||
.field("use_delta_palette", &WebPConfig::use_delta_palette)
|
||||
.field("use_sharp_yuv", &WebPConfig::use_sharp_yuv);
|
||||
|
||||
function("version", &version);
|
||||
function("encode", &encode);
|
||||
function("free_result", &free_result);
|
||||
}
|
||||
9
codecs/webp/enc/webp_enc.d.ts
vendored
Normal file
9
codecs/webp/enc/webp_enc.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import { EncodeOptions } from '../../src/codecs/webp/encoder-meta';
|
||||
|
||||
interface WebPModule extends EmscriptenWasm.Module {
|
||||
encode(data: BufferSource, width: number, height: number, options: EncodeOptions): Uint8Array;
|
||||
free_result(): void;
|
||||
}
|
||||
|
||||
|
||||
export default function(opts: EmscriptenWasm.ModuleOpts): WebPModule;
|
||||
70
codecs/webp/enc/webp_enc.js
Normal file
70
codecs/webp/enc/webp_enc.js
Normal file
@@ -0,0 +1,70 @@
|
||||
|
||||
var webp_enc = (function() {
|
||||
var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined;
|
||||
if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename;
|
||||
return (
|
||||
function(webp_enc) {
|
||||
webp_enc = webp_enc || {};
|
||||
|
||||
var d;d||(d=typeof webp_enc !== 'undefined' ? webp_enc : {});var u={},w;for(w in d)d.hasOwnProperty(w)&&(u[w]=d[w]);var x=!1,y=!1,aa=!1,ba=!1;x="object"===typeof window;y="function"===typeof importScripts;aa="object"===typeof process&&"object"===typeof process.versions&&"string"===typeof process.versions.node;ba=!x&&!aa&&!y;var z="",B,C,ca,da;
|
||||
if(aa)z=y?require("path").dirname(z)+"/":__dirname+"/",B=function(a,b){ca||(ca=require("fs"));da||(da=require("path"));a=da.normalize(a);return ca.readFileSync(a,b?null:"utf8")},C=function(a){a=B(a,!0);a.buffer||(a=new Uint8Array(a));a.buffer||D("Assertion failed: undefined");return a},1<process.argv.length&&process.argv[1].replace(/\\/g,"/"),process.argv.slice(2),process.on("uncaughtException",function(a){throw a;}),process.on("unhandledRejection",D),d.inspect=function(){return"[Emscripten Module object]"};
|
||||
else if(ba)"undefined"!=typeof read&&(B=function(a){return read(a)}),C=function(a){if("function"===typeof readbuffer)return new Uint8Array(readbuffer(a));a=read(a,"binary");"object"===typeof a||D("Assertion failed: undefined");return a},"undefined"!==typeof print&&("undefined"===typeof console&&(console={}),console.log=print,console.warn=console.error="undefined"!==typeof printErr?printErr:print);else if(x||y)y?z=self.location.href:document.currentScript&&(z=document.currentScript.src),_scriptDir&&
|
||||
(z=_scriptDir),0!==z.indexOf("blob:")?z=z.substr(0,z.lastIndexOf("/")+1):z="",B=function(a){var b=new XMLHttpRequest;b.open("GET",a,!1);b.send(null);return b.responseText},y&&(C=function(a){var b=new XMLHttpRequest;b.open("GET",a,!1);b.responseType="arraybuffer";b.send(null);return new Uint8Array(b.response)});var ea=d.print||console.log.bind(console),E=d.printErr||console.warn.bind(console);for(w in u)u.hasOwnProperty(w)&&(d[w]=u[w]);u=null;var F;d.wasmBinary&&(F=d.wasmBinary);var noExitRuntime;
|
||||
d.noExitRuntime&&(noExitRuntime=d.noExitRuntime);"object"!==typeof WebAssembly&&E("no native wasm support detected");var G,fa=new WebAssembly.Table({initial:129,maximum:129,element:"anyfunc"}),ha=!1,ia="undefined"!==typeof TextDecoder?new TextDecoder("utf8"):void 0;
|
||||
function ja(a,b,c){var e=I;if(0<c){c=b+c-1;for(var f=0;f<a.length;++f){var g=a.charCodeAt(f);if(55296<=g&&57343>=g){var n=a.charCodeAt(++f);g=65536+((g&1023)<<10)|n&1023}if(127>=g){if(b>=c)break;e[b++]=g}else{if(2047>=g){if(b+1>=c)break;e[b++]=192|g>>6}else{if(65535>=g){if(b+2>=c)break;e[b++]=224|g>>12}else{if(b+3>=c)break;e[b++]=240|g>>18;e[b++]=128|g>>12&63}e[b++]=128|g>>6&63}e[b++]=128|g&63}}e[b]=0}}var ka="undefined"!==typeof TextDecoder?new TextDecoder("utf-16le"):void 0;
|
||||
function la(a){var b;for(b=a>>1;J[b];)++b;b<<=1;if(32<b-a&&ka)return ka.decode(I.subarray(a,b));b=0;for(var c="";;){var e=J[a+2*b>>1];if(0==e)return c;++b;c+=String.fromCharCode(e)}}function ma(a,b,c){void 0===c&&(c=2147483647);if(2>c)return 0;c-=2;var e=b;c=c<2*a.length?c/2:a.length;for(var f=0;f<c;++f)J[b>>1]=a.charCodeAt(f),b+=2;J[b>>1]=0;return b-e}function na(a){return 2*a.length}
|
||||
function oa(a){for(var b=0,c="";;){var e=K[a+4*b>>2];if(0==e)return c;++b;65536<=e?(e-=65536,c+=String.fromCharCode(55296|e>>10,56320|e&1023)):c+=String.fromCharCode(e)}}function pa(a,b,c){void 0===c&&(c=2147483647);if(4>c)return 0;var e=b;c=e+c-4;for(var f=0;f<a.length;++f){var g=a.charCodeAt(f);if(55296<=g&&57343>=g){var n=a.charCodeAt(++f);g=65536+((g&1023)<<10)|n&1023}K[b>>2]=g;b+=4;if(b+4>c)break}K[b>>2]=0;return b-e}
|
||||
function qa(a){for(var b=0,c=0;c<a.length;++c){var e=a.charCodeAt(c);55296<=e&&57343>=e&&++c;b+=4}return b}var L,ra,I,J,sa,K,M,ta,ua;function va(a){L=a;d.HEAP8=ra=new Int8Array(a);d.HEAP16=J=new Int16Array(a);d.HEAP32=K=new Int32Array(a);d.HEAPU8=I=new Uint8Array(a);d.HEAPU16=sa=new Uint16Array(a);d.HEAPU32=M=new Uint32Array(a);d.HEAPF32=ta=new Float32Array(a);d.HEAPF64=ua=new Float64Array(a)}var wa=d.INITIAL_MEMORY||16777216;d.wasmMemory?G=d.wasmMemory:G=new WebAssembly.Memory({initial:wa/65536});
|
||||
G&&(L=G.buffer);wa=L.byteLength;va(L);K[8664]=5277696;function xa(a){for(;0<a.length;){var b=a.shift();if("function"==typeof b)b();else{var c=b.X;"number"===typeof c?void 0===b.R?d.dynCall_v(c):d.dynCall_vi(c,b.R):c(void 0===b.R?null:b.R)}}}var ya=[],za=[],Aa=[],Ba=[];function Ca(){var a=d.preRun.shift();ya.unshift(a)}var N=0,Da=null,O=null;d.preloadedImages={};d.preloadedAudios={};
|
||||
function D(a){if(d.onAbort)d.onAbort(a);ea(a);E(a);ha=!0;throw new WebAssembly.RuntimeError("abort("+a+"). Build with -s ASSERTIONS=1 for more info.");}function Ea(){var a=P;return String.prototype.startsWith?a.startsWith("data:application/octet-stream;base64,"):0===a.indexOf("data:application/octet-stream;base64,")}var P="webp_enc.wasm";if(!Ea()){var Fa=P;P=d.locateFile?d.locateFile(Fa,z):z+Fa}
|
||||
function Ga(){try{if(F)return new Uint8Array(F);if(C)return C(P);throw"both async and sync fetching of the wasm failed";}catch(a){D(a)}}function Ha(){return F||!x&&!y||"function"!==typeof fetch?new Promise(function(a){a(Ga())}):fetch(P,{credentials:"same-origin"}).then(function(a){if(!a.ok)throw"failed to load wasm binary file at '"+P+"'";return a.arrayBuffer()}).catch(function(){return Ga()})}za.push({X:function(){Ia()}});function Ja(){return 0<Ja.T}var Ka={};
|
||||
function La(a){for(;a.length;){var b=a.pop();a.pop()(b)}}function Ma(a){return this.fromWireType(M[a>>2])}var Q={},R={},Na={};function Oa(a){if(void 0===a)return"_unknown";a=a.replace(/[^a-zA-Z0-9_]/g,"$");var b=a.charCodeAt(0);return 48<=b&&57>=b?"_"+a:a}function Pa(a,b){a=Oa(a);return(new Function("body","return function "+a+'() {\n "use strict"; return body.apply(this, arguments);\n};\n'))(b)}
|
||||
function Qa(a){var b=Error,c=Pa(a,function(e){this.name=a;this.message=e;e=Error(e).stack;void 0!==e&&(this.stack=this.toString()+"\n"+e.replace(/^Error(:[^\n]*)?\n/,""))});c.prototype=Object.create(b.prototype);c.prototype.constructor=c;c.prototype.toString=function(){return void 0===this.message?this.name:this.name+": "+this.message};return c}var Ra=void 0;
|
||||
function Sa(a,b,c){function e(h){h=c(h);if(h.length!==a.length)throw new Ra("Mismatched type converter count");for(var k=0;k<a.length;++k)S(a[k],h[k])}a.forEach(function(h){Na[h]=b});var f=Array(b.length),g=[],n=0;b.forEach(function(h,k){R.hasOwnProperty(h)?f[k]=R[h]:(g.push(h),Q.hasOwnProperty(h)||(Q[h]=[]),Q[h].push(function(){f[k]=R[h];++n;n===g.length&&e(f)}))});0===g.length&&e(f)}
|
||||
function Ta(a){switch(a){case 1:return 0;case 2:return 1;case 4:return 2;case 8:return 3;default:throw new TypeError("Unknown type size: "+a);}}var Ua=void 0;function T(a){for(var b="";I[a];)b+=Ua[I[a++]];return b}var Va=void 0;function U(a){throw new Va(a);}
|
||||
function S(a,b,c){c=c||{};if(!("argPackAdvance"in b))throw new TypeError("registerType registeredInstance requires argPackAdvance");var e=b.name;a||U('type "'+e+'" must have a positive integer typeid pointer');if(R.hasOwnProperty(a)){if(c.aa)return;U("Cannot register type '"+e+"' twice")}R[a]=b;delete Na[a];Q.hasOwnProperty(a)&&(b=Q[a],delete Q[a],b.forEach(function(f){f()}))}var Wa=[],V=[{},{value:void 0},{value:null},{value:!0},{value:!1}];
|
||||
function Xa(a){4<a&&0===--V[a].S&&(V[a]=void 0,Wa.push(a))}function Ya(a){switch(a){case void 0:return 1;case null:return 2;case !0:return 3;case !1:return 4;default:var b=Wa.length?Wa.pop():V.length;V[b]={S:1,value:a};return b}}
|
||||
function Za(a,b){var c=d;if(void 0===c[a].P){var e=c[a];c[a]=function(){c[a].P.hasOwnProperty(arguments.length)||U("Function '"+b+"' called with an invalid number of arguments ("+arguments.length+") - expects one of ("+c[a].P+")!");return c[a].P[arguments.length].apply(this,arguments)};c[a].P=[];c[a].P[e.V]=e}}
|
||||
function $a(a,b,c){d.hasOwnProperty(a)?((void 0===c||void 0!==d[a].P&&void 0!==d[a].P[c])&&U("Cannot register public name '"+a+"' twice"),Za(a,a),d.hasOwnProperty(c)&&U("Cannot register multiple overloads of a function with the same number of arguments ("+c+")!"),d[a].P[c]=b):(d[a]=b,void 0!==c&&(d[a].ia=c))}
|
||||
function ab(a,b,c){switch(b){case 0:return function(e){return this.fromWireType((c?ra:I)[e])};case 1:return function(e){return this.fromWireType((c?J:sa)[e>>1])};case 2:return function(e){return this.fromWireType((c?K:M)[e>>2])};default:throw new TypeError("Unknown integer type: "+a);}}function bb(a){a=cb(a);var b=T(a);X(a);return b}function db(a,b){var c=R[a];void 0===c&&U(b+" has unknown type "+bb(a));return c}
|
||||
function eb(a){if(null===a)return"null";var b=typeof a;return"object"===b||"array"===b||"function"===b?a.toString():""+a}function fb(a,b){switch(b){case 2:return function(c){return this.fromWireType(ta[c>>2])};case 3:return function(c){return this.fromWireType(ua[c>>3])};default:throw new TypeError("Unknown float type: "+a);}}
|
||||
function gb(a){var b=Function;if(!(b instanceof Function))throw new TypeError("new_ called with constructor type "+typeof b+" which is not a function");var c=Pa(b.name||"unknownFunctionName",function(){});c.prototype=b.prototype;c=new c;a=b.apply(c,a);return a instanceof Object?a:c}function hb(a,b){for(var c=[],e=0;e<a;e++)c.push(K[(b>>2)+e]);return c}
|
||||
function Y(a,b){a=T(a);var c=d["dynCall_"+a];for(var e=[],f=1;f<a.length;++f)e.push("a"+f);f="return function dynCall_"+(a+"_"+b)+"("+e.join(", ")+") {\n";f+=" return dynCall(rawFunction"+(e.length?", ":"")+e.join(", ")+");\n";c=(new Function("dynCall","rawFunction",f+"};\n"))(c,b);"function"!==typeof c&&U("unknown function pointer with signature "+a+": "+b);return c}var ib=void 0;
|
||||
function jb(a,b){function c(g){f[g]||R[g]||(Na[g]?Na[g].forEach(c):(e.push(g),f[g]=!0))}var e=[],f={};b.forEach(c);throw new ib(a+": "+e.map(bb).join([", "]));}function kb(a,b,c){switch(b){case 0:return c?function(e){return ra[e]}:function(e){return I[e]};case 1:return c?function(e){return J[e>>1]}:function(e){return sa[e>>1]};case 2:return c?function(e){return K[e>>2]}:function(e){return M[e>>2]};default:throw new TypeError("Unknown integer type: "+a);}}Ra=d.InternalError=Qa("InternalError");
|
||||
for(var lb=Array(256),mb=0;256>mb;++mb)lb[mb]=String.fromCharCode(mb);Ua=lb;Va=d.BindingError=Qa("BindingError");d.count_emval_handles=function(){for(var a=0,b=5;b<V.length;++b)void 0!==V[b]&&++a;return a};d.get_first_emval=function(){for(var a=5;a<V.length;++a)if(void 0!==V[a])return V[a];return null};ib=d.UnboundTypeError=Qa("UnboundTypeError");
|
||||
var ob={j:function(a){return nb(a)},i:function(a){"uncaught_exception"in Ja?Ja.T++:Ja.T=1;throw a;},l:function(a){var b=Ka[a];delete Ka[a];var c=b.ba,e=b.da,f=b.U,g=f.map(function(n){return n.$}).concat(f.map(function(n){return n.fa}));Sa([a],g,function(n){var h={};f.forEach(function(k,l){var m=n[l],p=k.Y,r=k.Z,v=n[l+f.length],q=k.ea,t=k.ga;h[k.W]={read:function(A){return m.fromWireType(p(r,A))},write:function(A,H){var W=[];q(t,A,v.toWireType(W,H));La(W)}}});return[{name:b.name,fromWireType:function(k){var l=
|
||||
{},m;for(m in h)l[m]=h[m].read(k);e(k);return l},toWireType:function(k,l){for(var m in h)if(!(m in l))throw new TypeError("Missing field");var p=c();for(m in h)h[m].write(p,l[m]);null!==k&&k.push(e,p);return p},argPackAdvance:8,readValueFromPointer:Ma,O:e}]})},s:function(a,b,c,e,f){var g=Ta(c);b=T(b);S(a,{name:b,fromWireType:function(n){return!!n},toWireType:function(n,h){return h?e:f},argPackAdvance:8,readValueFromPointer:function(n){if(1===c)var h=ra;else if(2===c)h=J;else if(4===c)h=K;else throw new TypeError("Unknown boolean type size: "+
|
||||
b);return this.fromWireType(h[n>>g])},O:null})},r:function(a,b){b=T(b);S(a,{name:b,fromWireType:function(c){var e=V[c].value;Xa(c);return e},toWireType:function(c,e){return Ya(e)},argPackAdvance:8,readValueFromPointer:Ma,O:null})},o:function(a,b,c,e){function f(){}c=Ta(c);b=T(b);f.values={};S(a,{name:b,constructor:f,fromWireType:function(g){return this.constructor.values[g]},toWireType:function(g,n){return n.value},argPackAdvance:8,readValueFromPointer:ab(b,c,e),O:null});$a(b,f)},n:function(a,b,c){var e=
|
||||
db(a,"enum");b=T(b);a=e.constructor;e=Object.create(e.constructor.prototype,{value:{value:c},constructor:{value:Pa(e.name+"_"+b,function(){})}});a.values[c]=e;a[b]=e},g:function(a,b,c){c=Ta(c);b=T(b);S(a,{name:b,fromWireType:function(e){return e},toWireType:function(e,f){if("number"!==typeof f&&"boolean"!==typeof f)throw new TypeError('Cannot convert "'+eb(f)+'" to '+this.name);return f},argPackAdvance:8,readValueFromPointer:fb(b,c),O:null})},d:function(a,b,c,e,f,g){var n=hb(b,c);a=T(a);f=Y(e,f);
|
||||
$a(a,function(){jb("Cannot call "+a+" due to unbound types",n)},b-1);Sa([],n,function(h){var k=[h[0],null].concat(h.slice(1)),l=h=a,m=f,p=k.length;2>p&&U("argTypes array size mismatch! Must at least get return value and 'this' types!");for(var r=null!==k[1]&&!1,v=!1,q=1;q<k.length;++q)if(null!==k[q]&&void 0===k[q].O){v=!0;break}var t="void"!==k[0].name,A="",H="";for(q=0;q<p-2;++q)A+=(0!==q?", ":"")+"arg"+q,H+=(0!==q?", ":"")+"arg"+q+"Wired";l="return function "+Oa(l)+"("+A+") {\nif (arguments.length !== "+
|
||||
(p-2)+") {\nthrowBindingError('function "+l+" called with ' + arguments.length + ' arguments, expected "+(p-2)+" args!');\n}\n";v&&(l+="var destructors = [];\n");var W=v?"destructors":"null";A="throwBindingError invoker fn runDestructors retType classParam".split(" ");m=[U,m,g,La,k[0],k[1]];r&&(l+="var thisWired = classParam.toWireType("+W+", this);\n");for(q=0;q<p-2;++q)l+="var arg"+q+"Wired = argType"+q+".toWireType("+W+", arg"+q+"); // "+k[q+2].name+"\n",A.push("argType"+q),m.push(k[q+2]);r&&(H=
|
||||
"thisWired"+(0<H.length?", ":"")+H);l+=(t?"var rv = ":"")+"invoker(fn"+(0<H.length?", ":"")+H+");\n";if(v)l+="runDestructors(destructors);\n";else for(q=r?1:2;q<k.length;++q)p=1===q?"thisWired":"arg"+(q-2)+"Wired",null!==k[q].O&&(l+=p+"_dtor("+p+"); // "+k[q].name+"\n",A.push(p+"_dtor"),m.push(k[q].O));t&&(l+="var ret = retType.fromWireType(rv);\nreturn ret;\n");A.push(l+"}\n");k=gb(A).apply(null,m);q=b-1;if(!d.hasOwnProperty(h))throw new Ra("Replacing nonexistant public symbol");void 0!==d[h].P&&
|
||||
void 0!==q?d[h].P[q]=k:(d[h]=k,d[h].V=q);return[]})},b:function(a,b,c,e,f){function g(l){return l}b=T(b);-1===f&&(f=4294967295);var n=Ta(c);if(0===e){var h=32-8*c;g=function(l){return l<<h>>>h}}var k=-1!=b.indexOf("unsigned");S(a,{name:b,fromWireType:g,toWireType:function(l,m){if("number"!==typeof m&&"boolean"!==typeof m)throw new TypeError('Cannot convert "'+eb(m)+'" to '+this.name);if(m<e||m>f)throw new TypeError('Passing a number "'+eb(m)+'" from JS side to C/C++ side to an argument of type "'+
|
||||
b+'", which is outside the valid range ['+e+", "+f+"]!");return k?m>>>0:m|0},argPackAdvance:8,readValueFromPointer:kb(b,n,0!==e),O:null})},a:function(a,b,c){function e(g){g>>=2;var n=M;return new f(L,n[g+1],n[g])}var f=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array][b];c=T(c);S(a,{name:c,fromWireType:e,argPackAdvance:8,readValueFromPointer:e},{aa:!0})},h:function(a,b){b=T(b);var c="std::string"===b;S(a,{name:b,fromWireType:function(e){var f=M[e>>2];if(c){var g=
|
||||
I[e+4+f],n=0;0!=g&&(n=g,I[e+4+f]=0);var h=e+4;for(g=0;g<=f;++g){var k=e+4+g;if(0==I[k]){if(h){for(var l=I,m=h+NaN,p=h;l[p]&&!(p>=m);)++p;if(16<p-h&&l.subarray&&ia)h=ia.decode(l.subarray(h,p));else{for(m="";h<p;){var r=l[h++];if(r&128){var v=l[h++]&63;if(192==(r&224))m+=String.fromCharCode((r&31)<<6|v);else{var q=l[h++]&63;r=224==(r&240)?(r&15)<<12|v<<6|q:(r&7)<<18|v<<12|q<<6|l[h++]&63;65536>r?m+=String.fromCharCode(r):(r-=65536,m+=String.fromCharCode(55296|r>>10,56320|r&1023))}}else m+=String.fromCharCode(r)}h=
|
||||
m}}else h="";if(void 0===t)var t=h;else t+=String.fromCharCode(0),t+=h;h=k+1}}0!=n&&(I[e+4+f]=n)}else{t=Array(f);for(g=0;g<f;++g)t[g]=String.fromCharCode(I[e+4+g]);t=t.join("")}X(e);return t},toWireType:function(e,f){f instanceof ArrayBuffer&&(f=new Uint8Array(f));var g="string"===typeof f;g||f instanceof Uint8Array||f instanceof Uint8ClampedArray||f instanceof Int8Array||U("Cannot pass non-string to std::string");var n=(c&&g?function(){for(var l=0,m=0;m<f.length;++m){var p=f.charCodeAt(m);55296<=
|
||||
p&&57343>=p&&(p=65536+((p&1023)<<10)|f.charCodeAt(++m)&1023);127>=p?++l:l=2047>=p?l+2:65535>=p?l+3:l+4}return l}:function(){return f.length})(),h=nb(4+n+1);M[h>>2]=n;if(c&&g)ja(f,h+4,n+1);else if(g)for(g=0;g<n;++g){var k=f.charCodeAt(g);255<k&&(X(h),U("String has UTF-16 code units that do not fit in 8 bits"));I[h+4+g]=k}else for(g=0;g<n;++g)I[h+4+g]=f[g];null!==e&&e.push(X,h);return h},argPackAdvance:8,readValueFromPointer:Ma,O:function(e){X(e)}})},f:function(a,b,c){c=T(c);if(2===b){var e=la;var f=
|
||||
ma;var g=na;var n=function(){return sa};var h=1}else 4===b&&(e=oa,f=pa,g=qa,n=function(){return M},h=2);S(a,{name:c,fromWireType:function(k){var l=M[k>>2],m=n(),p=m[k+4+l*b>>h],r=0;0!=p&&(r=p,m[k+4+l*b>>h]=0);var v=k+4;for(p=0;p<=l;++p){var q=k+4+p*b;if(0==m[q>>h]){v=e(v);if(void 0===t)var t=v;else t+=String.fromCharCode(0),t+=v;v=q+b}}0!=r&&(m[k+4+l*b>>h]=r);X(k);return t},toWireType:function(k,l){"string"!==typeof l&&U("Cannot pass non-string to C++ string type "+c);var m=g(l),p=nb(4+m+b);M[p>>
|
||||
2]=m>>h;f(l,p+4,m+b);null!==k&&k.push(X,p);return p},argPackAdvance:8,readValueFromPointer:Ma,O:function(k){X(k)}})},m:function(a,b,c,e,f,g){Ka[a]={name:T(b),ba:Y(c,e),da:Y(f,g),U:[]}},e:function(a,b,c,e,f,g,n,h,k,l){Ka[a].U.push({W:T(b),$:c,Y:Y(e,f),Z:g,fa:n,ea:Y(h,k),ga:l})},t:function(a,b){b=T(b);S(a,{ha:!0,name:b,argPackAdvance:0,fromWireType:function(){},toWireType:function(){}})},u:Xa,k:function(a){4<a&&(V[a].S+=1)},q:function(a,b){a=db(a,"_emval_take_value");a=a.readValueFromPointer(b);return Ya(a)},
|
||||
p:function(a,b,c){I.copyWithin(a,b,b+c)},c:function(a){var b=I.length;if(2147418112<a)return!1;for(var c=1;4>=c;c*=2){var e=b*(1+.2/c);e=Math.min(e,a+100663296);e=Math.max(16777216,a,e);0<e%65536&&(e+=65536-e%65536);a:{try{G.grow(Math.min(2147418112,e)-L.byteLength+65535>>16);va(G.buffer);var f=1;break a}catch(g){}f=void 0}if(f)return!0}return!1},memory:G,table:fa},pb=function(){function a(f){d.asm=f.exports;N--;d.monitorRunDependencies&&d.monitorRunDependencies(N);0==N&&(null!==Da&&(clearInterval(Da),
|
||||
Da=null),O&&(f=O,O=null,f()))}function b(f){a(f.instance)}function c(f){return Ha().then(function(g){return WebAssembly.instantiate(g,e)}).then(f,function(g){E("failed to asynchronously prepare wasm: "+g);D(g)})}var e={a:ob};N++;d.monitorRunDependencies&&d.monitorRunDependencies(N);if(d.instantiateWasm)try{return d.instantiateWasm(e,a)}catch(f){return E("Module.instantiateWasm callback failed with error: "+f),!1}(function(){if(F||"function"!==typeof WebAssembly.instantiateStreaming||Ea()||"function"!==
|
||||
typeof fetch)return c(b);fetch(P,{credentials:"same-origin"}).then(function(f){return WebAssembly.instantiateStreaming(f,e).then(b,function(g){E("wasm streaming compile failed: "+g);E("falling back to ArrayBuffer instantiation");c(b)})})})();return{}}();d.asm=pb;
|
||||
var Ia=d.___wasm_call_ctors=function(){return(Ia=d.___wasm_call_ctors=d.asm.v).apply(null,arguments)},nb=d._malloc=function(){return(nb=d._malloc=d.asm.w).apply(null,arguments)},X=d._free=function(){return(X=d._free=d.asm.x).apply(null,arguments)},cb=d.___getTypeName=function(){return(cb=d.___getTypeName=d.asm.y).apply(null,arguments)};d.___embind_register_native_and_builtin_types=function(){return(d.___embind_register_native_and_builtin_types=d.asm.z).apply(null,arguments)};
|
||||
d.dynCall_i=function(){return(d.dynCall_i=d.asm.A).apply(null,arguments)};d.dynCall_vi=function(){return(d.dynCall_vi=d.asm.B).apply(null,arguments)};d.dynCall_iii=function(){return(d.dynCall_iii=d.asm.C).apply(null,arguments)};d.dynCall_viii=function(){return(d.dynCall_viii=d.asm.D).apply(null,arguments)};d.dynCall_fii=function(){return(d.dynCall_fii=d.asm.E).apply(null,arguments)};d.dynCall_viif=function(){return(d.dynCall_viif=d.asm.F).apply(null,arguments)};
|
||||
d.dynCall_ii=function(){return(d.dynCall_ii=d.asm.G).apply(null,arguments)};d.dynCall_iiiiii=function(){return(d.dynCall_iiiiii=d.asm.H).apply(null,arguments)};d.dynCall_viiiii=function(){return(d.dynCall_viiiii=d.asm.I).apply(null,arguments)};d.dynCall_v=function(){return(d.dynCall_v=d.asm.J).apply(null,arguments)};d.dynCall_iiii=function(){return(d.dynCall_iiii=d.asm.K).apply(null,arguments)};d.dynCall_viiiiiiiii=function(){return(d.dynCall_viiiiiiiii=d.asm.L).apply(null,arguments)};
|
||||
d.dynCall_viiii=function(){return(d.dynCall_viiii=d.asm.M).apply(null,arguments)};d.dynCall_viiiiii=function(){return(d.dynCall_viiiiii=d.asm.N).apply(null,arguments)};d.asm=pb;var Z;d.then=function(a){if(Z)a(d);else{var b=d.onRuntimeInitialized;d.onRuntimeInitialized=function(){b&&b();a(d)}}return d};O=function qb(){Z||rb();Z||(O=qb)};
|
||||
function rb(){function a(){if(!Z&&(Z=!0,d.calledRun=!0,!ha)){xa(za);xa(Aa);if(d.onRuntimeInitialized)d.onRuntimeInitialized();if(d.postRun)for("function"==typeof d.postRun&&(d.postRun=[d.postRun]);d.postRun.length;){var b=d.postRun.shift();Ba.unshift(b)}xa(Ba)}}if(!(0<N)){if(d.preRun)for("function"==typeof d.preRun&&(d.preRun=[d.preRun]);d.preRun.length;)Ca();xa(ya);0<N||(d.setStatus?(d.setStatus("Running..."),setTimeout(function(){setTimeout(function(){d.setStatus("")},1);a()},1)):a())}}d.run=rb;
|
||||
if(d.preInit)for("function"==typeof d.preInit&&(d.preInit=[d.preInit]);0<d.preInit.length;)d.preInit.pop()();noExitRuntime=!0;rb();
|
||||
|
||||
|
||||
return webp_enc
|
||||
}
|
||||
);
|
||||
})();
|
||||
if (typeof exports === 'object' && typeof module === 'object')
|
||||
module.exports = webp_enc;
|
||||
else if (typeof define === 'function' && define['amd'])
|
||||
define([], function() { return webp_enc; });
|
||||
else if (typeof exports === 'object')
|
||||
exports["webp_enc"] = webp_enc;
|
||||
|
||||
BIN
codecs/webp/enc/webp_enc.wasm
Normal file
BIN
codecs/webp/enc/webp_enc.wasm
Normal file
Binary file not shown.
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "webp_dec",
|
||||
"name": "webp",
|
||||
"requires": true,
|
||||
"lockfileVersion": 1,
|
||||
"dependencies": {
|
||||
13
codecs/webp/package.json
Normal file
13
codecs/webp/package.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "webp",
|
||||
"scripts": {
|
||||
"install": "napa",
|
||||
"build": "docker run --rm -v $(pwd):/src trzeci/emscripten-upstream ./build.sh"
|
||||
},
|
||||
"napa": {
|
||||
"libwebp": "webmproject/libwebp#v1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"napa": "3.0.0"
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
# WebP decoder
|
||||
|
||||
- Source: <https://github.com/webmproject/libwebp>
|
||||
- Version: v0.6.1
|
||||
|
||||
## Example
|
||||
|
||||
See `example.html`
|
||||
|
||||
## API
|
||||
|
||||
### `int version()`
|
||||
|
||||
Returns the version of libwebp as a number. va.b.c is encoded as 0x0a0b0c
|
||||
|
||||
### `uint8_t* create_buffer(int size)`
|
||||
|
||||
Allocates an buffer for the file data.
|
||||
|
||||
### `void destroy_buffer(uint8_t* p)`
|
||||
|
||||
Frees a buffer created with `create_buffer`.
|
||||
|
||||
### `void decode(uint8_t* img_in, int size)`
|
||||
|
||||
Decodes the given webp file into raw RGBA. The result is implicitly stored and can be accessed using the `get_result_*()` functions.
|
||||
|
||||
### `void free_result()`
|
||||
|
||||
Frees the result created by `decode()`.
|
||||
|
||||
### `int get_result_pointer()`
|
||||
|
||||
Returns the pointer to the start of the buffer holding the encoded data. Length is width x height x 4 bytes.
|
||||
|
||||
### `int get_result_width()`
|
||||
|
||||
Returns the width of the image.
|
||||
|
||||
### `int get_result_height()`
|
||||
|
||||
Returns the height of the image.
|
||||
@@ -1,45 +0,0 @@
|
||||
<!doctype html>
|
||||
<script src='webp_dec.js'></script>
|
||||
<script>
|
||||
const Module = webp_dec();
|
||||
|
||||
async function loadFile(src) {
|
||||
const resp = await fetch(src);
|
||||
return await resp.arrayBuffer();
|
||||
}
|
||||
|
||||
Module.onRuntimeInitialized = async _ => {
|
||||
const api = {
|
||||
version: Module.cwrap('version', 'number', []),
|
||||
create_buffer: Module.cwrap('create_buffer', 'number', ['number', 'number']),
|
||||
destroy_buffer: Module.cwrap('destroy_buffer', '', ['number']),
|
||||
decode: Module.cwrap('decode', '', ['number', 'number']),
|
||||
free_result: Module.cwrap('free_result', '', ['number']),
|
||||
get_result_pointer: Module.cwrap('get_result_pointer', 'number', []),
|
||||
get_result_width: Module.cwrap('get_result_width', 'number', []),
|
||||
get_result_height: Module.cwrap('get_result_height', 'number', []),
|
||||
};
|
||||
console.log('Version:', api.version().toString(16));
|
||||
const image = await loadFile('../example.webp');
|
||||
const p = api.create_buffer(image.byteLength);
|
||||
Module.HEAP8.set(new Uint8Array(image), p);
|
||||
api.decode(p, image.byteLength);
|
||||
const resultPointer = api.get_result_pointer();
|
||||
if(resultPointer === 0) {
|
||||
throw new Error("Could not decode image");
|
||||
}
|
||||
const resultWidth = api.get_result_width();
|
||||
const resultHeight = api.get_result_height();
|
||||
const resultView = new Uint8Array(Module.HEAP8.buffer, resultPointer, resultWidth * resultHeight * 4);
|
||||
const result = new Uint8ClampedArray(resultView);
|
||||
const imageData = new ImageData(result, resultWidth, resultHeight);
|
||||
api.free_result(resultPointer);
|
||||
api.destroy_buffer(p);
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = resultWidth;
|
||||
canvas.height = resultHeight;
|
||||
document.body.appendChild(canvas);
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.putImageData(imageData, 0, 0);
|
||||
};
|
||||
</script>
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"name": "webp_dec",
|
||||
"scripts": {
|
||||
"install": "napa",
|
||||
"build": "docker run --rm -v $(pwd):/src trzeci/emscripten emcc -O3 -s WASM=1 -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"cwrap\"]' -s ALLOW_MEMORY_GROWTH=1 -s MODULARIZE=1 -s 'EXPORT_NAME=\"webp_dec\"' -I node_modules/libwebp -o ./webp_dec.js webp_dec.c node_modules/libwebp/src/{dec,dsp,demux,enc,mux,utils}/*.c"
|
||||
},
|
||||
"napa": {
|
||||
"libwebp": "webmproject/libwebp#v1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"napa": "^3.0.0"
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
#include "emscripten.h"
|
||||
#include "src/webp/decode.h"
|
||||
#include "src/webp/demux.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
int version() {
|
||||
return WebPGetDecoderVersion();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
uint8_t* create_buffer(int size) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
void destroy_buffer(uint8_t* p) {
|
||||
free(p);
|
||||
}
|
||||
|
||||
int result[3];
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
void decode(uint8_t* img_in, int size) {
|
||||
int width, height;
|
||||
uint8_t* img_out = WebPDecodeRGBA(img_in, size, &width, &height);
|
||||
result[0] = (int)img_out;
|
||||
result[1] = width;
|
||||
result[2] = height;
|
||||
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
void free_result() {
|
||||
WebPFree(result[0]);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
int get_result_pointer() {
|
||||
return result[0];
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
int get_result_width() {
|
||||
return result[1];
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
int get_result_height() {
|
||||
return result[2];
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user