Closed ewanhowell5195 closed 2 years ago
This seems to be a known issue with Skia itself—specifically that it doesn't use a high-quality image filter when downscaling images, despite doing so when upscaling. I've tried fiddling with the SamplingOptions values that are used for the different imageSmoothingQuality
settings, but (as described in this discussion and this one) the cubic resampler is only applied when upsampling. Unfortunately, enabling bi-linear filtering didn't have a noticeable effect against your sample code.
SkiaSharp has also been wrestling with the for some time.
So if there is a solution to this problem, it's going to be more complicated. Some possibilities that might be worth investigating:
In the meantime, the best workaround might be to generate an interim bitmap of your canvas at a higher resolution (e.g., using 3 or 4 for the density
export argument), then scale that image down to your desired size:
const img = await loadImage("squares.png")
const canvas = new Canvas(256, 256)
const ctx = canvas.getContext("2d")
ctx.setTransform(ctx.createProjection([65, 10, 212, 112, 250, 200, 0, 256]))
ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
let snapshot = await canvas.toBuffer('png', {density:4})
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.resetTransform()
ctx.drawImage(await loadImage(snapshot), 0, 0, canvas.width, canvas.height)
canvas.saveAs("out.png")
Left image produced using skia-canvas, right image using ImageMagick The outer edge of the image seems to work correctly however
Changing the imageSmoothingQuality doesn't seem to improve anything
This doesn't seem to affect drawing things like rectangles and text, only images and canvases
The higher resolution the input image, the worse it gets
256x265 input image
1024x1024 input image
Code i tested with: