You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 20:25:40