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>
Related
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>
I have problem with my code, which is quite similar to this CodePen.
var img = new Image();
img.src = 'https://upload.wikimedia.org/wikipedia/commons/thumb/6/63/Diceros_bicornis.jpg/320px-Diceros_bicornis.jpg';
img.crossOrigin = "Anonymous"
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
img.onload = function() {
ctx.drawImage(img, 0, 0);
img.style.display = 'none';
};
var color = document.getElementById('color');
function pick(event) {
var x = event.layerX;
var y = event.layerY;
var pixel = ctx.getImageData(x, y, 1, 1);
var data = pixel.data;
var rgba = 'rgba(' + data[0] + ', ' + data[1] +
', ' + data[2] + ', ' + (data[3] / 255) + ')';
color.style.background = rgba;
color.textContent = rgba;
}
canvas.addEventListener('mousemove', pick);
<!-- Learn about this code on MDN: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas -->
<canvas id="canvas" width="300" height="227" style="float:left"></canvas>
<div id="color" style="width:200px;height:50px;float:left"></div>
It somehow certainly works when the page is first open. But when I refresh the page with F5, it SOMETIMES starts throwing the tainted canvas error. Only when I click x to close the tab, and then click the link again to open a brand new tab will it certainly work again.
I already have img.crossOrigin = "Anonymous".
That sounds like a chrome bug, but easily workaround-able :
Set your crossOrigin attribute first.
The first time the request is made, the crossOrigin attribute is set before the image has loaded, hence your browser will redo the request.
But when you reload the page, the image is already cached, and loads before the crossOrigin attribute is set. Then your canvas will be tainted.
For similar little bugs cases, you should also define your onload event handler before setting this src attribute :
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var img = new Image();
img.crossOrigin = "Anonymous"
img.onload = function() {
ctx.drawImage(img, 0, 0);
img.style.display = 'none';
};
// set the src last
img.src = 'https://upload.wikimedia.org/wikipedia/commons/thumb/6/63/Diceros_bicornis.jpg/320px-Diceros_bicornis.jpg';
var color = document.getElementById('color');
function pick(event) {
var x = event.layerX;
var y = event.layerY;
var pixel = ctx.getImageData(x, y, 1, 1);
var data = pixel.data;
var rgba = 'rgba(' + data[0] + ', ' + data[1] +
', ' + data[2] + ', ' + (data[3] / 255) + ')';
color.style.background = rgba;
color.textContent = rgba;
}
canvas.addEventListener('mousemove', pick);
<!-- Learn about this code on MDN: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas -->
<canvas id="canvas" width="300" height="227" style="float:left"></canvas>
<div id="color" style="width:200px;height:50px;float:left"></div>
I have tried to export the svg element to canvas element and that was working finr in chrome and firefox but that was not working in IE. can you please guide me what i made wrong or how to solve this?
Here is my code,
$("#import").click(function(){
var canvas = document.getElementById('canvas1');
var ctx = canvas.getContext('2d');
var DOMURL = window.URL || window.webkitURL || window;
$("#containerew").attr("xmlns", "http://www.w3.org/2000/svg");
var data1 = document.getElementById("containerew").outerHTML;
var img = new Image();
var svg = new Blob([data1], { type: 'image/svg+xml;charset=utf-8' });
var url = DOMURL.createObjectURL(svg);
img.onload = function () {
ctx.drawImage(img,25, 25);
DOMURL.revokeObjectURL(url);
}
img.src = url;
return true;
});
Please find the below link for example
Sample
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);
});
});
});
I would like some help with implementing a Barcode inside my canvas.
I am using ean13.js to produce a Barcode and it works like a charm if adding it to a div (#controlDiv).
However I have a canvas inside which I would like to add this "div".
My HTML
<div>
<div>
<input type="button" id="btnGenerateStuffInCanvas" value="Add Stuff"/>
<input type="button" id="btnGenerateEAN13" value="Generate EAN"/>
</div>
<div id="controlDiv">
</div>
<canvas id="myCanvas"></canvas>
</div>
Try this one. It works for me. It can be done using Data URI template to create SVG images.
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var data = '<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">' +
'<foreignObject width="100%" height="100%">' +
'<div xmlns="http://www.w3.org/1999/xhtml" style="font-size:40px">' +
'<div id="controlDiv">s</div>' +
'</div>' +
'</foreignObject>' +
'</svg>';
var DOMURL = window.URL || window.webkitURL || window;
var img = new Image();
var svg = new Blob([data], {type: 'image/svg+xml;charset=utf-8'});
var url = DOMURL.createObjectURL(svg);
img.onload = function () {
ctx.drawImage(img, 0, 0);
DOMURL.revokeObjectURL(url);
}
img.src = url;
Replace your html element in data where the div <div id="controlDiv">s</div> element exists.
DEMO
I think that it will help you.
You cannot have DOM elements inside a canvas.
What you can do to cheat it is to have the div overlay the canvas with css.
For instance (css):
#controlDiv {
...
margin-top:-100px;
...
}
I went at it this way:
I created another canvas which I style to display:none. Then I generated the eancode to this canvas and in another canvas I generated an Image from this canvas which I added to the canvas.
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var myEanCanvas = document.getElementById('myEan');
new EAN13(myEanCanvas, textToAdd);
//Create Image from EAN
var imageObj = new Image();
imageObj.onload = function () {
context.drawImage(imageObj, $(parent).attr('positionx'), $(parent).attr('positiony'), $(parent).attr('width'), $(parent).attr('height'));
};
imageObj.src = myEanCanvas.toDataURL();