From 59a82d0c2966e38f961c995c8cde2c4fe8f34432 Mon Sep 17 00:00:00 2001 From: Xavier Bourry Date: Fri, 3 Apr 2026 19:46:58 -0400 Subject: [PATCH 1/3] [QUAL] Apply gamma correction --- index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index b452b7f..4e2f604 100644 --- a/index.js +++ b/index.js @@ -90,7 +90,9 @@ export default class TinySDF { gridInner[j] = INF; } else { // aliased pixels - const d = 0.5 - a; + // gamma correction + const aLin = Math.pow(a, 1.0 / 2.2); + const d = 0.5 - aLin; gridOuter[j] = d > 0 ? d * d : 0; gridInner[j] = d < 0 ? d * d : 0; } From b6509249e9e840219f01af3948d42cfd0951ca79 Mon Sep 17 00:00:00 2001 From: Xavier Bourry Date: Mon, 6 Apr 2026 16:47:49 -0400 Subject: [PATCH 2/3] [TEST] Upgrade SDF reference for the test --- test/fixtures/1-metrics.json | 16 ++++++++-------- test/fixtures/1-out.json | 6 +++--- test/fixtures/1-raw.png | Bin 893 -> 887 bytes test/fixtures/1-sdf.png | Bin 3595 -> 3467 bytes 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/test/fixtures/1-metrics.json b/test/fixtures/1-metrics.json index 279c5a0..150a6cc 100644 --- a/test/fixtures/1-metrics.json +++ b/test/fixtures/1-metrics.json @@ -1,10 +1,10 @@ { - "width": 48, - "actualBoundingBoxLeft": 0, - "actualBoundingBoxRight": 48, - "actualBoundingBoxAscent": 39.2158203125, - "actualBoundingBoxDescent": 4.6083984375, - "emHeightAscent": 50.8798828125, - "emHeightDescent": 16.3203125, - "alphabeticBaseline": 13.9189453125 + "width": 48.2197265625, + "actualBoundingBoxLeft": 1.8720703125, + "actualBoundingBoxRight": 45.263671875, + "actualBoundingBoxAscent": 39.16796875, + "actualBoundingBoxDescent": 4.65625, + "emHeightAscent": 51, + "emHeightDescent": 17, + "alphabeticBaseline": 14.0390625 } \ No newline at end of file diff --git a/test/fixtures/1-out.json b/test/fixtures/1-out.json index 97c1b3b..19f4936 100644 --- a/test/fixtures/1-out.json +++ b/test/fixtures/1-out.json @@ -1,9 +1,9 @@ { - "width": 54, + "width": 50, "height": 51, - "glyphWidth": 48, + "glyphWidth": 44, "glyphHeight": 45, "glyphTop": 40, "glyphLeft": 0, - "glyphAdvance": 48 + "glyphAdvance": 48.2197265625 } \ No newline at end of file diff --git a/test/fixtures/1-raw.png b/test/fixtures/1-raw.png index d5bcf12f733b85b7952126180032d308fd42ddef..8a6f9c9cfa0d840b63c5eb8e99775f7e373c7e4a 100644 GIT binary patch delta 864 zcmV-m1E2i;2KNS#B!50hL_t(|0qwzCh*V_&0N`)_JvtQ9&1*>HOGF|O34v_B_ju)r={iprDS9#VVvj;jwr??j1!%~5j9GT%qA=nb$_8k5jSl(7V3kx4-j?r>=p&p^xy2|O>=<^->QRM6 zz5`ez-)yXs`hO8?3~!st&A>9z07{}Cuw0FT>djNEg;L+Cv!HtO4R!%a>LbBY(Lo$g zXF+wY#B~Onfv45SEto3m#DF>rs&fxYvYx~uwOb*zQvrg?jltcbK7*C81MNoc8r&e- zhi(N3Dt8km;~e%%{fsjx;{#k~WY(c1+NK~u%!gb40sjZN*+uJDydY4Je6TMz4Ydm02%3i}z%m!&00Ut;UTia~l?jPGXw^1^@15 z%oXjzQTYyGgDBuFOf|gouvuy&epR4gcx7ysddcvfN4IDqcB0MDp2IXz4_;8PV0i0s zg=jCj41cc|E2U=Pa{1=tA*rYEmx2XDn}x@u)~U=Vcvtic4#}E;H&7CNi8qacM85Ip zM4M<2K2y0>n2Zit2|979=rop~-zW&O+R%wP9hqSSyo2pX@9v9hj0yVMDFkZ8Q?@iBUF z5?Oy@ET$llI;;*7jrSG$P(~RO1VATctZ;-t5+;iVu}8L**p7vGMEP#Sm7>4VrO@-}Qldn* zR4 z64?%8xol(bq<_>|EO&m}uubVUDf9~#t58tBd1#ZLHgw2IP`(9*YC*f|S%g;6pQVZEpgUt@;yJ%npT>(MI*L4WC%ioU@iLoLB~qH)-c=}LDA zUJ~_Toty-vxeqf%TNLU?2abp)VjCtZ%?eBwy@{i85)AKRtQ8%@XR;kd2hNJ7<4cTl zem7vL=pD=refh~sh;oZoajCpv`(jVvW-EU={{s zy9ys55xs?-MnRD6emo=fGX7AW0ohvd2_}dRVVO}96l%j}G>H!3HPz9AkI*jaM+bV1 zlAzE@{4TW&|EOFOw%{(Q<@muU3bJhyeTq(%Yk$TjER^cRTB9t;_AZX$X_afi`*=)h zHy*_~qb!l_FWibAl^KT*F;D6s?!g%~kSOke%1p)QxK8RY?!<95lE}v-{Ddo{4&!!o ztDzttN3mC`8?(@@#)AAjg?{YCZ8+!xkjT$IJb{mK+65w!ueViZf+|bY-enkzKAglL z0$=V$yVPk_kf^=6=#&~jKgJkpuPR8?-uH%TMzf*LV6!R+YOe>sDQ-XJ<5yLX7@00? w6!ojz9k^7X6X@2^(9qD((9qD(&`@*#0dnA{abF~QdH?_b07*qoM6N<$f|lK(LjV8( diff --git a/test/fixtures/1-sdf.png b/test/fixtures/1-sdf.png index 3b502808fcd86038fd27026c24b885194ceafb13..d3d958fd00c016e17aa41b2c2c9c64483e3c0286 100644 GIT binary patch literal 3467 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 I77&y9KRa{xr~m)} From 9d611c4e31a2d02400807175002a837a0d6efec8 Mon Sep 17 00:00:00 2001 From: Xavier Bourry Date: Tue, 7 Apr 2026 10:04:59 -0400 Subject: [PATCH 3/3] [TEST] Add a benchmark --- package.json | 1 + test/bench.js | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 test/bench.js diff --git a/package.json b/package.json index cedbd9e..f538a1a 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "scripts": { "pretest": "eslint index.js index.html test", "test": "node --test", + "bench": "node ./test/bench.js", "start": "st --no-cache --localhost --index index.html ." }, "repository": { diff --git a/test/bench.js b/test/bench.js new file mode 100644 index 0000000..c953d49 --- /dev/null +++ b/test/bench.js @@ -0,0 +1,31 @@ +import TinySDF from '../index.js'; +import nodeCanvas from 'canvas'; + + +class MockTinySDF extends TinySDF { + _createCanvas(size) { + return nodeCanvas.createCanvas(size, size); + } +} + +function bench(iterationsCount) { + const sdf = new MockTinySDF({ + fontSize: 48, + buffer: 3 + }); + for (let i = 0; i < iterationsCount; ++i) { + sdf.draw('@'); + } +} + +function getCurrentTimestamp() { + return performance.now(); +} + +const ITERATIONS_COUNT = 1e5; +const tStart = getCurrentTimestamp(); +bench(ITERATIONS_COUNT); +const tEnd = getCurrentTimestamp(); +const dtSec = (tEnd - tStart) * 0.001; +console.log(`Durations for ${ITERATIONS_COUNT} iterations: ${dtSec} seconds`); +