There may be two more known problems (I believe there is another problem with similar sources, but it does not seem to be the case):
Problem with retinal screen
Retinal screen or Retinal screen (european portuguese) or Retina Display (english) are used LCD (Apple) screens that feature sufficient pixel density for the human eye not to be able to perceive pixelation at a standard distance, used in Apple products like iPhone and Mac.
Usually the content displayed on the screen has on average the "double" size that appears, that is and we usually have to use high-quality images so that they do not present the blurred effect ("blurry").
The moment you use the html2canvas
on the retina screen, what is presented to you is an image that would be only noticeable to the pixels. This seems to be a problem of Canvas API
trying to adjust the image when exporting it.
Chrome/Safari bug with background images on Windows 64bit
Note: Apparently this bug has been fixed in the latest versions of Chromium
I don’t remember if the problem occurs in Safari, but in Chrome and Opera (Chromium/Blink technology) this occurs. It’s a bug in Canvas API
also, which usually occurs when the image has different element size (for example a DIV).
Let’s assume we have a 100x100 image call test png. one <div>
thus:
<style>
.foo {
width: 200px;
height: 200px;
background: url(test.png) no-repeat;
}
</style>
If your Chrome is 32bit running on a 64bit system there is a blur effect, see an example (as I mentioned here #206):
function putImage()
{
//Funciona-----------------------
var canvas=document.getElementById("myCanvas1");
var ctx=canvas.getContext("2d");
ctx.webkitImageSmoothingEnabled = false; //Corrige o problema
var pat=ctx.createPattern(img, "repeat");
ctx.rect(0,0, 64, 64);
ctx.fillStyle=pat;
ctx.fill();
ctx.restore();
//Funciona-----------------------
//Causa o bug-----------------------
var canvas2=document.getElementById("myCanvas2");
var ctx2=canvas2.getContext("2d");
var pat=ctx2.createPattern(img, "repeat");
ctx2.rect(0,0, 64, 64);
ctx2.fillStyle=pat;
ctx2.fill();
ctx2.restore();
//Causa o bug-----------------------
}
var img = document.getElementById("lamp");
img.onload = function() {
setTimeout(putImage, 100);
};
<div>
<p>Imagem usada:</p>
<img src="http://i.stack.imgur.com/IvOeo.png" id="lamp">
</div>
<div style="float: left; width: 40%;">
<p>Funciona (com ctx.webkitImageSmoothingEnabled = false):</p>
<canvas id="myCanvas1" width="300" height="318"></canvas>
</div>
<div style="float: right; width: 40%;">
<p>Falha (se não falhar é porque está usando um navegador que já teve o bug corrigido):</p>
<canvas id="myCanvas2" width="300" height="318"></canvas>
</div>
Possible solution 1
This solution may work with Retina monitors, but her focus is to solve the problem with the background-size
. The solution seems to cause some other problem, but I do not know for sure what it is (maybe with images resized by background-size
or width=""
and height=""
, I’m not sure, but it seems that the canvas loses the "precision" of the resized images), however if your page is simpler it is quite possible that it works.
In the "context" of the Canvas API we have the properties:
var ctx = canvas.getContext("2d");
ctx.webkitImageSmoothingEnabled = false; //Webkit/Safari/Chrome
ctx.mozImageSmoothingEnabled = false; //Firefox/Gecko
ctx.imageSmoothingEnabled = false; //Outros navegadores
These properties disable image smoothing, but you need to "mess" with the source code of html2canvas
to be able to apply this.
Possible solution 2
The second possible solution is addressed to the problem with the retinal screens, the idea is that you can create an image twice the size and reduce it later, the process would be something like:
Note: Very large canvas images cannot be exported with .toDataURI
, because there is a size limit.
CSS:
.escala-x2 {
-webkit-transform: scale(2);
-moz-transform: scale(2);
transform: scale(2);
}
Javascript:
var elemento = document.getElementById("foo");
elemento.className += " escala-x2";
html2canvas(elemento).then(function(canvas) {
elemento.className = elemento.className.replace(/\sescala\-x2/g, "");
var new_canvas = document.createElement("canvas");
//Copia canvas para new_canvas e redimenciona pela metade
new_canvas.width = canvas.width / 2;
new_canvas.height = canvas.height / 2;
var ctx = new_canvas.getContext('2d');
ctx.drawImage(canvas, 0, 0, new_canvas.width, new_canvas.height);
ctx.webkitImageSmoothingEnabled = false; //Webkit/Safari/Chrome
ctx.mozImageSmoothingEnabled = false; //Firefox/Gecko
ctx.imageSmoothingEnabled = false; //Outros navegadores
canvas = null;
document.body.appendChild(new_canvas);//Adiciona o canvas redimensionado ao body
});
This way you can use the imageSmoothingEnabled
quietly, as the original images have already been converted to canvas, so it is likely that no problem will occur.
Size limit of canvas
Each browser has an image limit that can work with Canvas, usually when it exceeds this limit is launched an Exception, according to the answer of Soen (these limits are improved as the browser receives updates):
Note: I will update the data as I find more sources
Data of 10/13/2014:
Chrome:
- Maximum width and height: 32,767 pixels
- Maximum area: 268,435,456 pixels (for example 16,384 x 16,384)
Firefox:
- Maximum width and height: 32,767 pixels
- Maximum area: 472,907,776 pixels (for example 22,528 x 20,992)
Internet Explorer:
- Maximum width and height: 8,192 pixels
IE Mobile:
- Maximum width and height: 4,096 pixels
In this case, to maintain quality, it would not be better to try to convert the print into svg?
– MarceloBoni
I thought about it too, but I haven’t tried yet, I’ll try.
– Thomerson Roncally
If you have the image in Canvas, you can convert it to SVG using this plug-in: https://github.com/gliffy/canvas2svg
– MarceloBoni
@Marcelobonifazio the problem is that there was already generated with low quality.
– Maniero
So @bigown, I was commenting on this, the ideal would be to convert straight from HTML to SVG, only I never had to do something like, I’ll do a search, if I find a solution, put here
– MarceloBoni
@Marcelobonifazio If you mean
foreignObject
, think it is blocked in Chrome by "security".– Guilherme Nascimento
Post html and css too, if possible post an image of the problem.
– Guilherme Nascimento
@Guillhermenascimento posted :)
– Thomerson Roncally
@Thomersonroncally I didn’t understand the facebook part in the photo. Do so, without wanting to ask too much rs, post a full example in jsfiddle please.
– Guilherme Nascimento
@Guilhermenascimento Ok rsrs
– Thomerson Roncally
@Guilhermenascimento Edited rsrs Jsfiddle + PHP + Image
– Thomerson Roncally
The test I did was no loss of quality, see the result: http://i.stack.Imgur.com/u2EzW.jpg - for me it looks "perfect". Then I tested with more reddish colors (http://www.socwall.com/images/wallpapers/26794-1920x1200.jpg) and the result was: http://i.stack.Imgur.com/5uQ5s.jpg - With warmer colors it is possible to observe more details, however it seems normal. Maybe the problem occurs at another time, at the time you share on facebook for example (facebook compresses the images I think)
– Guilherme Nascimento
@Guilhermenascimento Um, got it! Yes, in local tests, it also seemed normal to me, but there were several complaints about this, so I thought the mistake was with html2canvas, but I will try your solution, to see if it changes something and I will look for possible causes in other parts of code! Thanks for the great help :) If I solve, I will share here, changing the question :)
– Thomerson Roncally