I'm programmatically creating a very simple HTML Canvas on which I'm writing some text and then drawing an imported PNG Image.
I now want to "flatten" this canvas and export it out as a new Image.
It's working - but not 100%.
The issue is that while the text and background colors DO show up in the newly created and exported PNG, the image that was imported and drawn on the original canvas is NOT showing up.
Here's my code:
var newCanvas = document.createElement("canvas");
var context = newCanvas.getContext("2d");
// 1. Filling Canvas with Background Color:
context.fillStyle = "blue";
context.fillRect(0, 0, newCanvas.width, newCanvas.height);
// 2. Writing Text on the Canvas:
context.font = "30px Comic Sans MS";
context.fillStyle = "yellow";
context.textAlign = "center";
context.fillText("Hello World", newCanvas.width/2, newCanvas.height/2);
// 3. Adding a PNG to the Canvas:
let bgdImage = new Image();
bgdImage.src = "images/TilePattern1.png";
bgdImage.onload = function(){
context.drawImage(bgdImage, 0, 0, bgdImage.width, bgdImage.height);
}
// 4. Now I create a NEW Image object and set its contents to be
// all those elements I drew on my Canvas:
let finalImage = new Image();
finalImage.src = newCanvas.toDataURL();
So the resulting finalImage created by this code DOES have both the Background color and the Text I wrote - but it does NOT have the "TilePattern1.png" IMAGE I imported and drew on the canvas using .drawImage
What do I need to do to fix this?
(NOTE: the imported "TilePattern1.png" image DOES show up in the canvas drawn on the webpage; but it does NOT show up on the Image exported from the Canvas.)
My guess is that you have an error situation:
MDN
SecurityError
The canvas's bitmap is not origin clean; at least some of its contents
have or may have been loaded from a site other than the one from which
the document itself was loaded.
UPDATE: I have now run your code fully and the first problem is that you are not waiting for the image to be loaded before creating the base64 from the canvas so it doesn't have the image in it. The second problem is that if you wait for the image to be loaded and then attempt to create the base64 you will see something like this error:
Uncaught DOMException: Failed to execute 'toDataURL' on
'HTMLCanvasElement': Tainted canvases may not be exported.
Here's the code which waits for the image to load so you can try for yourself:
<body>
<img />
<script>
var newCanvas = document.createElement("canvas");
var context = newCanvas.getContext("2d");
// 1. Filling Canvas with Background Color:
context.fillStyle = "blue";
context.fillRect(0, 0, newCanvas.width, newCanvas.height);
// 2. Writing Text on the Canvas:
context.font = "30px Comic Sans MS";
context.fillStyle = "yellow";
context.textAlign = "center";
context.fillText("Hello World", newCanvas.width/2, newCanvas.height/2);
// 3. Adding a PNG to the Canvas:
let bgdImage = new Image();
bgdImage.src = "images/TilePattern1.png";
bgdImage.onload = function(){
context.drawImage(bgdImage, 0, 0, bgdImage.width, bgdImage.height);
// 4. Now I create a NEW Image object and set its contents to be
// all those elements I drew on my Canvas:
let finalImage = new Image();
finalImage.src = newCanvas.toDataURL();
// below added so we can see the canvas and the final image (if you comment out the above line)
document.body.appendChild(finalImage);
document.body.appendChild(newCanvas);
}
</script>
</body>
Related
I have been using a pixel editor called pixel paint and I wanted to create a button that allows me to load any image onto the canvas. Currently, I have been researching and testing multiple methods online and I am still struggling to get the image loaded in. Here is the code for the script.js method.
function showSelectedFile(){
var canvas = document.createElement("canvas");
var context = canvas.getContext("2d");
var img = new Image();
var file = document.getElementById("inputfile");
var name = file.value.replaceAll("\\","").replace("C:fakepath","").replace(".png","");
document.getElementById("myText").value = name;
window.URL = window.URL || window.webkitURL;
img.onload = function()
{
context.drawImage(img,0,0)
}
img.src = "/Users/angadp/Dropbox/Mac/Downloads/pixel-paint-master/" + name + ".png";
}
Also, in the script.js file I have tried to use
var canvas = document.getElementById("canvas-div")
but it gets the following error
Uncaught TypeError: canvas.getContext is not a function
In the index.html file the code is currently using <div id="canvas-div"></div>. So I am not really sure how to load the image onto the canvas that is using the div tag. Also at the beginning of the html file I am using <input id='inputfile' type='file' accept = ".png" name='inputfile' onChange='showSelectedFile()'> which makes the choose file button.
I also have a picture of pixel paint so that you would know what I am talking about.
Can you please provide me with some help on how to solve all these solutions. Thank you. I have also attached the hyperlink to the original pixel-paint so that you can download and test it.
Pixel Editor Menu for you to download and test
You can load image on change of file. Then createObjectURL (that's data:something;base64). Then load it on an image finally draw it on the <canvas>.
function loadFile(event) {
var canvas = document.querySelector("canvas");
var ctx = canvas.getContext('2d');
var dummy = document.getElementById('dummy');
dummy.src = URL.createObjectURL(event.target.files[0]);
dummy.onload = function() {
ctx.drawImage(dummy, 0, 0, 600, 300);
// Set line width
ctx.lineWidth = 10;
ctx.beginPath();
ctx.moveTo(50, 140);
ctx.lineTo(150, 60);
ctx.lineTo(250, 140);
ctx.closePath();
ctx.stroke();
// free memory
URL.revokeObjectURL(dummy.src)
dummy.parentNode.removeChild(dummy)
}
};
canvas {
width: 600px;
height: 300px;
}
<input type="file" accept="image/*" onchange="loadFile(event)">
<canvas></canvas>
<img id="dummy" />
is there a way to add white spaces to an image in javascript ?
I this the image 1 and I want to edit or create a new image, to add white spaces and the result would be the image 2.
The following code achieves this task. Basically, we create a canvas and set it to the size of the desired output. We then fill it with white before drawing the original image at (0,250) This centers the image (I should have done this with code, but instead looked at your output image in an image editor. (OutputHeight-InputHeight)/2 = Y offset to draw image at.
Since you're not actually adding any detail, it's possible this isn't the best way to go about what you're trying to achieve. It's possible that you should use margin/padding to expand the room the image appears to occupy.
window.addEventListener('load', onLoaded, false);
function onLoaded(evt)
{
let img = document.querySelector('img');
let canvas = document.querySelector('#output');
let ctx = canvas.getContext('2d');
ctx.fillStyle = '#fff';
ctx.fillRect(0,0,759,759);
ctx.drawImage(img, 0, 250);
}
body{
background-color: #ddd;
}
<img src='https://i.stack.imgur.com/bN5hp.jpg'/>
<hr>
<canvas id='output' width=760 height=760/></canvas>
You can do it using the canvas object.. if you have the image for instance
<img src="some.jpeg" id="myImg">
You can copy it to a new canvas and play with the drawImage properties
var img = document.getElementById('myImg');
var canvas = document.createElement('canvas');
canvas.width = img.width; // add here the extra width you want
canvas.height = img.height; // add here the extra height you want
canvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height); // play here with the position, 0, 0 are the top x,y axis
Here is the link to mozilla documentation:
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage
I am working on an image generator using HTML5 canvas and jQuery/JS. What I want to accomplish is the following.
The user can upload 2 or max 3 images (type should be png or jpg) to the canvas. The generated images should always be 1080x1920. If the hart uploads only 2 images, the images are 1080x960. If 3 images are uploaded, the size of each image should be 1080x640.
After they upload 2 or 3 images, the user can click on the download button to get the merged image, with a format of 1080x1920px.
It should make use of html canvas to get this done.
I came up with this:
HTML:
<canvas id="canvas">
Sorry, canvas not supported
</canvas><!-- /canvas.offers -->
<input id="fileInput" type="file" />
Generate
jQuery:
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
canvas.height = 400;
canvas.width = 800;
var img1 = loadImage('http://www.shsu.edu/dotAsset/0e829093-971c-4037-9c1b-864a7be1dbe8.png', main);
var img2 = loadImage('https://upload.wikimedia.org/wikipedia/commons/thumb/c/c5/Ikea_logo.svg/266px-Ikea_logo.svg.png', main);
var minImages = 2;
var imagesLoaded = 0;
function main() {
imagesLoaded += 1;
if(imagesLoaded >= minImages) {
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.save();
ctx.drawImage(img1, 0, 0);
// ctx.translate(canvas.height/2,canvas.width/2); // move to the center of the canvas
// ctx.rotate(270*Math.PI/180); // rotate the canvas to the specified degrees
// ctx.drawImage(img2,0,canvas.height/2);
ctx.translate(-canvas.height/2,canvas.width/2); // move to the center of the canvas
ctx.rotate(90*Math.PI/180); // rotate the canvas to the specified degrees
ctx.drawImage(img2,-img2.width/2,-img2.width/2);
ctx.restore(); // restore the unrotated context
}
}
function loadImage(src, onload) {
var img = new Image();
img.onload = onload;
img.src = src;
console.log(img);
return img;
}
Above code will create the canvas and place both images (that are now hard-coded in JS) to the created canvas. It will rotate 90 degrees, but it will not position to the right corner. Also the second image should be position beside the first one.
How can I do the rotation and positioning of each image side by side?
Working Fiddle: https://jsfiddle.net/8ww1x4eq/2/
Have a look at the updated jsFiddle, is that what you wanted?
Have a look here regarding image rotation
Updated jsFiddle, drawing multiple images.
Notice:
The save script was just a lazy way to make sure I've got the
external scripts loaded before I save the merged_image...
There is no synchornisation in the sample script, notice that addToCanvas
was called on image loaded event, there could be a race condition
here (but I doubt it, since the image is loaded to memory on
client-side)
function addToCanvas(img) {
// resize canvas to fit the image
// height should be the max width of the images added, since we rotate -90 degree
// width is just a sum of all images' height
canvas.height = max(lastHeight, img.width);
canvas.width = lastWidth + img.height;
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (lastImage) {
ctx.drawImage(lastImage, 0, canvas.height - lastImage.height);
}
ctx.rotate(270 * Math.PI / 180); // rotate the canvas to the specified degrees
ctx.drawImage(img, -canvas.height, lastWidth);
lastImage = new Image();
lastImage.src = canvas.toDataURL();
lastWidth += img.height;
lastHeight = canvas.height;
imagesLoaded += 1;
}
PS: I've added some script to download the merged image, but it would fail. The error message was: "Uncaught SecurityError: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported."
I've done a quick Google search and it seemed to be related to Cross-origin resources. I assumed that it wouldn't be an issue with FileReader. I haven't had time to test that so please test it (and please let me know :) It works with FileReader!
You can use toDataURL. But in this way user must do something like Save image as...
var img = canvas.toDataURL("image/png");
And then set for example img result src:
$("#result").attr("src",img);
Canvas is already an Image.
The canvas and img are interchangeable so there is no need to add the risky step of canvas.toDataURL which can fail depending on the image source domain. Just treat the canvas as if it were and img and put it in the DOM. Converting to a jpg does not save space (actually a resource hungry operation) as the an img needs to be decoded before it can be displayed.
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
canvas.height = 400;
canvas.width = 800;
document.body.appendChild(canvas); // add to the end of the document
// or add it to a containing element
var container = document.getElementById("containerID"); // or use JQuery
if(container !== null){
container.appendChild(canvas);
}
I'm having some issues using the drawImage method to place a pre-loaded image larger then 250PX width and height onto a canvas.
//Canvas
var canvas = document.createElement("canvas");
var contex = canvas_image.getContext('2d');
canvas.width = 350;
canvas.height = 350;
canvas.id = 'canvas'
$('.canvas').append(canvas);
//Draw Image to canvas
var imageObj = new Image();
imageObj.onload = new function() {
contex.drawImage(imageObj, 0, 0);
};
imageObj.src = $('img').attr('src');
I can't seem to get it to work with an image larger then 250PX Width or Height. But under 250 the image shows... It's really odd and frustrating.
You must get the context from the canvas element. The code you are showing in the post (not sure if it's a typo that happen when posting the question or not? though you shouldn't be able to draw anything if it's not a typo :-) ) has the following error:
This line:
var contex = canvas_image.getContext('2d');
should be:
var contex = canvas.getContext('2d');
as canvas_image does not seem to exist.
If you already have an image loaded you can draw that directly onto canvas instead - there is no need to do a second load of the image:
contex.drawImage($('img')[0], 0, 0);
just make sure you tap into its load event first as you do with the off-screen image.
var img = $('img');
img.on('load', function(e) {
contex.drawImage(img[0], 0, 0);
}
or call it on window's load event.
Other things to look out for is if the image actually has data in the 350x350 pixel area in top left corner (in case the image is very large). You can test by drawing it scaled to see if there is information there:
contex.drawImage(imageObj, 0, 0, canvas.width, canvas.height);
I'm playing with the canvas element in HTML5 and I have noticed a peculiar behavior. On initial load, an image I'm displaying does not show. However, when I refresh the browser, it displays appropriately. I've used IE9 and Chrome. Both behave identically. The JavaScript code looks like this:
window.onload = load;
function load() {
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
context.fillRect(0, 0, 640, 400);
var image = new Image();
image.src = "Images/smiley.png";
context.drawImage(image, 50, 50);
}
The rectangle draws correctly both times, it's the smiley that only shows on a browser refresh.
I'm in the process of learning HTML5 and JavaScript. I'm sure I'm just doing something stupid, but I can't figure it out.
Images load asynchronously, so only after refresh it loads early enough because it's cached. Normally it isn't loaded yet at the time you call drawImage. Use onload:
var image = new Image();
image.src = "Images/smiley.png";
image.onload = function() {
context.drawImage(image, 50, 50);
};
This happened with me as well (only for IE9 for me) anyways, i found a simple solution.
Set the background of the canvas to the initial image you wish to display.
var canvas = document.getElementById("canvas");
canvas.style.background="url('image.png')";
That should work!
Actually, even just using image.onload = function() {}, you can still run into problems. Do use this technique (that's not at all what I'm saying), but move it to the bottom of your page.
As an example, I have a social networking site that uses canvas to show the profile photo (URI stored to the DB), and print it to canvas, then overlay a logo.
<section id="content">
<article id="personalbox" >
<h2>Hi! My name is {profile_name}</h2>
<a id="friendbutton" href=""><img src="views/default/images/friend.png" width="12" height="12" /><span>Add {profile_name} as a friend?</span></a>
<video id="profilevideo" width="240" height="144">DEBUG: Video is not supported.</video>
<canvas id="profilecanvas" width="240" height="144" >DEBUG: Canvas is not supported.</canvas>
<a id="gallerytextlink" href="gallery.html" >Click to visit {profile_name} Gallery</a>
<table id="profileinfotable1">
...
</section>
<script type="text/javascript">
function init() {
var cvs = document.getElementById("profilecanvas");
var ctx = cvs.getContext("2d");
var img = new Image();
img.src = "uploads/profile/{profile_photo}";
img.onload = function() {
// Ignore. I was playing with the photo.
ctx.drawImage(img, 42, 32, 186, 130, cvs.width/2 - (186-42)/2, cvs.height/2 - (130-32)/2, 186-42, 130-32);
drawLogo(cvs,ctx);
}
}
function drawLogo(cvs,ctx) {
var logo = "Enter Logo Here.";
ctx.fillStyle = "rgba(36,36,36,0.6)";
ctx.strokeStyle = "rgba(255,255,255,0.3)";
ctx.font = "bold italic 6pt Serif";
ctx.textAlign = "left";
ctx.textBaseline = "middle" ;
ctx.save();
ctx.strokeText(logo, 4, cvs.height-11);
ctx.strokeText(logo, 6, cvs.height-11);
ctx.strokeText(logo, 4, cvs.height-9);
ctx.strokeText(logo, 6, cvs.height-9);
ctx.fillText(logo, 5, cvs.height-10);
ctx.restore();
}
window.onload = init;
</script>
Ideally, this would go all the way at the bottom before the end </body> tag, but I put it up higher because of my template system. Apparently, this gives the image time to load after the canvas element has been drawn to the screen and is ready to receive input.
I can't rely on setting the background of the canvas, and I have no desire to contend with refreshes. For whatever reason, just including the script with img.onload = function() {} was not enough. Move it lower, and save yourself the headaches.