From 4414069617ae3ebc3fcad7e926a87a9a76e68355 Mon Sep 17 00:00:00 2001 From: David Luzar Date: Fri, 3 Feb 2023 17:07:14 +0100 Subject: [PATCH] feat: disable canvas smoothing (antialiasing) for right-angled elements (#6186)Co-authored-by: Ignacio Cuadra <67276174+ignacio-cuadra@users.noreply.github.com> * feat: disable canvas smoothing for text and other types * disable smoothing for all right-angled elements * Update src/renderer/renderElement.ts Co-authored-by: Ignacio Cuadra <67276174+ignacio-cuadra@users.noreply.github.com> * Update src/renderer/renderElement.ts Co-authored-by: Ignacio Cuadra <67276174+ignacio-cuadra@users.noreply.github.com> * fix lint * always enable smoothing while zooming --------- Co-authored-by: Ignacio Cuadra <67276174+ignacio-cuadra@users.noreply.github.com> --- src/math.ts | 12 ++++++++++++ src/renderer/renderElement.ts | 28 +++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/math.ts b/src/math.ts index 2deb221b..cfa28e23 100644 --- a/src/math.ts +++ b/src/math.ts @@ -459,3 +459,15 @@ export const mapIntervalToBezierT = ( export const arePointsEqual = (p1: Point, p2: Point) => { return p1[0] === p2[0] && p1[1] === p2[1]; }; + +export const isRightAngle = (angle: number) => { + // if our angles were mathematically accurate, we could just check + // + // angle % (Math.PI / 2) === 0 + // + // but since we're in floating point land, we need to round. + // + // Below, after dividing by Math.PI, a multiple of 0.5 indicates a right + // angle, which we can check with modulo after rounding. + return Math.round((angle / Math.PI) * 10000) % 5000 === 0; +}; diff --git a/src/renderer/renderElement.ts b/src/renderer/renderElement.ts index f77a8c48..39173d7b 100644 --- a/src/renderer/renderElement.ts +++ b/src/renderer/renderElement.ts @@ -27,7 +27,7 @@ import { RoughGenerator } from "roughjs/bin/generator"; import { RenderConfig } from "../scene/types"; import { distance, getFontString, getFontFamilyString, isRTL } from "../utils"; -import { getCornerRadius, isPathALoop } from "../math"; +import { getCornerRadius, isPathALoop, isRightAngle } from "../math"; import rough from "roughjs/bin/rough"; import { AppState, BinaryFiles, Zoom } from "../types"; import { getDefaultAppState } from "../appState"; @@ -989,7 +989,33 @@ export const renderElement = ( element, renderConfig, ); + + const currentImageSmoothingStatus = context.imageSmoothingEnabled; + + if ( + // do not disable smoothing during zoom as blurry shapes look better + // on low resolution (while still zooming in) than sharp ones + !renderConfig?.shouldCacheIgnoreZoom && + // angle is 0 -> always disable smoothing + (!element.angle || + // or check if angle is a right angle in which case we can still + // disable smoothing without adversely affecting the result + isRightAngle(element.angle)) + ) { + // Disabling smoothing makes output much sharper, especially for + // text. Unless for non-right angles, where the aliasing is really + // terrible on Chromium. + // + // Note that `context.imageSmoothingQuality="high"` has almost + // zero effect. + // + context.imageSmoothingEnabled = false; + } + drawElementFromCanvas(elementWithCanvas, rc, context, renderConfig); + + // reset + context.imageSmoothingEnabled = currentImageSmoothingStatus; } break; }