HTML5 Canvas绘制图像模糊/挤压问题技术求助
解决HTML5 Canvas图像自适应模糊/挤压问题
问题描述
在HTML5 Canvas中绘制图像,期望图像自适应画布以适配不同屏幕分辨率,但绘制后的图像出现模糊或被挤压的现象,直接查看原图画质清晰。原实现代码如下:
原JavaScript代码
function drawImageScaled(img, ctx) { var canvas = ctx.canvas; var hRatio = canvas.width / img.width; var vRatio = canvas.height / img.height; var ratio = Math.min(hRatio, vRatio); var centerShift_x = (canvas.width - img.width * ratio) / 2; var centerShift_y = (canvas.height - img.height * ratio) / 2; ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.drawImage(img, 0, 0, img.width, img.height, centerShift_x, centerShift_y, img.width * ratio, img.height * ratio); } function draw() { var ctx = document.getElementById('floor_canvas'); if (ctx.getContext) { ctx = ctx.getContext('2d'); var bg_img = new Image(); bg_img.onload = function() { drawImageScaled(bg_img, ctx); }; bg_img.src = 'https://i.sstatic.net/FTm9g.jpg'; //'floor_plan/floor_1.jpg'; } } draw();
原CSS代码
#floor_canvas { width: 100%; height: 100vh; }
原HTML代码
<canvas id="floor_canvas"></canvas>
原因分析
- Canvas像素尺寸与显示尺寸不匹配:Canvas的
width/height属性是它的实际像素画布尺寸,而CSS设置的width/height是显示尺寸。原代码只通过CSS将Canvas设为全屏,但未设置Canvas自身的width/height属性,导致Canvas使用默认的300x150像素尺寸,再被CSS拉伸到屏幕大小,图像先缩放到小尺寸画布再被放大,自然模糊。 - 未适配高DPI屏幕:高清屏的设备像素比(
devicePixelRatio)大于1,不处理的话,Canvas的像素密度跟不上屏幕,图像会显得模糊。 - 比例计算基于错误尺寸:原缩放逻辑用Canvas默认的小尺寸计算比例,和实际显示尺寸不匹配,导致图像比例错误出现挤压。
解决方案
调整代码,同步Canvas实际像素尺寸与显示尺寸,适配高DPI屏幕,并监听窗口变化保持自适应:
修改后的完整代码
function drawImageScaled(img, ctx) { const canvas = ctx.canvas; // 获取Canvas的实际显示尺寸 const displayWidth = canvas.clientWidth; const displayHeight = canvas.clientHeight; // 获取设备像素比,适配高DPI屏幕 const dpr = window.devicePixelRatio || 1; // 设置Canvas的实际像素尺寸,确保和显示尺寸匹配 canvas.width = displayWidth * dpr; canvas.height = displayHeight * dpr; // 缩放绘图上下文,让坐标适配高DPI ctx.scale(dpr, dpr); // 基于显示尺寸计算缩放比例,保证图像比例正确 const hRatio = displayWidth / img.width; const vRatio = displayHeight / img.height; const ratio = Math.min(hRatio, vRatio); const centerShift_x = (displayWidth - img.width * ratio) / 2; const centerShift_y = (displayHeight - img.height * ratio) / 2; ctx.clearRect(0, 0, displayWidth, displayHeight); ctx.drawImage(img, 0, 0, img.width, img.height, centerShift_x, centerShift_y, img.width * ratio, img.height * ratio); } function draw() { const canvas = document.getElementById('floor_canvas'); if (!canvas.getContext) return; const ctx = canvas.getContext('2d'); const bg_img = new Image(); bg_img.onload = function() { drawImageScaled(bg_img, ctx); }; bg_img.src = 'https://i.sstatic.net/FTm9g.jpg'; } // 初始化绘制 draw(); // 监听窗口大小变化,重新绘制图像保持自适应 window.addEventListener('resize', draw);
修改说明
- 同步Canvas实际像素尺寸与显示尺寸:通过
clientWidth/clientHeight获取Canvas的显示大小,结合设备像素比设置width/height属性,避免图像被拉伸模糊。 - 适配高DPI屏幕:使用
ctx.scale(dpr, dpr)让绘图坐标和屏幕显示坐标一致,保证高清屏上图像清晰。 - 基于显示尺寸计算比例:确保图像按正确的比例缩放,不会出现挤压变形。
- 添加窗口监听:屏幕尺寸变化时自动重新绘制,保持图像始终自适应。
内容的提问来源于stack exchange,提问作者Vpp Man
相关产品推荐
相关产品推荐

