Javascript 带有 HTML5 画布的更高 DPI 图形
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14488849/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Higher DPI graphics with HTML5 canvas
提问by redGREENblue
Is there a way to set a custom DPI/PPI when creating an image using the HTML5 canvas? I know how can I draw on the canvas and export it as an image, but how can I make sure the output image is of certain DPI/PPI. I guess using SVG elemnts to draw on the canvas is a way, but wouldn't that be flattened out when I export the whole canvas as an image? Or calculating the device DPI and then scaling the image to meet my DPI requirement, but that doesn't seem like the correct solution.
有没有办法在使用 HTML5 画布创建图像时设置自定义 DPI/PPI?我知道如何在画布上绘制并将其导出为图像,但如何确保输出图像具有特定的 DPI/PPI。我想使用 SVG 元素在画布上绘制是一种方法,但是当我将整个画布导出为图像时,这会不会变平?或者计算设备 DPI,然后缩放图像以满足我的 DPI 要求,但这似乎不是正确的解决方案。
采纳答案by Mikko Ohtamaa
You cannot (ugh) access the DPI of a display of the current web page in any browser:
您无法(呃)在任何浏览器中访问当前网页显示的 DPI:
Detecting the system DPI/PPI from JS/CSS?
For printing: You most likely cannot set the DPI of exported <canvas>image (PNG, JPEG) using browser standard functions. However, if you use a pure Javascript encoder image encoder you are free to create any sort of binary file you wish and manually adjust the DPI value embedded int he binary.
对于打印:您很可能无法<canvas>使用浏览器标准功能设置导出图像(PNG、JPEG)的 DPI 。但是,如果您使用纯 Javascript 编码器图像编码器,您可以自由创建您希望的任何类型的二进制文件,并手动调整嵌入在二进制文件中的 DPI 值。
回答by Erik Koopmans
Canvases have two different 'sizes': their DOM width/height and their CSS width/height. You can increase a canvas' resolution by increasing the DOM size while keeping the CSS size fixed, and then using the .scale() method to scale all of your future draws to the new bigger size. Here's an example:
画布有两种不同的“尺寸”:它们的 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);
}
The canvas default resolution is 96dpi (CSS inches, not based on the actual screen). So a scaleFactor of 2 gives 192dpi, 3 is 288dpi, etc. In fact, here's a version that should give your desired DPI:
画布默认分辨率为 96dpi(CSS 英寸,不基于实际屏幕)。所以 2 的 scaleFactor 是 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);
}
Have fun! Note that both these code samples can only be used once per canvas, they assume the current DOM size is the original (they could be tweaked to change that). Also the rescaling needs to happen beforeyou do any drawing on the canvas. Thanks to this postfor the method and information!
玩得开心!请注意,这两个代码示例只能在每个画布上使用一次,它们假定当前 DOM 大小是原始大小(可以对其进行调整以更改)。此外,在您在画布上进行任何绘图之前,需要进行重新缩放。感谢这篇文章的方法和信息!
Edit:Here is a more robust function that will scale future draws andmaintain existing canvas contents. This can be called to rescale multiple times.
编辑:这是一个更强大的功能,可以扩展未来的绘图并维护现有的画布内容。这可以被调用以多次重新缩放。
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);
}
回答by murkle
If you just want to set the dpi of the PNG (ie not increase the number of pixels) then this library lets you set the pHYschunk (amongst other things):
如果您只想设置 PNG 的 dpi(即不增加像素数),那么此库可让您设置pHYs块(除其他外):
https://github.com/imaya/CanvasTool.PngEncoder
https://github.com/imaya/CanvasTool.PngEncoder
Minimal example to export an HTML5 canvas to base64-encoded PNG:
将 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);
回答by Stefan
Use the library changedpi:
使用库changedpi:
npm install changedpi --save
Also see
另见
Example code that also allows to adapt the px size and resolution for png or jpg export:
还允许调整 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;
}
}

