I am using domtoimage library to convert html (with lots of CSS) to image.
Actually I need high clarity image for printing purpose (600 DPI). So for this I scale (zoom) the html to 6.25(600/96) times, then I use domtoimage to capture it. I am successful as per my plans. My image is of high resolution and the printing clarity is also satisfactory.
But the issue is with optimization. It takes too long time for domtomimage. I know this issue is because of html scaling, but I need high resolution image.
Any idea for making this capture fast? My main focus is to reduce time taken by library to capture and create image.
Note:
I have also tried with phantom JS, but some css properties are not supported in it.
I have also tried html2canvas which has also limitation with some CSS property
Just for information I have added scale property to draw function
function draw(domNode, options) {
return toSvg(domNode, options)
.then(util.makeImage)
.then(util.delay(100))
.then(function (image) {
var canvas = newCanvas(domNode);
// canvas.getContext('2d').drawImage(image, 0, 0);
var ctx = canvas.getContext('2d');
if(options.scale){
ctx.scale(6.25,6.25);
}
ctx.drawImage(image, 0, 0);
return canvas;
});
function newCanvas(domNode) {
var canvas = document.createElement('canvas');
if(options.scale){
canvas.width = options.width || 6.25 * util.width(domNode);
canvas.height = options.height || 6.25 * util.height(domNode);
}
else{
canvas.width = options.width || util.width(domNode);
canvas.height = options.height || util.height(domNode);
}
if (options.bgcolor) {
var ctx = canvas.getContext('2d');
ctx.fillStyle = options.bgcolor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
return canvas;
}
}
I could speed up the image generation process by several times by skipping the font re-rendering process. I'm not sure what content you're trying to capture but if it is not font-specific, I forked and edited the library based on suggestions from several other users and it works for me. It also helped me get rid of many failed XHR requests due to CORS and is currently working on all browsers.
Check out: https://github.com/venkat4541/dom-to-image
This may or may not work for you based on your font usage. Hope it helps.
Related
I have an <img> loading from a URL and I want to see what colors the pixels have.
var img = document.getElementById('image');
img.src = "https://someimage.url/image.jpg";
img.onload = function () {
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
};
At this point, due to .getImageData, the console says operation is insecure.
I try to fix this by adding img.crossOrigin = "anonymous";.
This gets rid of the error message, but leaves me with an empty, unloaded image.
Other posts have suggested moving components out of img.onload, but it's the same result.
Some have suggested that this path is not possible due to security reasons. If so, what is another way of approaching this? How else does one determine the color of a certain pixel displayed on screen?
The documentation for getImageData seems to show exactly what I want to do. It looks like the only difference is that their image is on their own server instead of someone else's. Is this the only way around this problem? And if that's the case, would a more straightforward concept be:
download image to your own server
process it locally
delete image after processing
This might be more straightforward, but probably won't scale very well?
My site allows users to upload their own photos. I've learned that this is trickier than first expected and although I can get each of the components working individually I'm not successfully getting them to produce the outcome I need when combining them. I believe the issue is my lack of understanding around the outputs of the functions i'm using.
I think what I need to do is:
Let the user choose the file to upload
Check / fix the orientation
Display the image in a canvas
Convert the canvas to base64 (to upload to Firebase)
Upload the item
Let the user choose the file to upload
$(document).on('change','#fileUpload',function(e) {
correctImageOrientation(e);
});
Check / fix the image orientation
I'm using image-load (link) for my orientation changes.
function correctImageOrientation(e) {
loadImage(
e.target.files[0],
function (img) {
// document.body.appendChild(img); // Note: this successfully appends the image in the correct orientation to the body - but I need to do this to a canvas to I call:
addImageToCanvas(img);
},
{
orientation: true
}
);
Display the image in a canvas
This part fails. If I pass in the selected file using e.target.files[0] and create an objectURL then it works. This is why I think the img i'm passing in needs to be read / displayed on the canvas differently.
function addImageToCanvas(img) {
img.onload = function() {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0, 300, 300);
console.log("Ending img.onload"); // This is never reached
}
}
I can then successfully convert the file to base64 and upload to Firebase.
I think there must be an easier way to achieve what I want which is for people to upload an image, for the orientation to be correct, and for this to be stored online.
EDIT: To store the image in firebase I am using this to convert the image back to a blob.
I have replaced addImageToCanvas with the function below which was taken then modified from David Walsh's site. Because I'm passing in an image I needed to convert this to a canvas.
function convertImageToCanvas(image) {
var canvas = document.getElementById("canvas");
canvas.width = image.width;
canvas.height = image.height;
canvas.getContext("2d").drawImage(image, 0, 0);
}
The way I'm resizing images now is by sticking it into a canvas element and then scaling the context of the canvas. The problem is, when I'm resizing many images the UI basically freezes. Is there anyways I can move this resizing step to a web worker? Problem I'm having is that you can't use document.createElement('canvas') or Image(), two functions crucial to this implementation.
It is possible. However, because canvas isn't available in a worker, you would have to use your own/3rd party code to manipulate the image data in the worker.
For example, you could use
https://github.com/nodeca/pica, which quite handily does its processing in a web worker if web workers are supported.
A rough example of using this to resize image from an img element to a canvas element...
<button onclick="resize()">Resize</button>
<img id="original" src="my-image.jpg">
<canvas id="resized">
With Javascript
function resize() {
// Find the original image
var originalImg = document.getElementById("original");
// Create an empty canvas element of the same dimensions as the original
var originalCanvas = document.createElement("canvas");
originalCanvas.width = originalImg.width;
originalCanvas.height = originalImg.height;
// Copy the image contents to the canvas
var ctx = originalCanvas.getContext("2d");
ctx.drawImage(originalImg, 0, 0);
// Set the target dimensions
var resizedCanvas = document.getElementById("resized");
resizedCanvas.width = originalCanvas.width / 2;
resizedCanvas.height = originalCanvas.height / 2;
// Resize (using web workers if supported)
pica.resizeCanvas(originalCanvas, resizedCanvas, {}, function(err) {
// Do something on finish/error
});
}
Which can be seen at https://plnkr.co/edit/yPRjxqQkHryqeZKw4YIH?p=preview
Unfortunately, you cannot use integrated browser functions for that. Instead, you need to obtain pixel data:
var data = ctx.getImageData(0,0,canvas.width, canvas.height);
You need to send those to worker. You can use transfer mode for the array:
worker.postMessage( {
name: "image_data",
data: data.data,
width: data.width,
height: data.height
},
[data.data] // this tells browser to transfer data to web worker
);
I modified function from some other answer so that it can scale image using the image data array. It's quite limited, as the scale is only allowed to be integer - that means you can't scale down: https://jsfiddle.net/n3drn8v9/5/
I recommend googling some libraries for this, rather than reinventing the wheel.
I'm developing a server for a iPhone game in Javascript with socket.io. The servers purpose is to draw a offscreen bitmap with the players path in order to check if that path is already draw. Simply put, all of the drawing will only be shown on the client screen. Here is the code I've found for creating a canvas and then finding pixel colors in it. However I've no html code since it's only made using Javascript. So will this code work in a Javascript only program? If not, how can i do something like this but with the same result?
Edit: I'm using socket.io with node.js
var canvas = document.createElement("canvas");
var context = canvas.getContext("2d");
// Make sure to set the size, otherwise its zero
canvas.width = 100;
canvas.height = 100;
// Draw to the offscreen canvas
context.fillStyle = "#0000ff";
context.fillRect(0,0,50,50);
context.fillStyle = "#ff9900";
context.arc(50,50,25,50,0,Math.PI*2);
context.fill();
// document.body.appendChild(canvas)
// To preview the canvas
var imgData = context.getImageData(0, 0, canvas.height, canvas.width);
var offset = 90*canvas.width+50*4
console.log(imgData.data[offset]);
console.log(imgData.data[offset+1]);
console.log(imgData.data[offset+2]);
console.log(imgData.data[offset+3]);
Node.JS + Node-Canvas will accept javascript-only input and will output an image:
https://github.com/Automattic/node-canvas
Systematically updating src of IMG. Memory leak.
I am currently updating an image every x sec. A few ways I thought of doing this were as follows:
Take One:
var url ="...";
$('#ImageID').attr('src', url);
Now this works perfectly changes the image but causes a memory leak.
Take Two:
So it is creating DOM elements, so I attempted the following.
<div id="ImageHolder">
</div>
var image - "..."; //Obv actual image in working.
$('#ImageHolder').empty();
$('#ImageHolder').html(image);
Now this works but causes a flicker when it changes which is unliked. Now with two images and swapping them at intervals works fine, but I want to stay as low on bandwidth as possible.
Edit 1:
My Code:
<form name="selected">
<input type="hidden" name="map" />
</form>
<img id="MyMaps" src="http://localhost/web/blank.png" alt="" />
<script type="text/javascript">
var locate = window.location;
var uri = document.selected.map.value;
var MyHost = window.location.hostname;
function delineate2(name) {
totheleft= uri.indexOf("maps/") + 5;
totheright= uri.lastIndexOf("&");
return (uri.substring(totheleft, totheright));
}
function loadImage() {
var CurrentMap = delineate2(name);
var url = 'http://' + MyHost+ '/map/' + CurrentMap+ '/image?' + new Date().getTime();
$('#MyMaps').attr('src', url);
setTimeout(loadImage, 10000);
}
</script>
Has anyone done something similar and found a working solution, or how can I go about preventing the memory leak / flickering when the image updates?
I believe that your "take one" should work. There should be no memory leak. You're overwriting the src tag every time around - if you hold no other references to old images, they should get garbage collected. I'm seeing this problem in FF and Chrome. Chrome tells me that JS memory usage is constant, the memory must be lost somehwere else.
I have opened a Chrome bug:
https://code.google.com/p/chromium/issues/detail?id=309543
In case you want to put in your weight as well and maybe star the bug :)
I have used different methods to solve this problem, none of them works. It seems that memory leaks when img.src = base64string and those memory can never get released. Here is my solution.
fs.writeFile('img0.jpg', img_data, function (err) {
// console.log("save img!" );
});
document.getElementById("my-img").src = 'img0.jpg?'+img_step;
img_step+=1;
My Electron app updating img every 50ms, and memory doesn't leak.
Forget about disk usage. Chrome's memory management piss me off.
I have never thought of doing this like your fist method.. interesting. I can imagine that it causes a memory leak because every single image is kept in memory because nothing is actually removed. Thats just a guess though.
I would recomend sticking to the second method but modifying it so solve the flicker, like fading between images. A good jQuery plugin to look at would be the jQuery Cycle Plugin
If that plugin doesn't do it for you or you want to keep the code small, jQuery also has some animation functions built in. fadeIn() and fadeOut() may be of interest.
Something like this might work better.
<div id="ImageHolder">
</div>
var image - "..."; //Obv actual image in working.
function loadImage() {
choose your image however you want to, preferably a preloaded image.
$('#ImageHolder').fadeOut('fast');
$('#ImageHolder').html(image);
$('#ImageHolder').fadeIn('fast');
setTimeout(loadImage, 10000);
}
I believe a shorter way to do this might be: (also delay() may be optional, I just put it there in case you need it.)
$('#ImageHolder').fadeOut('fast').html(image).delay('100').fadeIn('slow');
Additionally there may be a delay for the image to load if it hasn't been preloaded. I'm not 100% sure how to do that off the top of my head so a quick google seach came up with this:
http://engineeredweb.com/blog/09/12/preloading-images-jquery-and-javascript
5 years old question yet it still 'hot' for me, I want to share the very same problem I just faced.
The "take one" approach maybe is the very first approach every programmer used to change the image source, but till now ( 5 years after this question posted ) the problem is still occurred, change the <img> 'src' frequently and you can see on windows task manager that your browser became greedy.
The "take two" create flicker, and it is rarely acceptable.
Fortunately, html5 comes with <canvas>, so I try to use <canvas> to overcome this problem.
var canvas = document.getElementById("mycanvas");
var ctx = canvas.getContext("2d");
img = new Image();
img.onload = function () {
ctx.drawImage(img, 0, 0);
img.src = "";
}
img.src = "data:image/png;base64," + stringSource;
The new problem found, <canvas> different from <img>, it will not automatically resize and 'fit'. We have to manually resize the image to fit the canvas and keep the ratio. Below is my code to resolve the problem
var canvas = document.getElementById("mycanvas");
var ctx = canvas.getContext("2d");
img = new Image();
img.onload = function () {
var imageWidth = canvas.width;
var imageHeight = canvas.height;
var xPosition = 0;
var yPosition = 0;
var proportion = 1;
var padding = 2;
if ((img.width / canvas.width) > (img.height / canvas.height)) {
proportion = img.width / canvas.width;
}
else {
proportion = img.height / canvas.height;
}
imageWidth = img.width / proportion;
imageHeight = img.height / proportion;
xPosition = (canvas.width - imageWidth) / 2;
yPosition = (canvas.height - imageHeight) / 2;
ctx.drawImage(img, 0, 0, img.width, img.height, xPosition+padding, yPosition+padding, imageWidth-2*padding, imageHeight-2*padding);
img.src = "";
}
img.src = "data:image/png;base64," + stringSource;
Hope it will help any one who face the same problem.