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

为何canvg配置中scaleWidth与scaleHeight需设为400?如何缩至40?

问题描述

我尝试将宽高约44像素的SVG渲染为40像素的尺寸,但发现必须把canvg preset中的scaleWidth和scaleHeight设为400才能接近预期效果。根据官方文档描述,这两个属性是用于将SVG分别按水平、垂直方向缩放到指定宽度和高度,我本应设置preset.scaleWidth = 40;和preset.scaleHeight = 40;,但实际却不是这样。请问该如何正确理解这些属性,以实现将SVG渲染为40像素宽高的需求?

代码示例

主页面JavaScript代码

const svg = `<svg xmlns="http://www.w3.org/2000/svg" fill="#ff0000" viewBox="0 0 512 512"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M256 0c17.7 0 32 14.3 32 32l0 10.4c93.7 13.9 167.7 88 181.6 181.6l10.4 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-10.4 0c-13.9 93.7-88 167.7-181.6 181.6l0 10.4c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-10.4C130.3 455.7 56.3 381.7 42.4 288L32 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l10.4 0C56.3 130.3 130.3 56.3 224 42.4L224 32c0-17.7 14.3-32 32-32zM107.4 288c12.5 58.3 58.4 104.1 116.6 116.6l0-20.6c0-17.7 14.3-32 32-32s32 14.3 32 32l0 20.6c58.3-12.5 104.1-58.4 116.6-116.6L384 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l20.6 0C392.1 165.7 346.3 119.9 288 107.4l0 20.6c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-20.6C165.7 119.9 119.9 165.7 107.4 224l20.6 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-20.6 0zM256 224a32 32 0 1 1 0 64 32 32 0 1 1 0-64z"/></svg>`;

var blob = new Blob(
  Array.prototype.map.call(
    document.querySelectorAll('script[type="text/js-worker"]'),
    function (oScript) {
      return oScript.textContent;
    }
  ),
  { type: "text/javascript" }
);

const worker = new Worker(window.URL.createObjectURL(blob), {
  type: "module"
});

const img = document.querySelector("img");

worker.postMessage({svg: svg});

worker.onmessage = (event) => {
  img.src = event.data.pngUrl;
};

Worker脚本代码

<script type="text/js-worker">
  import { DOMParser } from 'https://cdn.skypack.dev/@xmldom/xmldom@^0.7.5'
  import {
    Canvg,
    presets
  } from 'https://cdn.skypack.dev/canvg@^4.0.0'

  const preset = presets.offscreen({
    DOMParser
  })

  preset.ignoreClear = true;
  preset.scaleWidth = 400;
  preset.scaleHeight = 400;
  
  self.onmessage = async (event) => {
    const { svg } = event.data;
    
    const radius = 28;
    const canvas = new OffscreenCanvas( radius * 2, radius * 2 ); // width, height
    const ctx = canvas.getContext( '2d' );
    
    ctx.beginPath();
    ctx.arc(radius, radius, radius, 0, 2 * Math.PI);
    ctx.fillStyle = 'blue';
    ctx.fill();
    
    const v = await Canvg.from(ctx, svg, preset)
    await v.render()

    const blob = await canvas.convertToBlob()
    const pngUrl = URL.createObjectURL(blob)

    self.postMessage({
      pngUrl
    })
  }
</script>

<img />
问题分析与解决方案

正确理解scaleWidth/scaleHeight

这两个属性的作用是将SVG的viewBox所定义的逻辑内容,缩放到canvas坐标系中的指定宽高(单位为像素,与canvas实际像素尺寸一一对应)。你的SVGviewBox是0 0 512 512,意味着SVG的原始逻辑尺寸是512x512单位,设置scaleWidth=40就会把这512单位的内容缩放到40像素宽,刚好匹配你的需求。

之前设置400能接近预期是因为:你的canvas实际尺寸是56x56像素,400/512≈0.781的缩放比例,56*0.781≈44,刚好是你提到的“约44像素的SVG”,但这并非目标的40px。

实现40px尺寸的具体修改

方案1:保持现有56x56画布,居中渲染40px SVG

修改Worker脚本中的preset参数,设置正确的缩放和偏移量:

preset.scaleWidth = 40;
preset.scaleHeight = 40;
preset.offsetX = (56 - 40)/2; // 水平居中偏移8px
preset.offsetY = (56 - 40)/2; // 垂直居中偏移8px

修改后的Worker脚本完整代码:

<script type="text/js-worker">
  import { DOMParser } from 'https://cdn.skypack.dev/@xmldom/xmldom@^0.7.5'
  import {
    Canvg,
    presets
  } from 'https://cdn.skypack.dev/canvg@^4.0.0'

  const preset = presets.offscreen({
    DOMParser
  })

  preset.ignoreClear = true;
  preset.scaleWidth = 40;
  preset.scaleHeight = 40;
  preset.offsetX = 8;
  preset.offsetY = 8;
  
  self.onmessage = async (event) => {
    const { svg } = event.data;
    
    const radius = 28;
    const canvas = new OffscreenCanvas( radius * 2, radius * 2 );
    const ctx = canvas.getContext( '2d' );
    
    ctx.beginPath();
    ctx.arc(radius, radius, radius, 0, 2 * Math.PI);
    ctx.fillStyle = 'blue';
    ctx.fill();
    
    const v = await Canvg.from(ctx, svg, preset)
    await v.render()

    const blob = await canvas.convertToBlob()
    const pngUrl = URL.createObjectURL(blob)

    self.postMessage({
      pngUrl
    })
  }
</script>

方案2:直接使用40x40画布,SVG占满整个画布

如果不需要蓝色圆形的56px尺寸,可以直接将画布改为40x40,此时无需偏移:

// 修改画布尺寸
const canvas = new OffscreenCanvas(40, 40);
// 若不需要蓝色圆形,可移除以下绘制代码
// ctx.beginPath(); ... ctx.fill();

这样设置scaleWidth=40和scaleHeight=40后,SVG会直接占满整个40px的画布,完全符合你的需求。


内容的提问来源于stack exchange,提问作者Eric G

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 12:52:03