web: the upscale drops its tile seams
A tile's destination rectangle was placed at x0 * scale, and that scale is rarely whole, so every 256px boundary landed on a fraction of a pixel. The edge was drawn half covered, stayed transparent, and the JPEG export flattened that transparency onto black: a dark line down each seam. Snap both destination edges to whole pixels instead, so neighbouring tiles share the exact same boundary, and make the destination context opaque so no partly covered pixel can survive as transparency again. Measured on a 640px source: the seam at 2K was 46 levels darker than its neighbours (96 at 4K); it is now within one level of them.
This commit is contained in:
@@ -78,7 +78,9 @@ export async function upscaleJpeg(
|
||||
const srcCanvas = new OffscreenCanvas(w, h);
|
||||
const srcCtx = srcCanvas.getContext('2d', { willReadFrequently: true });
|
||||
const dstCanvas = new OffscreenCanvas(Math.max(1, Math.round(w * scale)), Math.max(1, Math.round(h * scale)));
|
||||
const dstCtx = dstCanvas.getContext('2d');
|
||||
// Opaque: a partly covered edge pixel would otherwise survive as transparency
|
||||
// and the JPEG export flattens that onto black — a dark line down every seam.
|
||||
const dstCtx = dstCanvas.getContext('2d', { alpha: false });
|
||||
if (!srcCtx || !dstCtx) return bytes;
|
||||
srcCtx.drawImage(bitmap, 0, 0);
|
||||
const src = srcCtx.getImageData(0, 0, w, h);
|
||||
@@ -138,16 +140,22 @@ export async function upscaleJpeg(
|
||||
img.data[d + 3] = 255;
|
||||
}
|
||||
tileCtx.putImageData(img, 0, 0);
|
||||
// Destination edges snapped to whole pixels: neighbouring tiles then share
|
||||
// the exact same boundary, so nothing is left half-covered (and half-black)
|
||||
// where they meet. `scale` is rarely an integer, so `x0 * scale` alone
|
||||
// lands on a fraction and antialiases the seam.
|
||||
const dx0 = Math.round(x0 * scale);
|
||||
const dy0 = Math.round(y0 * scale);
|
||||
dstCtx.drawImage(
|
||||
tile,
|
||||
left * MODEL_SCALE,
|
||||
top * MODEL_SCALE,
|
||||
tw * MODEL_SCALE,
|
||||
th * MODEL_SCALE,
|
||||
x0 * scale,
|
||||
y0 * scale,
|
||||
tw * scale,
|
||||
th * scale
|
||||
dx0,
|
||||
dy0,
|
||||
Math.round((x0 + tw) * scale) - dx0,
|
||||
Math.round((y0 + th) * scale) - dy0
|
||||
);
|
||||
|
||||
done++;
|
||||
|
||||
Reference in New Issue
Block a user