How to draw a dragged and droppped image on to a canvas - javascript

I drag and drop images on to a canvas using below code . Can someone please tell me how to draw it on a canvas? Thanks in advance.Earlier my canvas used to be a div and I used to append img to that div and it worked.But now I want it to be drawn to a canvas.
function dropb(ev) {
ev.preventDefault();
const dt = ev.dataTransfer;
const files = dt.files;
handleFilesb(files);
}
function handleFilesb(files) {
for (let i = 0; i < files.length; i++) {
const file = files[i];
if (!file.type.startsWith('image/')) {
continue
}
const img = document.createElement("img");
img.className = "my_image";
img.setAttribute("width", "300px");
img.setAttribute("height", "300px");
img.classList.add("obj");
img.file = file;
document.getElementById("area_c"); // canvas
var ctx = c.getContext("2d");
ctx.drawImage(img, 10, 10); // this line is not working
const reader = new FileReader();
reader.onload = (function(aImg) {
return function(e) {
aImg.src = e.target.result;
};
})(img);
reader.readAsDataURL(file);
}
}
<div style="display:flex">
<canvas id ="area_c" style="width:300px;height:300px;border:3px solid black;z-index:1" ondrop="dropb(event)" ondragover="myfkb(event)" >
</canvas>
<div id ="area_c2" style="width:300px;height:300px;border:3px solid black;z-index:1" >
</div>
<div >
<input type="button" value="Crop"
onclick="crop()">
</div>
</div>

ctx.drawImage(img) comes before img.src... There is no way your image gets drawn.
You need to wait until it loads, and that will be only after the FileReader onload event fired, and even after the img's onload fires:
img.onload = e => {
ctx.drawImage(img, 10, 10);
};
const reader = new FileReader();
reader.onload = (function(aImg) {
return function(e) {
aImg.src = e.target.result;
};
})(img);
reader.readAsDataURL(file);
But you don't need the FileReader here, use a blob URL instead:
img.onload = e => {
ctx.drawImage(img, 10, 10);
};
img.src = URL.createObjetURL(file);
const c = document.getElementById("area_c");
c.ondragover = e => {
e.preventDefault();
}
c.ondrop = dropb;
const ctx = c.getContext("2d");
function dropb(ev) {
ev.preventDefault();
const dt = ev.dataTransfer;
const files = dt.files;
handleFilesb(files);
}
function handleFilesb(files) {
for (let i = 0; i < files.length; i++) {
const file = files[i];
if (!file.type.startsWith('image/')) {
continue
}
const img = document.createElement("img");
img.className = "my_image";
img.setAttribute("width", "300px");
img.setAttribute("height", "300px");
img.classList.add("obj");
img.file = file;
img.onload = e => {
ctx.drawImage(img, 10, 10);
};
img.src = URL.createObjectURL(file);
}
}
canvas {
border: 1px solid
}
<canvas id="area_c">
</canvas>

Related

Canvas doesn't save as image properly, just blank transparent image

I'm looping through an array of image elements (from a local folder) and attaching them to a canvas and at the end I would like to save the canvas as an image but it is not being saved properly. The resulting image matches the dimensions of the canvas but it is just a blank transparent image.
If in test.js I don't save the canvas to an image and I instead use resolve(canvas) I can display it perfectly in index.html so I know that the canvas is being written properly.
There are also no error messages displayed in the Google Chrome console.
Test.js
class Test {
constructor() {}
createPoster(images) {
return new Promise((resolve, reject) => {
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
let locX = 0;
for (let i = 0, len = images.length; i < len; ++i) {
let image = images[i];
image.onload = () => {
ctx.drawImage(image, locX, 0);
locX += image.width;
};
}
let poster = new Image();
poster.crossOrigin = 'anonymous';
poster.onload = () => {
resolve(poster);
};
poster.src = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream');
});
}
}
Index.html
<script type="module">
const Test = require('./test.js');
let test = new Test();
async function main() {
// let images = Get array of image elements from another library.
let poster = await test.createPoster(images).catch((err) => console.log(err));
document.body.appendChild(poster); // Displays just a transparent image with the same dimensions as the canvas.
}
</script>
You need to check for all image loaded before you create your poster image.
createPoster(images) {
return new Promise((resolve, reject) => {
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
let locX = 0;
let imageLoaded = 0;
for (let i = 0, len = images.length; i < len; ++i) {
let image = images[i];
image.onload = () => {
ctx.drawImage(image, locX, 0);
locX += image.width;
imageLoaded++;
if (imageLoaded == len) {
let poster = new Image();
poster.crossOrigin = 'anonymous';
poster.onload = () => {
resolve(poster);
};
poster.src = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream');
}
};
// image.src = ..
}
});
}

all image gets appended to last container div in multiple upload

I am working on a multiple file upload system.File upload works fine.Problem arises when i've decided to show a preview div before file reading complete.For this purpose i create a container div inside for loop and tried to insert image in that container.Problem is that file is only gets appended to last container div.
function handleDragOver(event)
{
event.stopPropagation();
event.preventDefault();
event.dataTransfer.dropEffect = 'copy';
document.getElementById('drop_zone').innerHTML="";
}
function handleDragLeave()
{
document.getElementById('drop_zone').style.background = 'white';
}
function handleFileSelect(event)
{
event.stopPropagation();
event.preventDefault();
var files = event.dataTransfer.files;
for(var i=0,file;file=files[i];i++){
if(i>=files.length){
break;
}
var reader = new FileReader();
var container = document.createElement('div');
reader.onloadstart = function (){
container.setAttribute('style','background:gray;padding:5px;width:100px;height:100px;margin:10px;float:left;border:1px solid gray;');
document.getElementById('drop_zone').appendChild(container);
};
reader.onload = (function(myfile){
return function(event){
var img = new Image();
img.src = event.target.result;
img.width = 100;
img.height = 100;
container.style.background = 'white';
container.appendChild(img);
}
})(file);
reader.readAsDataURL(file);
}
}
function handleFileUpload()
{
var dropZone = document.getElementById('drop_zone');
dropZone.addEventListener('dragover', handleDragOver, false);
dropZone.addEventListener('dragleave', handleDragLeave, false);
dropZone.addEventListener('drop', handleFileSelect, false);
}
handleFileUpload();
<div id="drop_zone" style="width:95%;border:4px dotted gray;float:left;min-height:100px;text-align:center;line-height:100px;color:gray;font-size:25px;">
Drop files here
</div>
Use a closure within for loop to reference current file
for (var i = 0, file; file = files[i]; i++) {
(function(file) {
// do stuff with `file` here
// `file` is current `File` object
})(file);
}
change for loop in handleFileSelect(event)
for(var i=0,file;file=files[i];i++){
if(i>=files.length){
break;
}
var reader = new FileReader();
reader.onloadstart = function (){
/*
container.setAttribute('style','background:gray;padding:5px;width:100px;height:100px;margin:10px;float:left;border:1px solid gray;');
document.getElementById('drop_zone').appendChild(container);
*/
};
reader.onload = (function(myfile){
return function(event){
var container = document.createElement('div');
container.setAttribute('style','background:gray;padding:5px;width:100px;height:100px;margin:10px;float:left;border:1px solid gray;');
document.getElementById('drop_zone').appendChild(container);
var img = new Image();
img.src = event.target.result;
img.width = 100;
img.height = 100;
container.style.background = 'white';
container.appendChild(img);
}
})(file);
reader.readAsDataURL(file);
}

How to compress image size in JavaScript?

I am trying to compress image size using JavaScript. but it returns canvas error.
below is my code.
var reader = new FileReader();
reader.readAsDataURL(fileItem._file);
reader.onload = function (event) {
var base64 = event.target.result.substring(event.target.result.indexOf(',') + 1, event.target.result.length);
var cvs = document.createElement('canvas');
var source_img_obj = event.target.result;
cvs.width = source_img_obj.naturalWidth;
cvs.height = source_img_obj.naturalHeight;
var ctx = cvs.getContext("2d").drawImage(source_img_obj, 0, 0);
var newImageData = cvs.toDataURL(type, 70 / 100);
var result_image_obj = new Image();
result_image_obj.src = newImageData;
console.log(result_image_obj);
};
Error:
I think you are looking something like this~
This implementation has two methods to reduce the size of the image. One method resize the image while the other compress it maintaining the same size but it reduces the quality.
This implementation is based on FileReader() to read the contents of files (or raw data buffers for Blob objects) stored on the user's computer.
// Console logging (html)
if (!window.console) console = {}
const consoleOut = document.getElementById('console-out')
console.log = message => {
consoleOut.innerHTML += message + '<br />'
consoleOut.scrollTop = consoleOut.scrollHeight
}
const outputFormat = 'jpg'
const encodeButton = document.getElementById('jpeg-encode-button')
const encodeQuality = document.getElementById('jpeg-encode-quality')
function previewFile() {
const preview = document.getElementById('source-image')
const previewResize = document.getElementById('result-resize-image')
const previewCompress = document.getElementById('result-compress-image')
const file = document.querySelector('input[type=file]').files[0]
const reader = new FileReader()
reader.onload = e => {
preview.onload = () => {
resizeFile(preview, previewResize)
compressFile(preview, previewCompress)
}
preview.src = e.target.result
// preview.src = reader.result
}
if (file) {
reader.readAsDataURL(file)
}
}
function resizeFile(loadedData, preview) {
console.log('Image resizing:')
console.log(`Resolution: ${loadedData.width}x${loadedData.height}`)
const canvas = document.createElement('canvas')
canvas.width = Math.round(loadedData.width / 2)
canvas.height = Math.round(loadedData.height / 2)
preview.appendChild(canvas)
// document.body.appendChild(canvas)
const ctx = canvas.getContext('2d')
ctx.drawImage(loadedData, 0, 0, canvas.width, canvas.height)
console.log(`New resolution: ${canvas.width}x${canvas.height}`)
console.log('---')
}
function compressFile(loadedData, preview) {
console.log('Image compressing:')
console.log(`width: ${loadedData.width} | height: ${loadedData.height}`)
const quality = parseInt(encodeQuality.value)
console.log(`Quality >> ${quality}`)
const timeStart = performance.now()
console.log('process started...')
const mimeType = typeof outputFormat !== 'undefined' && outputFormat === 'png' ? 'image/png' : 'image/jpeg'
const canvas = document.createElement('canvas')
canvas.width = loadedData.width;
canvas.height = loadedData.height;
const ctx = canvas.getContext('2d').drawImage(loadedData, 0, 0)
const newImageData = canvas.toDataURL(mimeType, quality / 100)
const img = new Image()
img.src = newImageData
preview.src = img.src
preview.onload = () => {}
const duration = performance.now() - timeStart;
console.log('process finished...')
console.log(`Processed in: ${duration}ms`)
console.log('---')
}
<input type="file" onchange="previewFile()"><br>
<div>
<h3>Original Image</h3>
<img id="source-image" />
</div>
<div>
<h3>Resized Image</h3>
<div id="result-resize-image">
</div>
</div>
<div>
<h3>Compressed Image</h3>
<img id="result-compress-image" class='img-container' />
</div>
<br><br>
<div>
<fieldset>
<legend>Compressor settings</legend>
<div id='controls-wrapper'>
Compression ratio : <input id="jpeg-encode-quality" size='3' readonly='true' type="text" value="30" /> %
</div>
</fieldset>
</div>
<div>
<fieldset>
<legend>Console output</legend>
<div id='console-out'></div>
</fieldset>
</div>
You might have to resize the canvas size
refer the following example
here
function resizeImg(base, width, height) {
var canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
var context = canvas.getContext("2d");
var deferred = $.Deferred();
$("<img/>").attr("src", "data:image/gif;base," + base).load(function() {
context.scale(width/this.width, height/this.height);
context.drawImage(this, 0, 0);
deferred.resolve($("<img/>").attr("src", canvas.toDataURL()));
});
return deferred.promise();
}
To compress a File (got from input type file) you can use this function. Just call it with the file, and it will return the same file but compressed:
const compressImage = (imageFile, quality) => {
return new Promise((resolve, reject) => {
const $canvas = document.createElement("canvas");
const image = new Image();
image.onload = () => {
$canvas.width = image.width;
$canvas.height = image.height;
$canvas.getContext("2d").drawImage(image, 0, 0);
$canvas.toBlob(
(blob) => {
if (blob === null) {
return reject(blob);
} else {
resolve(blob);
}
},
"image/jpeg",
quality / 100
);
};
image.src = URL.createObjectURL(imageFile);
});
};
Usage is:
<input type="file" id="my_input">
And JS:
const $inputFile = document.querySelector("#my_input");
$inputFile.addEventListener("change", async () => {
const file = $inputFile.files[0];
const blob = await compressImage(file, 50);
// Upload the blob with FormData or something similar
console.log({ blob });
});

HTML5 Drag and Drop only images

What i'm trying to do is : if all the dragged files was images drop them, but if there was other file exstensions don't drop them, but drop the images only.
Here's my try :
HTML :
<div id="dropzone"></div>
Javascript :
var dropzone = document.getElementById("dropzone");
dropzone.ondrop = function (e) {
e.preventDefault();
e.stopPropagation();
var files = e.dataTransfer.files;
for(x = 0; x < files.length; x = x + 1){
if(files[x].type.split("/")[0] == 'image') {
console.log(files[x].name + "is image");
}else {
console.log(files[x].name + "is not image");
}
}
}
i need to loop through the files that i dragged and if the file was image do something otherwise do something else, for example
file.jpeg is image
file.txt is not image
But using my code if i dragged other file extension with the image it's not dropping the image, it's skipping both files.
The point is : Dropping only images.
You could use the FileReader and test the file type for an image like this:
// don't try to process non-images
var imageType = /image.*/;
if (file.type.match(imageType)) {
// it's an image, process it
}
Here's example code and a Demo:
// dropzone event handlers
var dropzone;
dropzone = document.getElementById("dropzone");
dropzone.addEventListener("dragenter", dragenter, false);
dropzone.addEventListener("dragover", dragover, false);
dropzone.addEventListener("drop", drop, false);
//
function dragenter(e) {
e.stopPropagation();
e.preventDefault();
}
//
function dragover(e) {
e.stopPropagation();
e.preventDefault();
}
//
function drop(e) {
e.stopPropagation();
e.preventDefault();
var dt = e.dataTransfer;
var files = dt.files;
handleFiles(files);
}
//
function handleFiles(files) {
for (var i = 0; i < files.length; i++) {
// get the next file that the user selected
var file = files[i];
var imageType = /image.*/;
// don't try to process non-images
if (!file.type.match(imageType)) {
continue;
}
// a seed img element for the FileReader
var img = document.createElement("img");
img.classList.add("obj");
img.file = file;
// get an image file from the user
// this uses drag/drop, but you could substitute file-browsing
var reader = new FileReader();
reader.onload = (function(aImg) {
return function(e) {
aImg.onload = function() {
// draw the aImg onto the canvas
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = aImg.width;
canvas.height = aImg.height;
ctx.drawImage(aImg, 0, 0);
// make the jpeg image
var newImg = new Image();
newImg.onload = function() {
newImg.id = "newest";
document.body.appendChild(newImg);
}
newImg.src = canvas.toDataURL('image/jpeg');
}
// e.target.result is a dataURL for the image
aImg.src = e.target.result;
};
})(img);
reader.readAsDataURL(file);
} // end for
} // end handleFiles
body {
background-color: ivory;
}
canvas {
border: 1px solid red;
}
#dropzone {
border: 1px solid blue;
width: 300px;
height: 300px;
}
<h4>Drag file(s) from desktop to blue dropzone.<br>Only image files will be processed.</h4>
<div id="dropzone"></div>
<div id="preview"></div>

canvas and img working in chrome but not firefox

I have searched a few results regarding this issue but none of them works for me, so I am posting here to get some helps. Basically my issue is when I clicked on the generate button, I want the image from canvas to be displayed in a img element. However, the image will show up in chrome but not firefox! Below is my coding...
<body onload="onLoad();">
<canvas id="aimage">Your browser does not support the canvas tag.</canvas>
<input type="button" value="Generate" onclick="genImage();" />
<img id="cImg" name="cImg" src="${param.src}" />
...
</body>
And the javascript...
var tcanvas;
var scanvas;
var tcontext;
var imageURL;
function onLoad() {
tcanvas = document.getElementById("aimage");
tcontext = tcanvas.getContext("2d");
scanvas = document.getElementById("cImg");
imageURL = "${param.src}";
update();
}
function update() {
var image = new Image();
image.onload = function () {
if (image.width != tcanvas.width)
tcanvas.width = image.width;
if (image.height != tcanvas.height)
tcanvas.height = image.height;
tcontext.clearRect(0, 0, tcanvas.width, tcanvas.height);
tcontext.drawImage(image, 0, 0, tcanvas.width, tcanvas.height);
}
image.crossOrigin = 'anon';
image.src = imageURL;
}
function genImage() {
var url = tcanvas.toDataURL("image/jpeg");
scanvas.crossOrigin = 'anon';
scanvas.src = url;
if(scanvas.width > 1000){
scanvas.width = 1000;
}
if(scanvas.height > 1000){
scanvas.height = 1000;
}
}
try this:
var scanvas, tcontext, tcanvas;
function genImage() {
var url = tcanvas.toDataURL("image/jpeg");
scanvas.src = url;
if (scanvas.width > 1000) {
scanvas.width = 1000;
}
if (scanvas.height > 1000) {
scanvas.height = 1000;
}
}
window.onload = function () {
tcanvas = document.getElementById("aimage");
tcontext = tcanvas.getContext("2d");
scanvas = document.getElementById('cImg');
var img = new Image();
img.onload = function () {
tcontext.drawImage(img, 0, 0, img.width, img.height)
};
img.src = "yourImage.jpg";
}

Categories

Resources