From 14e94d1deffbf0b2e1c9738035f5abb35caf222f Mon Sep 17 00:00:00 2001 From: Mathis Mensing Date: Fri, 16 Oct 2026 20:35:25 +0000 Subject: [PATCH] renderText: smooth outlines along the antialiased glyph edge The outline was the distance to the nearest pixel at least half covered, so its edge followed that pixel staircase (bumpy at larger widths). Near the outline's edge, the distance now goes to the edge points of the pixels around the nearest covered one (3x3): from the pixel center along the coverage gradient to where a straight edge would cover it as much, like Gustavson's antialiased distance transform. The distance transform also returns the nearest sample for that. Against text rendered at 8x and scaled down, the mean error of the outline's coverage drops from about 0.3 to 0.07-0.1 (Source Sans, Open Sans, stroke widths 1-24). Distances beyond the outline are left out of the row pass, so it costs about as much as before (64px text, 3px outline: 6.6 -> 7.9 ms). effects target regenerated. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01YJgRK5qpwJEbHPuFv6kgAQ --- CHANGELOG.md | 2 + src/image.ts | 87 +++++++++++++++++++++++++++++++------- tests/targets/effects.png | Bin 501136 -> 502936 bytes 3 files changed, 74 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2f93e1b..edd7a3eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,8 @@ - The outline of `Image.renderText` (`strokeWidth`) showed through translucent text, it now only shows around the glyphs (opaque text renders as before). +- The outline of `Image.renderText` follows the glyphs' antialiased edges instead of their pixels, so it is smooth + rather than stepped, and it reaches exactly `strokeWidth` beyond the edge. ## 3.2.1 diff --git a/src/image.ts b/src/image.ts index d9ebc6f9..b9adc89d 100644 --- a/src/image.ts +++ b/src/image.ts @@ -2212,44 +2212,100 @@ const BLEND_MODES: Record numbe /** * Grows a coverage mask by a radius, using the distance of every pixel to the glyphs (an exact euclidean distance - * transform, so the cost doesn't depend on the radius) + * transform, so the cost doesn't depend on the radius). Near the outline's edge, the distance goes to the glyph edge + * within the pixels around the nearest covered one (estimated from their coverage and its gradient, like Gustavson's + * antialiased distance transform), so the outline follows the antialiased edge instead of the pixels * @return the outline's coverage (0..1) per pixel, including the area under the glyphs */ +// covered pixels around the nearest one (on either side) whose edge points the outline's edge is measured to +const OUTLINE_WINDOW = 1; + function outline(coverage: Uint8Array, width: number, height: number, radius: number): Float32Array { const count = width * height; - // squared distance to the nearest pixel that is at least half covered + // squared distance to the nearest pixel that is at least half covered, and that pixel's coordinates const distance = new Float64Array(count); for (let i = 0; i < count; i++) distance[i] = coverage[i] >= 128 ? 0 : Infinity; + const nearestY = new Int32Array(count), nearestX = new Int32Array(count); const size = Math.max(width, height); - const line = new Float64Array(size), result = new Float64Array(size); + const line = new Float64Array(size), result = new Float64Array(size), nearest = new Int32Array(size); const parabolas = new Int32Array(size), bounds = new Float64Array(size + 1); for (let x = 0; x < width; x++) { for (let y = 0; y < height; y++) line[y] = distance[y * width + x]; - distanceTransform(line, height, result, parabolas, bounds); - for (let y = 0; y < height; y++) distance[y * width + x] = result[y]; + distanceTransform(line, height, result, parabolas, bounds, nearest); + for (let y = 0; y < height; y++) { + distance[y * width + x] = result[y]; + nearestY[y * width + x] = nearest[y]; + } } + // distances beyond the outline don't matter: leaving them out of the rows saves most of their work + const far = (radius + 2) ** 2; for (let y = 0; y < height; y++) { const row = y * width; - for (let x = 0; x < width; x++) line[x] = distance[row + x]; - distanceTransform(line, width, result, parabolas, bounds); - for (let x = 0; x < width; x++) distance[row + x] = result[x]; + for (let x = 0; x < width; x++) line[x] = distance[row + x] < far ? distance[row + x] : Infinity; + distanceTransform(line, width, result, parabolas, bounds, nearest); + for (let x = 0; x < width; x++) { + distance[row + x] = result[x]; + nearestX[row + x] = nearest[x]; + } } + // where the glyph edge crosses an edge pixel (partly covered, or covered next to an uncovered one): from its + // center along the outward normal (the coverage gradient) to where a straight edge would cover it as much. The + // coverage has an empty border (the outline's room), so covered pixels have all their neighbors + const pointX = new Float32Array(count), pointY = new Float32Array(count), isEdge = new Uint8Array(count); + for (let y = 1; y < height - 1; y++) + for (let x = 1, e = y * width + 1; x < width - 1; x++, e++) { + const c = coverage[e]; + if (!c || c === 255 && coverage[e - 1] >= 128 && coverage[e + 1] >= 128 && coverage[e - width] >= 128 && coverage[e + width] >= 128) continue; + // Sobel gradient, pointing inwards + const above = e - width, below = e + width; + const gx = coverage[above + 1] + 2 * coverage[e + 1] + coverage[below + 1] - coverage[above - 1] - 2 * coverage[e - 1] - coverage[below - 1]; + const gy = coverage[below - 1] + 2 * coverage[below] + coverage[below + 1] - coverage[above - 1] - 2 * coverage[above] - coverage[above + 1]; + const length = Math.sqrt(gx * gx + gy * gy); + if (!length) continue; + // the center lies 1/2 - c outside the edge + const outside = 0.5 - c / 255; + pointX[e] = x + outside * gx / length; + pointY[e] = y + outside * gy / length; + isEdge[e] = 1; + } + + // the distance to the nearest covered pixel's center is within a pixel of the distance to the edge: outside of that + // band around the outline's edge, a pixel is fully covered or not at all + // (pixels next to the glyph edge are covered by the glyph's own antialiasing) const out = new Float32Array(count); - for (let i = 0; i < count; i++) { - // pixels next to the glyph edge are covered by the glyph's own antialiasing - const d = Math.sqrt(distance[i]); - out[i] = Math.max(coverage[i] / 255, Math.min(1, Math.max(0, radius + 0.5 - d))); - } + const inner = radius - 1.5, near = inner > 0 ? inner * inner : -1; + for (let y = 0, i = 0; y < height; y++) + for (let x = 0; x < width; x++, i++) { + const d2 = distance[i]; + if (d2 <= near) out[i] = 1; + if (d2 <= near || d2 >= far) { + if (d2 >= far) out[i] = coverage[i] / 255; + continue; + } + + // the closest edge point around the nearest covered pixel + const qx = nearestX[i], qy = nearestY[y * width + qx]; + let closest = Infinity; + for (let wy = Math.max(0, qy - OUTLINE_WINDOW); wy <= Math.min(height - 1, qy + OUTLINE_WINDOW); wy++) + for (let wx = Math.max(0, qx - OUTLINE_WINDOW), e = wy * width + wx; wx <= Math.min(width - 1, qx + OUTLINE_WINDOW); wx++, e++) { + if (!isEdge[e]) continue; + const ex = x - pointX[e], ey = y - pointY[e]; + closest = Math.min(closest, ex * ex + ey * ey); + } + closest = closest === Infinity ? Math.sqrt(d2) - 0.5 : Math.sqrt(closest); + out[i] = Math.max(coverage[i] / 255, Math.min(1, Math.max(0, radius + 0.5 - closest))); + } return out; } -// 1D squared euclidean distance transform (Felzenszwalb & Huttenlocher): lower envelope of parabolas -function distanceTransform(f: Float64Array, n: number, d: Float64Array, v: Int32Array, z: Float64Array): void { +// 1D squared euclidean distance transform (Felzenszwalb & Huttenlocher): lower envelope of parabolas, also the index +// of the nearest sample +function distanceTransform(f: Float64Array, n: number, d: Float64Array, v: Int32Array, z: Float64Array, nearest: Int32Array): void { let k = -1; for (let q = 0; q < n; q++) { if (f[q] === Infinity) continue; @@ -2273,5 +2329,6 @@ function distanceTransform(f: Float64Array, n: number, d: Float64Array, v: Int32 for (let q = 0, j = 0; q < n; q++) { while (z[j + 1] < q) j++; d[q] = (q - v[j]) ** 2 + f[v[j]]; + nearest[q] = v[j]; } } diff --git a/tests/targets/effects.png b/tests/targets/effects.png index 1ae40e400886117402a9e7e103e23d735c3f2c95..7bd54e35dd92a93d10aeb825d21704710b246951 100644 GIT binary patch delta 14611 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