Javascript canvas drawImage results in blank? -revised- - javascript

I'm working inside a lit-element component trying to draw an img element onto a canvas element:
return html`
<img></img>
<br>
<canvas width="1500" height="1500"></canvas>
<br>
<input type='file' accept='image/*' #change=${this.readImage}> </input>
`
readImage(event) {
// Get the image element
var img = this.shadowRoot.querySelector('img')
// Get the file
var file = event.target.files[0]
// File reader
var reader = new FileReader()
// Handle read
reader.onload = event=>{
img.src = event.target.result
// Get the canvas element
var canvas = this.shadowRoot.querySelector('canvas')
// Get the canvas context
var context = canvas.getContext('2d')
// Draw image on canvas
context.drawImage(img,0,0)
}
// Read the file
reader.readAsDataURL(file)
}
However for some reason the canvas element remains blank. I can't seam to find out where I'm going wrong or if I'm running into some kind of bug?

You need to use onload to make sure the image has finished loading. Is there a reason you aren't just using a new Image() object instead of using an embedded img element?
this.shadowRoot=document;
function
readImage(event) {
// Get the image element
var img = this.shadowRoot.querySelector('img')
// Get the file
var file = event.target.files[0]
// File reader
var reader = new FileReader()
// Handle read
reader.onload = event => {
img.onload = () => {
// Get the canvas element
var canvas = this.shadowRoot.querySelector('canvas')
// Get the canvas context
var context = canvas.getContext('2d')
// Draw image on canvas
context.drawImage(img, 0, 0)
}
img.src = event.target.result
}
// Read the file
reader.readAsDataURL(file)
}
<img></img>
<br>
<canvas width="1500" height="1500"></canvas>
<br>
<input type='file' accept='image/*' onchange=readImage(event)> </input>

Related

Changing img.src doesn't always load the new image immediately

I have a simple demo where users can select an image file, and I want to extract the RGB values of the image file as a ImageData. Here's my attempt:
<form>
<label for="img">Select image:</label>
<div>
<input type="file" id="img" name="img" accept="image/*" onchange="loadImage(this)">
</div>
</form>
<canvas id="origCanvas" .../>
function loadImage(input) {
if (input.files && input.files[0]) {
var imageFile = input.files[0]
var reader = new FileReader();
reader.onload = function() {
var img = new Image(CANVAS_WIDTH, CANVAS_HEIGHT);
img.src = reader.result;
readRGB(img);
}
reader.readAsDataURL(imageFile);
}
}
function readRGB(img) {
var c = document.getElementById("origCanvas");
var ctx = c.getContext("2d");
ctx.drawImage(img, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
imageData = ctx.getImageData(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
// do something else
}
However, when I keep selecting different files, readRGB only extracts the correct imageData some of the times. Other times the imageData I extracted are the old imageData that's already there on the canvas.
My gut feeling says that img.src = reader.result is an async operation, and it's at the mercy of the browser when img will be loaded. Many times when I try to ctx.drawImage(img), I end up drawing an empty canvas because img hasn't loaded the actual image file yet.
Is my guess correct, and what should I do in this case?

file input to blob using canvas

unable to insert blob to indexedDB please assint in inserting blob from file to indexedDB :)
CODE
<html>
<head>
<title>file to BLOB</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<div id="test">
<input id="File" type="file" accept="image/*" capture="user">
</div>
</body>
</html>
<script src="js/idbConn.js"></script>
Javascript
<script>
$(document).ready(function(){
$("#File").change(function(){
const File = this.files[0];
const cvs = document.createElement("canvas");
const optBlob = cvs.toBlob(function(cvsBlob){
let fileURL = URL.createObjectURL(File);
let imgFile = new Image();
let imgFile.src = fileURL;
imgFile.onload = function(){
cvs.width = imgFile.naturalWidth;
cvs.height = imgFile.naturalHeight;
let ctx = cvs.getContext("2d").drawImage(imgFile,0,0);
URL.revokeObjectURL(fileURL);
}
},File.type,0.3);
const data = new Object();
data.blob = optBlob;
let trx = db.transaction(["imgBlobs"],"readwrite").objectStore("imgBlobs").put(data,"test.jpeg");
});
});
</script>
trying to directly insert file into indexedDB but blob is as undefined
if kept cvsBlob in data.blob blank image is storing in indexedDB
There are a few problems.
HTMLCanvasElement.toBlob does not return anything. You get the blob in the callback function.
JavaScript is blocking, queued tasks (like the toBlob callback) events (like onload) will not run until the current execution has returned. This means that the line
const data = new Object(); is run before the toBlob callback has been called.
You are calling toBlob before you have created, loaded and drawn the image to the canvas.
let imgFile.src = fileURL; This line will throw a syntax error??
Fix
First load the image.
On image load create the canvas and draw the image on it.
Revoke the image url.
Convert the canvas to a blob.
In the toBlob callback add the blob to the DB.
Example
Call the function with the file you get from the file input. Eg $("#File").change(function() { saveImageToDB(this.files[0]) });
function saveImageToDB(file) {
const fileURL = URL.createObjectURL(file);
const img = new Image();
img.src = fileURL;
img.addEventListener("load", () => {
URL.revokeObjectURL(fileURL);
const cvs = document.createElement("canvas");
cvs.width = img.naturalWidth;
cvs.height = img.naturalHeight;
cvs.getContext("2d").drawImage(img, 0, 0);
cvs.toBlob(blob => {
// Code to add blob to database. Put your db code in here
db.transaction(["img"], "write").objectStore("imgs").put({blob}, file.name);
}, File.type, 0.3);
}, {once: true});
}

save and display image captured from input type=file

I have a webpage with capture image from the Available camera feature. For the web version it simply places the video capture onto a canvas. However for a phone, I am using <input class="btn btn-info" type="file" accept="image/*" id="cameraCapture" capture="camera"> to capture a picture. It asks the user to either capture the image using the phone's camera or upload from its filesystem/gallery etc. Once the image is clicked it simply places the image's name next to the button.
Is there a way to access this image and display it in the same page.
Thanks in advance
You can do that with JS using FileReader object.
Take a look at this answer: preview-an-image-before-it-is-uploaded
I hope it helps
var input = document.querySelector('input[type=file]');
input.onchange = function () {
var file = input.files[0];
drawOnCanvas(file);
};
function drawOnCanvas(file) {
var reader = new FileReader();
reader.onload = function (e) {
var dataURL = e.target.result,
c = document.querySelector('canvas'),
ctx = c.getContext('2d'),
img = new Image();
img.onload = function() {
c.width = img.width;
c.height = img.height;
ctx.drawImage(img, 0, 0);
};
img.src = dataURL;
};
reader.readAsDataURL(file);
}

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>

Uploading an image from computer to Fabric.JS Canvas

Are there any Fabric.JS Wizards out there?
I've done my fair research and I can't seem to find much of an explanation on how to add an image to the fabric.JS canvas.
User Journey:
a) User uploads an image from an input file type button.
b) As soon as they have selected an image from their computer I want to place it into the users canvas.
So far I've got to storing the image into an expression, this is my code below:
scope.setFile = function(element) {
scope.currentFile = element.files[0];
var reader = new FileReader();
/**
*
*/
reader.onload = function(event) {
// This stores the image to scope
scope.imageSource = event.target.result;
scope.$apply();
};
// when the file is read it triggers the onload event above.
reader.readAsDataURL(element.files[0]);
};
My HTML/Angular:
<label class="app-file-input button">
<i class="icon-enter"></i>
<input type="file"
id="trigger"
onchange="angular.element(this).scope().setFile(this)"
accept="image/*">
</label>
If you haven't guessed yet I am using a MEAN stack. Mongoose, Express, Angular and Node.
The scope imageSource is what the image is store in. I've read this SO
and it talks about pushing the image to the Image object with my result, and then pass it to the fabric.Image object. Has anyone done a similar thing that they can help me with?
Thanks in advance
**** UPDATE ****
Directive defines the canvas variable:
var canvas = new fabric.Canvas(attrs.id, {
isDrawingMode: true
});
Upload image from computer with Fabric js.
var canvas = new fabric.Canvas('canvas');
document.getElementById('file').addEventListener("change", function (e) {
var file = e.target.files[0];
var reader = new FileReader();
reader.onload = function (f) {
var data = f.target.result;
fabric.Image.fromURL(data, function (img) {
var oImg = img.set({left: 0, top: 0, angle: 00,width:100, height:100}).scale(0.9);
canvas.add(oImg).renderAll();
var a = canvas.setActiveObject(oImg);
var dataURL = canvas.toDataURL({format: 'png', quality: 0.8});
});
};
reader.readAsDataURL(file);
});
canvas{
border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.min.js"></script>
<input type="file" id="file"><br />
<canvas id="canvas" width="450" height="450"></canvas>
once you have a dataURL done, you can do either:
reader.onload = function(event) {
// This stores the image to scope
fabric.Image.fromURL(event.target.result, function(img) {
canvas.add(img);
});
scope.$apply();
};
Or you put on your image tag an onload event where you do:
var img = new fabric.Image(your_img_element);
canvas.add(img);
This is for drag and drop from desktop using the dataTransfer interface.
canvas.on('drop', function(event) {
// prevent the file to open in new tab
event.e.stopPropagation();
event.e.stopImmediatePropagation();
event.e.preventDefault();
// Use DataTransfer interface to access the file(s)
if(event.e.dataTransfer.files.length > 0){
var files = event.e.dataTransfer.files;
for (var i = 0, f; f = files[i]; i++) {
// Only process image files.
if (f.type.match('image.*')) {
// Read the File objects in this FileList.
var reader = new FileReader();
// listener for the onload event
reader.onload = function(evt) {
// put image on canvas
fabric.Image.fromURL(evt.target.result, function(obj) {
obj.scaleToHeight(canvas.height);
obj.set('strokeWidth',0);
canvas.add(obj);
});
};
// Read in the image file as a data URL.
reader.readAsDataURL(f);
}
}
}
});
Resources
https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/File_drag_and_drop

Categories

Resources