使用 HTML5 画布实现更高 DPI 图形

问题描述 投票:0回答:5

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

javascript html canvas html5-canvas
5个回答
75
投票

画布有两种不同的“尺寸”:它们的 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);
}

画布默认分辨率为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);
}

玩得开心!请注意,这两个代码示例在每个画布上只能使用一次,它们假设当前 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); }



4
投票

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

对于打印:您很可能无法使用浏览器标准功能设置导出的

<canvas>

图像(PNG、JPEG)的 DPI。但是,如果您使用纯 Javascript 编码器图像编码器,您可以自由创建您希望的任何类型的二进制文件,并手动调整嵌入到二进制文件中的 DPI 值。


https://gist.github.com/1245476


2
投票
pHYs

块(除其他外):

https://github.com/imaya/CanvasTool.PngEncoder

将 HTML5 画布导出为 Base64 编码的 PNG 的最小示例:

// convert dots per inch into dots per metre var pixelsPerM = dpi * 100 / 2.54; var param = { bitDepth : 8, colourType : 2, filterType : 0, height : canvas.height, interlaceMethod : 0, phys : { unit : 1, x : pixelsPerM, y : pixelsPerM }, width : canvas.width }; var array = canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height).data; var png = new window.CanvasTool.PngEncoder(array, param).convert(); var base64 = 'data:image/png;base64,' + btoa(png);



0
投票

例如,如果设备像素比为2,CSS中画布为600x400像素,则画布实际大小应为1200x800像素,画布上下文比例应为2。

<style> canvas { width: 600px; height: 400px; } </style> <canvas></canvas>

const canvas = document.querySelector('canvas')
const ctx = canvas.getContext('2d')
const dpr = window.devicePixelRatio || 2

const { width, height } = canvas.getBoundingClientRect()

if (canvas.width !== width * dpr || canvas.height !== height * dpr) {
  canvas.width = width * dpr // 600 x 2 = 1200
  canvas.height = height * dpr // 400 x 2 = 800
}

// Reset scale to identical matrix to allow multiple re-scales.
ctx.setTransform(1, 0, 0, 1, 0, 0)

ctx.scale(dpr, dpr)
现在,绘图将缩放至指定的设备像素比。

画布 CSS 宽度和高度可以制作
    100%
  • 并在调整大小时使用
    ResizeObserver
    进行计算。 调整大小和缩放定义应在渲染前完成一次。

-2
投票

npm install changedpi --save

另请参阅

    https://github.com/shutterstock/changeDPI
  • https://github.com/hongru/canvas2image
  • 还允许调整 px 大小和分辨率以导出 png 或 jpg 的示例代码:

Canvas2Image.saveAsImage('fileName.png', canvas, 2000, 3000, 300, 'png');

-

import Url from './url'; import * as ChangeDpi from 'changeDPI'; export default class Canvas2Image { static saveAsImage(fileName, canvas, width, height, dpi, type) { type = this._fixType(type); canvas = this._scaleCanvas(canvas, width, height); let dataUrl = canvas.toDataURL(type); let dataUrlWithDpi = ChangeDpi.changeDpiDataUrl(dataUrl, dpi) dataUrlWithDpi = dataUrlWithDpi.replace(type, 'image/octet-stream'); Url.download(fileName, dataUrlWithDpi); } static _fixType(type) { type = type.toLowerCase().replace(/jpg/i, 'jpeg'); const r = type.match(/png|jpeg|bmp|gif/)[0]; return `image/${r}`; } static _scaleCanvas(canvas, width, height) { const w = canvas.width; const h = canvas.height; if (width === undefined) { width = w; } if (height === undefined) { height = h; } const retCanvas = document.createElement('canvas'); const retCtx = retCanvas.getContext('2d'); retCanvas.width = width; retCanvas.height = height; retCtx.drawImage(canvas, 0, 0, w, h, 0, 0, width, height); return retCanvas; } }

-

export default class Url { static download(fileName, url) { const element = document.createElement('a'); element.setAttribute('href', url); element.setAttribute('download', fileName); element.style.display = 'none'; document.body.appendChild(element); element.click(); document.body.removeChild(element); } static createUrlForBlob(blob) { return this._URL.createObjectURL(blob); } static clearBlobUrl(blobUrl) { this._URL.revokeObjectURL(blobUrl); } static get _URL() { return window.URL || window.webkitURL || window; } }

© www.soinside.com 2019 - 2024. All rights reserved.