I have a canvas image, and I want to store that as local storage, then I want to load a canvas on all canvas names in HTML.thanks
var img = new Image();
//Wait for image to load before doing something with content
img.onload = function() {
var canvas = document.querySelectorAll("canvas[name=myCanvas]");
for (var i = 0; i < canvas.length; i++) {
canvas[i].getContext("2d").drawImage(img,10,10);
}
};
img.src = 'http://i.imgur.com/VdXQ7z6.png';
localStorage.setItem("img", img);
<p>Image to use:</p>
<img id="scream" onload="draw(this)" src="http://i.imgur.com/VdXQ7z6.png" alt="The Scream" width="220" height="277">
<p>Canvas:</p>
<canvas name="myCanvas" width="250" height="300" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<canvas name="myCanvas" width="250" height="300" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<canvas name="myCanvas" width="250" height="300" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
You could store the image URL instead of the image object. localStorage can only store strings, not arbitrary data.
If you want to use base64 encoding, here's a demo on JSFiddle. I was going to do it on a stack snippet but there's too many restrictions when dealing with image data, so instead, here's all the JavaScript code:
var input = document.getElementById('upload');
var canvas1 = document.getElementById('disp');
var context1 = canvas1.getContext('2d');
var canvas2 = document.getElementById('test');
var context2 = canvas2.getContext('2d');
function processBlob(blob, callback) {
console.log('generating image from blob');
var blobURL = URL.createObjectURL(blob);
var img = new Image();
img.addEventListener('load', function () {
console.log('blob url loaded');
URL.revokeObjectURL(blobURL);
// 'this' is img
callback.apply(this, arguments);
});
img.src = blobURL;
}
function drawImage(canvas, context, image) {
console.log('drawing image to ' + canvas.id);
var width = image.naturalWidth;
var height = image.naturalHeight;
canvas.width = width;
canvas.height = height;
context.drawImage(image, 0, 0, width, height);
}
function storeImage(canvas, itemName) {
console.log('storing image from ' +
canvas.id + ' to ' + itemName);
// remove 22 byte header from base64
var dataURL = canvas.toDataURL('image/png').slice(22);
localStorage.setItem(itemName, dataURL);
}
function loadImage(itemName, callback) {
console.log('loading image from ' + itemName);
var dataURL = localStorage.getItem(itemName);
var binary = atob(dataURL);
var uint8 = new Uint8Array(binary.length);
for (var i = 0; i < binary.length; i++) {
uint8[i] = binary.charCodeAt(i);
}
var blob = new Blob([uint8], { type: 'image/png' });
processBlob(blob, callback);
}
console.log('start of program');
input.addEventListener('change', function () {
var file = this.files[0];
console.log('processing ' + file.name);
processBlob(file, function () {
console.log('callback for file image');
drawImage(canvas1, context1, this);
storeImage(canvas1, 'myImage');
loadImage('myImage', function () {
console.log('callback for localStorage image');
drawImage(canvas2, context2, this);
});
});
});
Related
Context
I'm trying to generate a Base64 string of a JPG/PNG/... image after resizing it. For some reason, the resulting Base64 string is that of a plain white image.
Assumption
My assumption of what is causing this, is the following: <canvas width="X" height="Y"></canvas> does not seem to contain innerHTML, where I would expect it to contain <img src="https://static.wixstatic.com/media/6068b5_b0d5df4c3d094694bb5d348eac41128d~mv2.jpg" crossorigin="anonymous"> However, I cannot figure out why ctx.drawImage() does not handle this.
Related issues
Several other people have brought up this issue, but unfortunately, the proposed solutions didn't seem to resolve my issue. See:
Rendering a base64 image, currently comes back as blank
How can I convert an image into Base64 string using JavaScript?
How to display Base64 images in HTML?
Minimal Working Example
async function init(){
//getDataUrl
var dataUrl = await getDataUrl("https://static.wixstatic.com/media/6068b5_5888cb03ab9643febc221f3e6788d656~mv2.jpg");
console.log(dataUrl); //returns string, but white image?
//Create new image on body tag with dataurl
addBase64Image(dataUrl);
}
function getImageDimensions(file) {
return new Promise (function (resolved, rejected) {
var i = new Image()
i.onload = function(){
resolved({w: i.width, h: i.height})
};
i.src = file
})
}
async function getDataUrl(img_url) {
// Create canvas
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
var dimensions = await getImageDimensions(img_url);
console.log(dimensions);
// Set width and height
canvas.width = dimensions.w; //img_url.width
canvas.height = dimensions.h; //img_url.height
var res = await loadImage(ctx, img_url, dimensions.w, dimensions.h);
console.log(res);
res.setAttribute('crossorigin', 'anonymous');
ctx.drawImage(res, dimensions.w, dimensions.h); //issue: <canvas width="2075" height="3112"></canvas> has no innerHTML e.g. <img src="https://static.wixstatic.com/media/6068b5_b0d5df4c3d094694bb5d348eac41128d~mv2.jpg" crossorigin="anonymous">
console.log(canvas);
console.log(ctx);
dataurl = canvas.toDataURL('image/png');
return dataurl;
}
function loadImage(context, path, dimx, dimy){
return new Promise(function(resolve, reject){
var img=new Image();
img.onload = function() {
resolve.call(null, img);
};
img.src=path;
});
}
function calculateAspectRatioFit(srcWidth, srcHeight, maxWidth, maxHeight) {
var ratio = Math.min(maxWidth / srcWidth, maxHeight / srcHeight);
return { width: srcWidth*ratio, height: srcHeight*ratio };
}
async function addBase64Image(img_dataurl){
var dimensions = await getImageDimensions(img_dataurl);
console.log(dimensions);
var res = calculateAspectRatioFit(dimensions.w, dimensions.h, 512, 512);
console.log(res);
var image = document.createElement("img");
var imageParent = document.querySelector('body');
image.id = "user_upload";
image.width = res.width;
image.height = res.height;
image.src = img_dataurl;
imageParent.appendChild(image);
}
body {
margin: 0px;
}
#user_upload {
display: block;
margin-left: auto;
margin-right: auto;
border: 2.5px solid;
}
<body onload="init()">
</body>
To be able to draw an image hosted on a different domain onto a canvas
a) the webserver needs to permit it and send the appropriate headers
b) you need to set the crossOrigin property of the image to "anonymous"
Obviously you already figured this out yourself, as you already have the line
res.setAttribute('crossorigin', 'anonymous');
in your code.
The problem is that it happens too late. It needs to be set before assigning an URL to the src property of the image.
So simply move the above line inside the loadImage() function, just before the call to
img.src=path;
Here's an example:
async function init() {
//getDataUrl
var dataUrl = await getDataUrl("https://static.wixstatic.com/media/6068b5_5888cb03ab9643febc221f3e6788d656~mv2.jpg");
console.log(dataUrl); //returns string, but white image?
//Create new image on body tag with dataurl
addBase64Image(dataUrl);
}
function getImageDimensions(file) {
return new Promise(function(resolved, rejected) {
var i = new Image()
i.onload = function() {
resolved({
w: i.width,
h: i.height
})
};
i.src = file
})
}
async function getDataUrl(img_url) {
// Create canvas
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
var dimensions = await getImageDimensions(img_url);
console.log(dimensions);
// Set width and height
canvas.width = dimensions.w; //img_url.width
canvas.height = dimensions.h; //img_url.height
var res = await loadImage(ctx, img_url, dimensions.w, dimensions.h);
console.log("asd ", res);
ctx.drawImage(res, 0, 0); //issue: <canvas width="2075" height="3112"></canvas> has no innerHTML e.g. <img src="https://static.wixstatic.com/media/6068b5_b0d5df4c3d094694bb5d348eac41128d~mv2.jpg" crossorigin="anonymous">
console.log(canvas);
console.log(ctx);
dataurl = canvas.toDataURL('image/png');
return dataurl;
}
function loadImage(context, path, dimx, dimy) {
return new Promise(function(resolve, reject) {
var img = new Image();
img.onload = function() {
resolve.call(null, img);
};
img.setAttribute('crossorigin', 'anonymous');
img.src = path;
});
}
function calculateAspectRatioFit(srcWidth, srcHeight, maxWidth, maxHeight) {
var ratio = Math.min(maxWidth / srcWidth, maxHeight / srcHeight);
return {
width: srcWidth * ratio,
height: srcHeight * ratio
};
}
async function addBase64Image(img_dataurl) {
var dimensions = await getImageDimensions(img_dataurl);
console.log(dimensions);
var res = calculateAspectRatioFit(dimensions.w, dimensions.h, 512, 512);
console.log(res);
var image = document.createElement("img");
var imageParent = document.querySelector('body');
image.id = "user_upload";
image.width = res.width;
image.height = res.height;
image.src = img_dataurl;
imageParent.appendChild(image);
}
init();
body {
margin: 0px;
}
#user_upload {
display: block;
margin-left: auto;
margin-right: auto;
border: 2.5px solid;
}
I need to convert 2 separate SVG's into 1 PNG image. I currently have code working for converting 1 SVG to a PNG. This code is shown below, I convert the SVG to canvas to PNG.
The SVG's are on the same page, and I have tried using an array to iterate through them and grab both. The code I am currently working on is also below, but is not working. Any advice on how to convert the SVGs to the same PNG image?
Thanks a bunch!
Single SVG to PNG
// convert svg to png
function svgToPng(){
var svg = document.querySelectorAll('svg')[0];
// clone svg nodes
var copy = svg.cloneNode(true);
// convert to xml format for storage/transportation
var serializer = new XMLSerializer();
var data = serializer.serializeToString(copy);
// create url
var DOMURL = window.URL || window.webkitURL || window;
// create image/blob
var img = new Image();
var blob = new Blob([data], {type: "image/svg+xml;charset=utf-8"});
var url = DOMURL.createObjectURL(blob);
// create canvas
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
// draw image on canvas
img.onload = function(){
ctx.drawImage(img, 0, 0, $(svg0).width(), $(svg0).height());
DOMURL.revokeObjectURL(url, url1);
var imgURI = canvas.toDataURL("image/png").replace("image/png", "image/octet-stream");
}
// send new image to window
img.src = url;
// return img.src;
window.open().document.write('<img src="' + img.src + '" width="1600" height="800"/>');
};
Multiple SVG's to PNG
// convert multipl svgs to png
function multSvgToPng(){
var array = [];
var totalSvg = document.querySelectorAll('svg'); // NodeList(2) [svg, svg]
// create array
for(var i = 0; i < totalSvg.length; i++){
array = document.querySelectorAll('svg')[i];
}
for(var j = 0; j < array.length; j++){
var svg = array[j];
var copy = svg.cloneNode(true);
var serializer = new XMLSerializer();
var data = serializer.serializeToString(copy);
var DOMURL = window.URL || window.webkitURL || window;
var img = new Image();
var blob = new Blob([data], {type: "image/svg+xml;charset=utf-8"});
var url = DOMURL.createObjectURL(blob);
var svgStr = serializer.serializeToString(copy);
}
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
img.onload = function(){
ctx.drawImage(img, 0, 0, $(svg).width(), $(svg).height());
DOMURL.revokeObjectURL(url);
var imgURI = canvas.toDataURL("image/png").replace("image/png", "image/octet-stream");
}
// send new image to window
img.src = url;
// return img.src;
window.open().document.write('<img src="' + img.src + '" width="1600" height="800"/>');
}
Example SVG Images
<!DOCTYPE html>
<html>
<body>
<svg height="100" width="100">
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
Sorry, your browser does not support inline SVG.
</svg>
</body>
</html>
<!DOCTYPE html>
<html>
<body>
<svg width="400" height="110">
<rect width="300" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" />
Sorry, your browser does not support inline SVG.
</svg>
</body>
</html>
I've used your technique and made two separate functions. The first function drawSVGToCanvas creates a canvas for a single SVG, by converting it to a blob and drawing it onto the canvas when the image has loaded. It returns a promise with the canvas element when it is fullfilled.
convertSVGsToSingleImage accepts a list of SVG elements for which it will loop over and call drawSVGToCanvas for each of those SVG elements. It waits until they are rendered and continues to draw the returned canvas elements on a single new canvas. This is where the combining happens.
const preview = document.getElementById('preview');
const svgs = document.querySelectorAll('svg');
function drawSVGToCanvas(svg) {
const { width, height } = svg.getBoundingClientRect();
const serializer = new XMLSerializer();
const copy = svg.cloneNode(true);
const data = serializer.serializeToString(copy);
const image = new Image();
const blob = new Blob([data], {
type: 'image/svg+xml;charset=utf-8'
});
const url = URL.createObjectURL(blob);
return new Promise(resolve => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = width;
canvas.height = height;
image.addEventListener('load', () => {
ctx.drawImage(image, 0, 0, width, height);
URL.revokeObjectURL(url);
resolve(canvas);
}, { once: true });
image.src = url;
})
}
async function convertSVGsToSingleImage(svgs, format = 'image/png') {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const drawSVGs = Array.from(svgs).map(svg => drawSVGToCanvas(svg))
const renders = await Promise.all(drawSVGs);
canvas.width = Math.max(...renders.map(render => render.width));
canvas.height = Math.max(...renders.map(render => render.height));
renders.forEach(render => ctx.drawImage(render, 0, 0, render.width, render.height));
const source = canvas.toDataURL(format).replace(format, 'image/octet-stream');
return source;
}
convertSVGsToSingleImage(svgs).then(source => {
const image = new Image();
image.addEventListener('load', () => {
preview.append(image);
})
image.src = source;
});
<svg width="400" height="110">
<rect width="300" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" />
Sorry, your browser does not support inline SVG.
</svg>
<svg height="100" width="100">
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
Sorry, your browser does not support inline SVG.
</svg>
<div id="preview"></div>
Previously, I tried to use an Annotation.StampAnnotation to create a custom annotation while using a SVG as the base image, however I discovered that the user cannot change or set the colour of a StampAnnotation. Hence, I am now using an Annotation.MarkupAnnotation.
As of right now, I am having trouble drawing the inline SVG (string) on the CanvasRenderingContext2D using drawImage(). I saw some code on TutorialsPoint, and I tested it in a Javascript sandbox, and it seems to work. However, when I implemented it with PDFTron, it only draws an empty box on the PDF.
Here's my code:
createCustomAnnotation: function (Annotations, annotManager, subject, inlineSVGString) {
const CustomAnnotation = function () {
Annotations.MarkupAnnotation.call(this);
this.Subject = subject;
}
CustomAnnotation.prototype = new Annotations.MarkupAnnotation();
CustomAnnotation.prototype.draw = function (ctx, pageMatrix) {
this.setStyles(ctx, pageMatrix);
var DOMURL = window.URL || window.webkitURL || window;
var img = new Image();
var svg = new Blob([inlineSVGString], {type: 'image/svg+xml'});
var url = DOMURL.createObjectURL(svg);
var x = this.X;
var y = this.Y;
img.onload = function() {
ctx.drawImage(img, x, y, 30, 30);
DOMURL.revokeObjectURL(url);
}
img.src = url;
}
return CustomAnnotation;
}
Any help would be appreciated!
Thank you!
there
Looks like the sample from Tutorials Point has a syntax error and it only draws an empty box, if you try this sample it draws the text correctly.
<!DOCTYPE html>
<html>
<head>
<title>SVG file on HTML Canvas </title>
</head>
<body>
<canvas id="myCanvas" style="border:2px solid green;" width="300" height="300"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
var data = '<svg xmlns="http://www.w3.org/2000/svg" width="300" height="200">' +
'<foreignObject width="100%" height="100%">' +
'<div xmlns="http://www.w3.org/1999/xhtml" style="font-size:50px">' +
'Simply Easy ' +
'<span style="color:blue;">' +
'Learning</span>' +
'</div>' +
'</foreignObject>' +
'</svg>';
var DOMURL = window.URL || window.webkitURL || window;
var img1 = new Image();
var svg = new Blob([data], {type: 'image/svg+xml'});
var url = DOMURL.createObjectURL(svg);
img1.onload = function() {
ctx.drawImage(img1, 25, 70);
DOMURL.revokeObjectURL(url);
}
img1.src = url;
</script>
</body>
</html>
I am developing a web app that clients can upload image, I will find faces in that image and send back rectangles to client.
I am using ajaxfileupload function for saving image on server but for efficiency I am loading images from client computer and sending rectangles from server.
I am having two problem here:
1-)For the first image image.onload is not firing but its creating canvas and uploadHandler function its not calling.
2-)uploadHandler function is getting the same canvas for all images.Therefore its drawing my rectangles on the first image.
<script src="http://code.jquery.com/jquery-1.10.2.js"></script>
<script src="http://code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
<script src="jquery.ajaxfileupload.js"></script>
<script src="ocanvas-2.7.2.min.js"></script>
<script type="text/javascript">
function uploadHandler(canvas)
{
$('input[type="file"]').ajaxfileupload({
'action': 'upload',
'onComplete': function(response) {
for (var i= 0; i < response.faces.length;i++)
{
var item = response.faces[i];
//alert("Tx:"+item.Tx+" Ty:"+item.Ty+" Bx:"+item.Bx+" By:"+item.By);
var rectangle = canvas.display.rectangle({
x: parseInt(item.Tx),
y: parseInt(item.Ty),
width: parseInt(parseInt(item.Bx)-parseInt(item.Tx)),
height: parseInt(parseInt(item.By)-parseInt(item.Ty)),
stroke: "5px #0aa"
});
canvas.addChild(rectangle);
}
},
'onStart': function() {
}
});
}
$(document).ready(function(){
var fileInput = document.getElementById('fileInput');
var fileDisplayArea = document.getElementById('fileDisplayArea');
fileInput.addEventListener('change', function(e) {
var file = fileInput.files[0];
var imageType = /image.*/;
if (file.type.match(imageType)) {
var reader = new FileReader();
reader.onload = function(e) {
var img = new Image();
img.onload = function(e) {
var elementID = 'canvas' + $('canvas').length; // Unique ID
//create canvas
$('<canvas>').attr({
id: elementID,
width: this.width + 'px',
height: this.height + 'px'
}).appendTo('#fileDisplayArea');
var canvas = oCanvas.create({
canvas: '#'+elementID
});
//add image to canvas
var image = canvas.display.image({
x: this.width,
y: this.height,
origin:{x:this.width,y:this.height},
image: reader.result
});
canvas.addChild(image);
//upload to server
uploadHandler(canvas);
}
img.src = reader.result;
//fileDisplayArea.appendChild(img);
}
reader.readAsDataURL(file);
} else {
fileDisplayArea.innerHTML = "File not supported!";
}
});
});
</script>
this is for 4 images
<input type="file" name="fileInput" id="fileInput"/>
<div id="upload" style="display: none;"></div>
<input id="predict" type="button" value="Process"></input>
<div id="work_place"></div>
<div id="fileDisplayArea">
<canvas id="canvas0" width="634px" height="471px"></canvas>
<canvas id="canvas1" width="600px" height="338px"></canvas>
<canvas id="canvas2" width="400px" height="400px"></canvas>
<canvas id="canvas3" width="960px" height="960px"></canvas>
</div>
I want to join multiple canvases to make a single image.
So is there any method to covert more than one canvases to toDataURL to make a single image?
create a function that takes multiple arguments (canvas elements), puts them on one blank canvas, then returns the dataurl for the newly made canvas.
var getImadeData = function () {
var i = arguments.length,
tempCanvas = document.createElement("canvas"),
ctx = tempCanvas.getContext("2d");
while (i--) {
ctx.drawImage(arguments[i], 0, 0);
};
return tempCanvas.toDataURL();
};
Now just feed the function multiple canvas elements you want to put into one dataurl like so.
var newData = getImageData(canvas1, canvas2, canvas3);
In this example, the last canvas is placed on the blank canvas first so make sure to order your canvas elements appropriately.
Yes, the drawImage method on the canvas 2d rendering context accepts canvas elements as image elements. So all you have to do is:
Create a new canvas
Get its context
Draw all other canvases to it with drawImage
Extract the final image from this new canvas
try this example hope it will help see here
//html block
<canvas id="myCanvas" width="200" height="100" style="border:1px solid #c3c3c3;">
</canvas>
<canvas id="myCanvas1" width="200" height="100" style="border:1px solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
<canvas id="Canvasimage" width="500" height="100" style="border:1px solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
<img id="finalimage" width="500" height="100" style="border:1px solid #c3c3c3;"/>
//script block
function loadImages(sources, callback) {
var images = {};
var loadedImages = 0;
var numImages = 0;
// get num of sources
for (var src in sources) {
numImages++;
}
for (var src in sources) {
images[src] = new Image();
images[src].onload = function () {
if (++loadedImages >= numImages) {
callback(images);
}
};
images[src].src = sources[src];
}
}
window.onload = function (images) {
//Canvas first here
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "#FF0000";
ctx.fillRect(0, 0, 200, 100);
//Canvas second here
var c1 = document.getElementById("myCanvas1");
var ctx1 = c1.getContext("2d");
ctx1.fillStyle = "#00FF00";
ctx1.fillRect(0, 0, 200, 100);
//Canvas final here.
var canvas = document.getElementById("Canvasimage");
var context = canvas.getContext("2d");
var sources = {
darthVader: c.toDataURL("image/png"),
yoda: c1.toDataURL("image/png")
};
loadImages(sources, function (images) {
context.drawImage(images.darthVader, 100, 30, 200, 137);
context.drawImage(images.yoda, 350, 55, 93, 104);
//finalimage here which has two canvas data
var finalimage = document.getElementById("finalimage");
finalimage.src = canvas.toDataURL("image/png");
});
};