What you are experiencing is the difference between your screen's PPI and your printer's DPI.
Canvas output is a raster image, if you set its size to be like 96px, a monitor with a resolution of 96ppi will output it as a one inch large image, but a printer with 300ppi will output it as a 3.125 inch image.
When doing so, the printing operation will downsample your image so it can fit into this new size. (each pixel will be multiplied so it covers a bigger area).
But the canvas context2d has a scale()
method, so if all your drawings are vector based1, you can :
- create a bigger canvas before printing,
- set its context's scale to the wanted factor,
- call the same drawing as on the smaller canvas
- if you are printing directly from the browser's "print the page", set the bigger canvas
style.width
and style.height
properties to the width
and height
properties of the smaller one,
- replace the smaller canvas node with the bigger one,
- print,
- replace the bigger canvas with the original one
For this, you will need to rewrite a little bit your function so it doesn't take the passed canvas' width/height as values, but rather values that you have chosen.
function drawBkg(ctx, width, height, squareSize, minorLineWidthStr, lineColStr) {
var nLinesDone = 0;
var i, curX, curY;
ctx.clearRect(0, 0, width, height);
// draw the vertical lines
curX = 0;
ctx.strokeStyle = lineColStr;
while (curX < width) {
if (nLinesDone % 5 == 0)
ctx.lineWidth = 0.7;
else
ctx.lineWidth = minorLineWidthStr;
ctx.beginPath();
ctx.moveTo(curX, 0);
ctx.lineTo(curX, height);
ctx.stroke();
curX += squareSize;
nLinesDone++;
}
// draw the horizontal lines
curY = 0;
nLinesDone = 0;
while (curY < height) {
if (nLinesDone % 5 == 0)
ctx.lineWidth = 0.7;
else
ctx.lineWidth = minorLineWidthStr;
ctx.beginPath();
ctx.moveTo(0, curY);
ctx.lineTo(width, curY);
ctx.stroke();
curY += squareSize;
nLinesDone++;
}
}
// your drawings
var smallCanvas = document.getElementById('smallCanvas');
var smallCtx = smallCanvas.getContext('2d');
drawBkg(smallCtx, smallCanvas.width, smallCanvas.height, 3.78, "0.35", "green");
// a function to get the screen's ppi
function getPPI() {
var test = document.createElement('div');
test.style.width = "1in";
test.style.height = 0;
document.body.appendChild(test);
var dpi = devicePixelRatio || 1;
var ppi = parseInt(getComputedStyle(test).width) * dpi;
document.body.removeChild(test);
return ppi;
}
function scaleAndPrint(outputDPI) {
var factor = outputDPI / getPPI();
var bigCanvas = smallCanvas.cloneNode();
// set the required size of our "printer version" canvas
bigCanvas.width = smallCanvas.width * factor;
bigCanvas.height = smallCanvas.height * factor;
// set the display size the same as the original one to don't brake the page's layout
var rect = smallCanvas.getBoundingClientRect();
bigCanvas.style.width = rect.width + 'px';
bigCanvas.style.height = rect.height + 'px';
var bigCtx = bigCanvas.getContext('2d');
// change the scale of our big context
bigCtx.scale(factor, factor);
// tell the function we want the height and width of the small canvas
drawBkg(bigCtx, smallCanvas.width, smallCanvas.height, 3.78, "0.35", "green");
// replace our original canvas with the bigger one
smallCanvas.parentNode.replaceChild(bigCanvas, smallCanvas);
// call the printer
print();
// set the original one back
bigCanvas.parentNode.replaceChild(smallCanvas, bigCanvas);
}
btn_o.onclick = function() { print(); };
btn_s.onclick = function() { scaleAndPrint(300);};
<button id="btn_o">print without scaling</button>
<button id="btn_s">print with scaling</button>
<br>
<canvas id="smallCanvas" width="250" height="500"></canvas>
1. all drawing operations on canvas are vector based, except for drawImage()
, and putImageData()