绘制
2024年06月19日
一、认识
注意: canvas
绘图时, 会从两个物理像素的中间位置开始绘制并向两边扩散 0.5
个物理像素。当设备像素比为 1
时,一个 1px
的线条实际上占据了两个物理像素(每个像素实际上只占一半),由于不存在 0.5
个像素,所以这两个像素本来不应该被绘制的部分也被绘制了,于是 1
物理像素的线条变成了 2
物理像素,视觉上就造成了模糊。
解决: 设置 Canvas
的缩放比例,确保在高密度屏幕上有更好的显示效果
二、关闭抗锯齿
context.mozImageSmoothingEnabled = false;
context.webkitImageSmoothingEnabled = false;
context.msImageSmoothingEnabled = false;
context.imageSmoothingEnabled = false;
三、 获取 Canvas
缩放比例
const getPixelRatio = (context)=>{
const backingStore = context.backingStorePixelRatio ||
context.webkitBackingStorePixelRatio ||
context.mozBackingStorePixelRatio ||
context.msBackingStorePixelRatio ||
context.oBackingStorePixelRatio ||
context.backingStorePixelRatio || 1;
return (window.devicePixelRatio || 1) / backingStore;
}
-
devicePixelRatio
: 用于表示设备上物理像素与CSS
像素之间比率的属性。它告诉你在渲染页面时,一个CSS
像素对应多少个物理像素。例如,如果devicePixelRatio
的值为2
,表示每个CSS
像素对应设备上的2
个物理像素,这通常出现在高密度屏幕(如Retina
屏幕)上。 -
backingStorePixelRatio
: 用于表示绘图表面(如Canvas
)的缓冲区像素比率。这个属性通常用于在高分辨率设备上绘制图形时,确保图形质量和性能的平衡。在Retina
屏幕上,使用这个属性可以绘制高清晰度的图形,而不会降低性能。
四、基于 Canvas
缩放比例, 绘制图像
const draw = config => {
const { canvas, context, imgEl, width, height, ratio } = config;
canvas.width = width * ratio;
canvas.height = height * ratio;
context.drawImage(imgEl, 0, 0);
};
五、完整代码
index.html
<div class="input-container">
<img id="input-img" src="" />
<input type="file" id="input-file" accept="image/*" />
</div>
<div class="output-container">
<canvas id="output-canvas"></canvas>
</div>
<script src="./index.js"></script>
index.js
const getPixelRatio = context => {
const backingStore =
context.backingStorePixelRatio ||
context.webkitBackingStorePixelRatio ||
context.mozBackingStorePixelRatio ||
context.msBackingStorePixelRatio ||
context.oBackingStorePixelRatio ||
context.backingStorePixelRatio ||
1;
return (window.devicePixelRatio || 1) / backingStore;
};
const draw = config => {
const { canvas, context, imgEl, width, height, ratio } = config;
context.mozImageSmoothingEnabled = false;
context.webkitImageSmoothingEnabled = false;
context.msImageSmoothingEnabled = false;
context.imageSmoothingEnabled = false;
canvas.width = width * ratio;
canvas.height = height * ratio;
context.drawImage(imgEl, 0, 0);
};
const inputImgEl = document.querySelector('#input-img');
const inputFileEl = document.querySelector('#input-file');
const outputCanvasEl = document.querySelector('#output-canvas');
const outputCanvasCtx = outputCanvasEl.getContext('2d');
const ratio = getPixelRatio(outputCanvasCtx);
inputFileEl.addEventListener('change', e => {
const file = e.target.files[0];
inputImgEl.src = URL.createObjectURL(file);
});
inputImgEl.addEventListener('load', () => {
const ratio = getPixelRatio(outputCanvasCtx);
draw({
ratio,
imgEl: inputImgEl,
canvas: outputCanvasEl,
context: outputCanvasCtx,
width: inputImgEl.naturalWidth,
height: inputImgEl.naturalHeight
});
});