使用HTML5画布的DPI图形更高

red*_*lue 13 javascript html5 canvas html5-canvas

有没有办法在使用HTML5画布创建图像时设置自定义DPI/PPI?我知道如何在画布上绘制并将其导出为图像,但如何确保输出图像具有某些DPI/PPI.我想使用SVG元素在画布上绘制是一种方式,但是当我将整个画布作为图像导出时,这不会被弄平吗?或者计算设备DPI然后缩放图像以满足我的DPI要求,但这似乎不是正确的解决方案.

Eri*_*ans 46

画布有两种不同的"尺寸":它们的DOM宽度/高度和它们的CSS宽度/高度.您可以通过增加DOM大小来增加画布的分辨率,同时保持CSS大小不变,然后使用.scale()方法将所有未来的绘制扩展到新的更大的大小.这是一个例子:

function changeResolution(canvas, scaleFactor) {
    // Set up CSS size.
    canvas.style.width = canvas.style.width || canvas.width + 'px';
    canvas.style.height = canvas.style.height || canvas.height + 'px';

    // Resize canvas and scale future draws.
    canvas.width = Math.ceil(canvas.width * scaleFactor);
    canvas.height = Math.ceil(canvas.height * scaleFactor);
    var ctx = canvas.getContext('2d');
    ctx.scale(scaleFactor, scaleFactor);
}
Run Code Online (Sandbox Code Playgroud)

画布默认分辨率为96dpi(CSS英寸,不基于实际屏幕).所以scaleFactor为2给出了192dpi,3为288dpi等等.事实上,这是一个应该给出你想要的DPI的版本:

function setDPI(canvas, dpi) {
    // Set up CSS size.
    canvas.style.width = canvas.style.width || canvas.width + 'px';
    canvas.style.height = canvas.style.height || canvas.height + 'px';

    // Resize canvas and scale future draws.
    var scaleFactor = dpi / 96;
    canvas.width = Math.ceil(canvas.width * scaleFactor);
    canvas.height = Math.ceil(canvas.height * scaleFactor);
    var ctx = canvas.getContext('2d');
    ctx.scale(scaleFactor, scaleFactor);
}
Run Code Online (Sandbox Code Playgroud)

玩得开心!请注意,这两个代码示例只能在每个画布上使用一次,它们假设当前的DOM大小是原始的(可以调整它们来改变它).在画布上进行任何绘制之前,还需要进行重新缩放.感谢这篇文章的方法和信息!

编辑:这是一个更强大的功能,可以扩展未来的绘制维护现有的画布内容.可以调用此方法多次重新缩放.

function setDPI(canvas, dpi) {
    // Set up CSS size.
    canvas.style.width = canvas.style.width || canvas.width + 'px';
    canvas.style.height = canvas.style.height || canvas.height + 'px';

    // Get size information.
    var scaleFactor = dpi / 96;
    var width = parseFloat(canvas.style.width);
    var height = parseFloat(canvas.style.height);

    // Backup the canvas contents.
    var oldScale = canvas.width / width;
    var backupScale = scaleFactor / oldScale;
    var backup = canvas.cloneNode(false);
    backup.getContext('2d').drawImage(canvas, 0, 0);

    // Resize the canvas.
    var ctx = canvas.getContext('2d');
    canvas.width = Math.ceil(width * scaleFactor);
    canvas.height = Math.ceil(height * scaleFactor);

    // Redraw the canvas image and scale future draws.
    ctx.setTransform(backupScale, 0, 0, backupScale, 0, 0);
    ctx.drawImage(backup, 0, 0);
    ctx.setTransform(scaleFactor, 0, 0, scaleFactor, 0, 0);
}
Run Code Online (Sandbox Code Playgroud)

  • 这个答案应该标记为正确的答案.这里唯一的问题是没有办法用配置的DPI导出这个画布,所以在调用toDataUrl后,图像尺寸将跟随scaleFactor,但PNG图像的分辨率仍然是96(或等于设备DPI).导出为高分辨率图像toDataURLHD的功能将作为HTML5.1的一部分提供,目前PNG分辨率只能在服务器上更改.如何使用改变分辨率的C#在服务器上缩放图像的好例子可以在http://stackoverflow.com/questions/1922040/resize-an-image-c-sharp找到. (6认同)

Mik*_*maa 4

您无法(呃)在任何浏览器中访问当前网页显示的 DPI:

从 JS/CSS 检测系统 DPI/PPI?

对于打印:您很可能无法使用浏览器标准功能设置导出图像(PNG、JPEG)的 DPI <canvas>。但是,如果您使用纯 Javascript 编码器图像编码器,您可以自由创建您希望的任何类型的二进制文件,并手动调整嵌入到二进制文件中的 DPI 值。

https://gist.github.com/1245476

  • 这个答案不再正确。`window.devicePixelRatio` 为您提供 DPI。 (9认同)
  • 比为 PNG/JPEG 进行整个编码器更好的是,使用本机编码器,然后重写标头中定义像素密度元数据的字节。在 PNG 中,它是 pHY 块 [必须通过将画布转换为 blob 并将块切片来注入],而在 JPEG 中,它更容易,因为您只需重写位 13-16。 (2认同)