diff --git a/index.js b/index.js index 17e8be4..0183c06 100644 --- a/index.js +++ b/index.js @@ -66,7 +66,9 @@ export default class TinySDF { // The integer/pixel part of the alignment is encoded in metrics.glyphTop/glyphLeft // The remainder is implicitly encoded in the rasterization const glyphTop = Math.ceil(actualBoundingBoxAscent); - const glyphLeft = Math.floor(actualBoundingBoxLeft); + // actualBoundingBoxLeft is positive when ink extends LEFT of the origin (per spec), + // so negate to get the ink's left edge in canvas x-coords (positive = right of origin) + const glyphLeft = Math.floor(-actualBoundingBoxLeft); // If the glyph overflows the canvas size, it will be clipped at the bottom/right const glyphWidth = Math.max(0, Math.min(this.size - this.buffer, Math.ceil(actualBoundingBoxRight) - glyphLeft)); @@ -106,7 +108,10 @@ export default class TinySDF { } edt(gridOuter, 0, 0, width, height, width, this.f, this.v, this.z); - edt(gridInner, buffer, buffer, glyphWidth, glyphHeight, width, this.f, this.v, this.z); + // Pad the inner EDT region by 1 px so ink pixels touching the bbox edge can see the + // outside-ink seeds in the buffer region; clamp to buffer so we don't underflow when buffer=0 + const pad = Math.min(buffer, 1); + edt(gridInner, buffer - pad, buffer - pad, glyphWidth + 2 * pad, glyphHeight + 2 * pad, width, this.f, this.v, this.z); // encode signed distance as a byte: inside the glyph maps to high values, outside to low, // with the edge gradient spanning [-radius * cutoff, radius * (1 - cutoff)] pixels around the edge; diff --git a/test/fixtures/1-metrics.json b/test/fixtures/1-metrics.json index 09dbeec..150a6cc 100644 --- a/test/fixtures/1-metrics.json +++ b/test/fixtures/1-metrics.json @@ -1,9 +1,9 @@ { - "width": 48, - "actualBoundingBoxLeft": 1.82421875, - "actualBoundingBoxRight": 45.2646484375, - "actualBoundingBoxAscent": 39.2158203125, - "actualBoundingBoxDescent": 4.6083984375, + "width": 48.2197265625, + "actualBoundingBoxLeft": 1.8720703125, + "actualBoundingBoxRight": 45.263671875, + "actualBoundingBoxAscent": 39.16796875, + "actualBoundingBoxDescent": 4.65625, "emHeightAscent": 51, "emHeightDescent": 17, "alphabeticBaseline": 14.0390625 diff --git a/test/fixtures/1-out.json b/test/fixtures/1-out.json index afd3b5e..7bdeb29 100644 --- a/test/fixtures/1-out.json +++ b/test/fixtures/1-out.json @@ -1,9 +1,9 @@ { - "width": 51, + "width": 54, "height": 51, - "glyphWidth": 45, + "glyphWidth": 48, "glyphHeight": 45, "glyphTop": 40, - "glyphLeft": 1, - "glyphAdvance": 48 + "glyphLeft": -2, + "glyphAdvance": 48.2197265625 } \ No newline at end of file diff --git a/test/fixtures/1-raw.png b/test/fixtures/1-raw.png index 9b67378..12891f0 100644 Binary files a/test/fixtures/1-raw.png and b/test/fixtures/1-raw.png differ diff --git a/test/fixtures/1-sdf.png b/test/fixtures/1-sdf.png index bbb6da2..a21bad3 100644 Binary files a/test/fixtures/1-sdf.png and b/test/fixtures/1-sdf.png differ diff --git a/test/test.js b/test/test.js index 490651c..8ccbcfe 100644 --- a/test/test.js +++ b/test/test.js @@ -93,7 +93,7 @@ test('does not return negative-width glyphs', () => { // stub these because they vary across environments sdf.ctx.measureText = () => ({ width: 0, - actualBoundingBoxLeft: 23.3759765625, + actualBoundingBoxLeft: -23.3759765625, actualBoundingBoxRight: -17.6162109375, actualBoundingBoxAscent: 20.2080078125, actualBoundingBoxDescent: -14.51953125,