Add image to HTML5 canvas on file upload issue - javascript

Allright, this is going to be quite hard to explain but I will try to explain my problem as clear as possible.
I currently have a HTML5 Canvas with a couple of preloaded shapes which I changed to images. I am using a modified version of this example. On the canvas I have now I can drag, drop and select the shapes which are preloaded.
I have implemented an option to upload a new image to the canvas using this:
var imageLoader = document.getElementById('uploader');
imageLoader.addEventListener('change', handleImage, false);
var canvas = document.getElementById('canvas1');
var ctx = canvas.getContext('2d');
function handleImage(e){
var reader = new FileReader();
reader.onload = function(event){
var imgNew = new Image();
imgNew.onload = function(){
ctx.drawImage(imgNew, 0, 0);
}
imgNew.src = event.target.result;
}
reader.readAsDataURL(e.target.files[0]);
}
This will now just put an image in the top-left corner of the canvas and when I select another shape this image will disappear. All shapes that are already in the canvas are in an array called 'shapes'. In the example there is an option to add a new shape when you dubbelclick on the canvas, this is the code:
// double click for making new shapes
canvas.addEventListener('dblclick', function(e) {
var mouse = myState.getMouse(e);
myState.addShape(new Shape(mouse.x - 10, mouse.y - 10, 20, 20, 'rgba(0,255,0,.6)'));
}, true);
This is the addShape part which is called when double clicking:
CanvasState.prototype.addShape = function(shape) {
this.shapes.push(shape);
this.valid = false;
}
What I am trying to do is when I upload an image using the file upload the image should be added to the 'shapes' array so I can also drag,drop and select the uploaded image. (basically I need to do the same with the uploaded image as I can do with the preloaded ones) My guess is that it should be done something like the doubleclick method and addShape but I can't get this to work.
A working version of my current version can be found here:
http://codepen.io/anon/pen/qLuCy/
If anyone knows how I can get this to work it would be great!

first the result, here : http://codepen.io/anon/pen/qBmnC/
Your shape object can only draw one single hard-coded image, so change this and have shape be either a color or an image. In fact for this you just have to change shape.draw since the 'type' of the fill does not matter in the constructor.
So just test the fill and draw accordingly :
// Tekent de Shape
Shape.prototype.draw = function(ctx) {
var locx = this.x;
var locy = this.y;
var fill = this.fill ;
if (typeof fill == 'string' )
{
ctx.fillStyle = fill;
ctx.fillRect(locx, locy, this.w, this.h);
}
else
{
ctx.drawImage(fill, locx, locy, this.w, this.h);
}
}
then on image load i just add a shape that has this image as fill :
function handleImage(e){
var reader = new FileReader();
reader.onload = function(event){
var imgNew = new Image();
imgNew.onload = function(){
s.addShape(new Shape(60,60,imgNew.width,imgNew.height,imgNew));
}
imgNew.src = event.target.result;
}
reader.readAsDataURL(e.target.files[0]);
}
I had to put the shape collection, s, as a global var.
You can also see that i used the same scheme in init() to
add an image once it's loaded.

Related

HTML Canvas - passing a background image to Canvas while it's also passing base64 data

I'm currently trying to do some Javascript work in Laserfiche forms which requires me to save the base64 data for an image in a separate text area, and feed that data back into the image to allow the canvas to be turned into an image in which I can save into the system.
The issue is I'm trying to have a background image in which the user can draw on (in this case, a vehicle that they can draw a circle on to indicate where the damage is). I am using sketch.js to allow the drawing part of the task.
From what I've read is that the background CSS cannot be saved into the canvas. That's fine but how do I pass the background image when I'm already grabbing the base64 data and passing that back into my canvas?
The saveimage class belongs to the text area and the imagefinish belong to the checkbox that they mark when the image is ready
html
<div class="demo" id="colors_demo">
<div class="tools">
Marker
Eraser
Download
</div>
<canvas id="colors_sketch" width="750" height="500" style="border:2px solid #000000 ; background: url(http://localhost/forms/img/vanImage.jpg"></canvas>
</div>
<input name="Field11" id="Field11-0" type="checkbox" value="isLocked" vo="e" data-parsley-class-handler="#Field11" data-parsley-errors-container="#Field11" data-parsley-multiple="Field11">
<textarea id="Field13" name="Field13" aria-labelledby="Field13" class="cf-medium" rows="3" vo="e" data-parsley-id="28"></textarea>
Javascript
//submitted form
if ($('[name=IsLocked]').val() == 'True') {
var myCanvas = document.getElementById('colors_sketch');
var ctx = myCanvas.getContext('2d');
var img = new Image;
img.onload = function() {
ctx.drawImage(this, 0, 0, myCanvas.width, myCanvas.height);
}
img.src = $('.saveimage .cf-field').text();
}
else {
//fill form
//$.getScript('http://localhost/Forms/js/sketch.js', function() {
$.getScript('https://rawgit.com/intridea/sketch.js/gh-pages/lib/sketch.js', function() {
//script is loaded and executed put your dependent JS here
$.each(['#f00', '#ff0', '#0f0', '#0ff', '#00f', '#f0f', '#000', '#fff'], function() {
$('#colors_demo .tools').append("<a href='#colors_sketch' data-color='" + this + "' style='width: 10px; background: " + this + ";'></a> ");
});
$.each([3, 5, 10, 15], function() {
$('#colors_demo .tools').append("<a href='#colors_sketch' data-size='" + this + "' style='background: #ccc'>" + this + "</a> ");
});
//$('#colors_sketch').sketch();
$('#colors_sketch').sketch({defaultColor: "#000"});
});
$('.imagefinish input').change(function(){
if(this.checked) {
var myCanvas = document.getElementById('colors_sketch');
$('.saveimage textarea').val(myCanvas.toDataURL());
}
});
}
I was able to add an image by adding a variable for my image path
var image = 'http://localhost/forms/img/vanImage.jpg'
and I also added the two lines to my onload for the style of "myCanvas". I have a feeling that this solution will only work because of how Laserfiches forms software works but the marked answer is also correct.
img.onload = function() {
ctx.drawImage(this, 0, 0, myCanvas.width, myCanvas.height);
myCanvas.style.backgroundRepeat = "no-repeat";
myCanvas.style.backgroundImage = 'url('+image+')'
}
img.src = $('.saveimage .cf-field').text();
}
Load the background image on page load, or an appropriate time and when the client is ready, draw the background onto the canvas behind the user content using ctx.globalCompositeOperation = "destination-over";
Create an image to hold the background.
const backgroundImage = new Image();
backgroundImage.src = "http://localhost/forms/img/vanImage.jpg";
You need to ensure that the image has loaded when the client clicks ready, incase it has not loaded you can set a callback that will call back the ready function if needed.
var backgroundLoadedCallback = null;
backgroundImage.onload = function(){
if( typeof backgroundLoadedCallback === "function"){
backgroundLoadedCallback();
}
}
Then create the canvas -> textarea function
function canvasToTextarea(){
const myCanvas = document.getElementById('colors_sketch');
const ctx = myCanvas.getContext("2d");
ctx.globalCompositeOperation = "destination-over"; // make sure the background go under the drawn pixels
// draw and fit background to the canvas
ctx.drawImage(backgroundImage,0,0,ctx.canvas.width,ctx.canvas.height);
// then convert to URL for textarea
$('.saveimage textarea').val(myCanvas.toDataURL());
}
In the checked function
$('.imagefinish input').change(function(){
if(this.checked) {
if(backgroundImage.complete) { // image has loaded so all good
canvasToTextarea(); // put canvas data URL to textarea
} else { // background has not yet loaded (or could be an error you will have to deal with that as well
// set the callback to the canvasToTextarea function
backgroundLoadedCallback = canvasToTextarea;
// when the background has loaded the canvas and background
// will be moved to the textarea as a data URL
}
}
});
Or modify sketch.js
Below is the draw function from sketch.js (and it`s very old school)
Sketch.prototype.redraw = function() {
var sketch;
this.el.width = this.canvas.width();
this.context = this.el.getContext('2d');
sketch = this;
$.each(this.actions, function() {
if (this.tool) {
return $.sketch.tools[this.tool].draw.call(sketch, this);
}
});
if (this.painting && this.action) {
return $.sketch.tools[this.action.tool].draw.call(sketch, this.action);
}
};
Just replace it with the following. You dont need to modify the sketch.js file justy overwrite the redraw Prototype
In your code load the background and set the new redraw
const backgroundImage = new Image();
backgroundImage.src = "http://localhost/forms/img/vanImage.jpg";
// replace Sketch.js redraw function
Sketch.prototype.redraw = function(){
var sketch;
// dont need the next line use clear instead
// this.el.width = this.canvas.width();
const ctx = this.context = this.el.getContext('2d');
// clear canvas
this.context.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
// If backgroundimage complete draw it first
if(backgroundImage && backgroundImage.complete){
ctx.drawImage(backgroundImage,0,0,ctx.canvas.width,ctx.canvas.height);
}
// back to the original code. :P
sketch = this;
$.each(this.actions, function() {
if (this.tool) {
return $.sketch.tools[this.tool].draw.call(sketch, this);
}
});
if (this.painting && this.action) {
return $.sketch.tools[this.action.tool].draw.call(sketch, this.action);
}
}

HTML Canvas Will Not Draw Image

Okay, I know that there are loads of subjects that look identical to this one on SO, but none of them have fixed my issue...
I'm trying to grab an image from a file input and throw it onto a canvas so that I can later turn it into a base-64 image... But I've hit a snag in the process that I was not expecting, in drawing the image to the canvas...
Taking the following HTML:
<input type="file" id="fileIn" onchange="preview()"><br>
<img id="filePreview"><br>
<canvas id="fileCanvas"></canvas>
And the following script:
var dataurl = '';
function preview(){
document.getElementById('filePreview').src = URL.createObjectURL(document.getElementById('fileIn').files[0]);
document.getElementById('filePreview').onload = showInCanvas;
cnv = document.getElementById('fileCanvas');
ctx = cnv.getContext('2d');
}
function showInCanvas(){
cnv.style.width = document.getElementById('filePreview').naturalWidth + 'px';
cnv.width = document.getElementById('filePreview').naturalWidth;
cnv.style.height = document.getElementById('filePreview').naturalHeight + 'px';
cnv.height = document.getElementById('filePreview').naturalHeight + 'px';
ctx.clearRect(0, 0, cnv.width, cnv.height);
ctx.drawImage(document.getElementById('filePreview'), 0, 0);
dataurl = cnv.toDataURL('image/png');
}
The problem I'm having is that the image simply refuses to draw onto the canvas. Even going into the console and drawing the image to the canvas manually, after the script has run, it still refuses to draw. Because of this, the image data simply runs through as data:,
It's an https site, if that affects anything.
For clarification, here's my question:
Why is the canvas refusing to render this image? How can I fix this issue?
If the intent is to convert the image to Data-URI ("base64"), the FileReader can be used - no need for canvas (which can also alter the image/final compression):
fileIn.onchange = function(e) {
var fr = new FileReader();
fr.onload = done.bind(fr);
fr.readAsDataURL(e.target.files[0]);
}
function done() {
var dataURI = filePreview.src = this.result;
alert(dataURI.substr(0, 35) + "...")
}
<input type="file" id="fileIn"><br>
<img id="filePreview"><br>
<canvas id="fileCanvas"></canvas>

Firefox drawing blank Canvas when restoring from saved base64

I am working with a single canvas that allows the user to click on a window pane in a window image. The idea is to show where the user has clicked. The image will then be modified (by drawing a grill on the window) and then saved to in JPEG. I am saving the canvas image prior to the click function because I don't want the selection box to show in the final image. However, Firefox often displays a blank canvas when restoring the canvas where IE and Chrome do not. This works perfectly in Chrome and IE. Any suggestions? Does Firefox have a problem with toDataURL()? Maybe some async issue going on here? I am also aware that saving a canvas in this fashion is memory intensive and there may be a better way to do this but I'm working with what I have.
Code:
/**
* Restores canvas from drawingView.canvasRestorePoint if there are any restores saved
*/
restoreCanvas:function()
{
var inverseScale = (1/drawingView.scaleFactor);
var canvas = document.getElementById("drawPop.canvasOne");
var c = canvas.getContext("2d");
if (drawingView.canvasRestorePoint[0]!=null)
{
c.clearRect(0,0,canvas.width,canvas.height);
var img = new Image();
img.src = drawingView.canvasRestorePoint.pop();
c.scale(inverseScale,inverseScale);
c.drawImage(img, 0, 0);
c.scale(drawingView.scaleFactor, drawingView.scaleFactor);
}
},
/**
* Pushes canvas into drawingView.canvasRestorePoint
*/
saveCanvas:function()
{
var canvas = document.getElementById("drawPop.canvasOne");
var urlData = canvas.toDataURL();
drawingView.canvasRestorePoint.push(urlData);
},
EXAMPLE OF USE:
readGrillInputs:function()
{
var glassNum = ir.get("drawPop.grillGlassNum").value;
var panelNum = ir.get("drawPop.grillPanelNum").value;
drawingView.restoreCanvas();
drawEngine.drawGrill(glassNum, panelNum,null);
drawingView.saveCanvas();
},
sortClick:function(event)
{
..... //Sorts where user has clicked and generates panel/glass num
.....
drawingView.showClick(panelNum, glassNum);
},
showClick:function(panelNum, glassNum)
{
var glass = item.panels[panelNum].glasses[glassNum];
var c = drawEngine.context;
drawingView.restoreCanvas();
drawingView.saveCanvas();
c.strokeStyle = "red";
c.strokeRect(glass.x, glass.y, glass.w, glass.h);
},
By just looking at the code setting the img.src is an async action to retrieve the image, so when you try to draw it 2 lines later to the canvas, it probably hasn't been loaded yet (having it in cache will make it return fast enough that it might work).
You should instead use an img.onload function to draw the image when it has loaded.
restoreCanvas:function()
{
var inverseScale = (1/drawingView.scaleFactor);
var canvas = document.getElementById("drawPop.canvasOne");
var c = canvas.getContext("2d");
if (drawingView.canvasRestorePoint[0]!=null)
{
c.clearRect(0,0,canvas.width,canvas.height);
var img = new Image();
img.onload = function() {
c.scale(inverseScale,inverseScale);
c.drawImage(img, 0, 0);
c.scale(drawingView.scaleFactor, drawingView.scaleFactor);
};
img.src = drawingView.canvasRestorePoint.pop();
}
},

How do I clear image for redrawing?

I need to find a way to change the picture when the user clicks on it, I seem to be having problems.
heres my code:
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var img = new Image();
img.src = 'Birthday.jpg';
img.onload = function() {
context.drawImage(img, 47, 90, 200, 300);
};
}
Ive already tried things like:
img.onclick = function() {
context.clearRect(47, 90, 200, 300);
img2.src = 'BirthdayOUT.jpg';
context.drawImage(img2, 47, 90, 200, 300);
};
When you paint an image to the canvas you do not paint the image element itself, just a bitmap representation.
This means that the img.onclick will never fire. Instead, you must manually keep track of where you drew the image and use a canvas onclick, determine if you clicked on the image, and then change the draw the new image.
you should create your img.onload function before you set the src, if not the onload may never fire.
I'm not sure what you're trying to achieve here but if you just want to have an image on the page, don't use the 'canvas' and change the image via the 'src' property.
However, if you want to have this on a canvas - which I suspect - you have to store the coordinates/dimensions of the image when it is drawn. Then, to change the picture, use 'clearRect()' to blank that area and draw the new image.
Note that in your code, the 'img' is not passed to the canvas as an element, but as a bitmap, as mentioned by 'Simon Sarris'. That means, your handler for the 'onclick' event must be assigned to the canvas. Then check whether the click occourred within the borders of the image. to achieve that, you need to access 'clientX' and 'clientY' from the event object which declare the position of the mouse click relative to the client area. Make sure to keep your img coordinates relative to the client area too.
Javascript:
window.onload = init;
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var img = new Image();
function init(){
img.src = 'Birthday.jpg';
context.drawImage(img, /* your img coords */ );
canvas.addEventListener('click', onCanvasClick);
}
function onCanvasClick(event){
var clickX = event.clientX;
var clickY = event.clientY;
if ( clickX > imgLeft && clickX < imgRight && clickY > imgTop && clickY < imgBottom ){ changePicture(); }
}
function changePicture(){
context.clearRect( /* your img coords */ );
img.src = /* new img URL */;
// save new img coords before next step
context.drawImage(img, /* your new img coords */ );
}
Image coordinates called 'imgLeft', 'ImgRight', 'ImgTop', 'imgBottom' / relative to client area!
You may have to modify the function name in 'addEventListener()', I'm not entirely sure. Maybe put the following:
canvas.addEventListener('click', function(){ onCanvasClick(); });
Your problem is not the clearing of the canvas, but the click event handling.
The img.onclick is not firing because the picture on the canvas is not an Image object. See this as an example.

Canvas - DrawImage Method

I got a strange problem with the "DrawImage"-Methode of the Canvas element. With the following code I create the canvas and attache it to the "rightcanvas" div.
var rightcanvas = document.getElementById('rightcanvas');
rcanvas = document.createElement('canvas');
rcanvas.setAttribute('width', canvasLength);
rcanvas.setAttribute('height', canvasHeight);
rcanvas.setAttribute('id', 'rcanvas');
rightcanvas.appendChild(rcanvas);
And now I try to draw a Base64 encoded image.
var rcontext = rcanvas.getContext('2d');
var image = new Image();
image.src = 'data:image/png;base64,iVBOR....';
rcontext.drawImage(image,0,0);
The canvas will be created and attached. But the image will not be displayed.Does somebody know what the problem is? =(
You have to wait for the image to load before drawing it to the canvas.
var image = new Image();
image.onload = function() {
rcontext.drawImage(image, 0, 0);
}
image.src = 'data:image/png;base64,iVBOR....';

Categories

Resources