Resize image during upload (Canvas and SimpleImage library) - javascript

My goal is to have the user upload a local image. I draw this image in a canvas element. On top of this canvas element, I create another canvas, which I use to draw boxes on, so that the boxes overlay the uploaded image.
I want the image to be uploaded in a specific size, say maximum 100 width and maximum 100 height. It's not enough for me to have the image merely displayed at max-height and max-width: 100, it physically needs to be resized during the upload process. Because if I put a super big picture in a say 100x100 canvas, then the boxes on top of it become very small and I need them to be the same size regardless what size the image in the canvas is.
Below is the code:
HTML:
<div style="position: relative;">
<canvas id="can"
style="position: absolute; left: 0; top: 0; z-index: 0;max-width:80%;"></canvas>
<canvas id="box"
style="position: absolute; left: 0; top: 0; z-index: 1;max-width:80%;"></canvas>
</div>
<input type="file" multiple="false" accept="image/*" id="finput" onchange="upload()">
And JS:
function upload() {
//Get input from file input
var fileinput = document.getElementById("finput");
//Make new SimpleImage from file input
image = new SimpleImage(fileinput);
//Get canvas
var canvas = document.getElementById("can");
//Draw image on canvas
image.drawTo(canvas);
}
I use the simpleImage library because it lets me extract RGB values of the image.

let originalWidth;
let originalHeight;
let imageWidth;
let imageHeight;
const load = result => {
return new Promise((fulfill, _reject) => {
let imageObj = new Image();
imageObj.onload = () => fulfill(imageObj);
imageObj.src = result;
});
}
const upload = () => {
const fileinput = document.getElementById("finput");
const canvas = document.getElementById("can");
let context = canvas.getContext("2d");
const reader = new FileReader();
reader.onload = event => {
Promise.all([
load(event.target.result)
])
.then(images => {
originalWidth = images[0].width;
originalHeight = images[0].height;
imageWidth = originalWidth;
imageHeight = originalHeight;
imageWidth = 200; // Fixed value
// Value proportional to width. Keeping to scale without distorting the image ( recommended )
imageHeight = originalHeight * (imageWidth / originalWidth);
context.drawImage(images[0], positionX, positionY, imageWidth, imageHeight);
})
}
reader.readAsDataURL(fileinput);
}

Related

Clearing previous positions of canvas object and not the entire canvas

l believe to have a logic error in the way of which my logic is meant to find the previous coordinates of my canvas object, a moving image, and delete the frame drawn before it so that it does not duplicated the image every time it is drawn onto the canvas.
There is a reproducible demo below and l added comments where l believe the problem occurs.
var canvas = document.getElementById("c");
var ctx = canvas.getContext("2d");
var the_background = document.getElementById("the_background");
var imgTag = new Image();
var X_POS = canvas.width;
var Y_POS = 0;
imgTag.src = "http://i.stack.imgur.com/Rk0DW.png"; // load image
function animate() {
/* Error resides from here */
var coords = {};
coords.x = Math.floor(this.X_POS - imgTag);
coords.y = Math.floor(this.Y_POS - imgTag);
ctx.clearRect(coords.x, coords.y, X_POS, Y_POS);
/* To here */
ctx.drawImage(imgTag, X_POS, Y_POS);
X_POS -= 5;
if (X_POS > 200) requestAnimationFrame(animate)
}
window.onload = function() {
ctx.drawImage(the_background, 0, 0, canvas.width, canvas.height);
animate();
}
html,
body {
width: 100%;
height: 100%;
margin: 0px;
border: 0;
overflow: hidden;
display: block;
}
<html>
<canvas id="c" width="600" height="400"></canvas>
<img style="display: none;" id="the_button" src="https://i.imgur.com/wO7Wc2w.png" />
<img style="display: none;" id="the_background" src="https://img.freepik.com/free-photo/hand-painted-watercolor-background-with-sky-clouds-shape_24972-1095.jpg?size=626&ext=jpg" />
</html>
It seems logical to only clear the subset of the canvas that's changing, but the normal approach is to clear and redraw the entire canvas per frame. After the car moves, the background that's cleared underneath it needs to be filled in, and trying to redraw only that subset will lead to visual artifacts and general fussiness. Clearing small portions of the screen is a premature optimization.
Canvases can't keep track of much of anything other than pixels, so an animation is more like a flipbook of stationary frames and less like a cardboard cutout animation, where the same pieces of cardboard move along and overlap one another.
Math.floor(this.X_POS - imgTag) looks wrong -- imgTag is an image object, which doesn't make sense to subtract from a number. You may have meant to grab the x property from this.
Use image.onload to ensure the image is actually loaded before running the loop. It's a bit odd to use image tags in the DOM just to load images for a canvas. I'd do that programmatically from JS which saves some typing and makes it easier to manage the data.
const loadImg = url => new Promise((resolve, reject) => {
const img = new Image();
img.onerror = reject;
img.onload = () => resolve(img);
img.src = url;
});
const images = [
"https://img.freepik.com/free-photo/hand-painted-watercolor-background-with-sky-clouds-shape_24972-1095.jpg?size=626&ext=jpg",
"http://i.stack.imgur.com/Rk0DW.png",
];
Promise
.all(images.map(loadImg))
.then(([backgroundImg, carImg]) => {
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const car = {x: canvas.width, y: 0};
(function update() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(
backgroundImg, 0, 0, canvas.width, canvas.height
);
ctx.drawImage(
carImg, car.x, car.y, carImg.width, carImg.height
);
car.x -= 5;
if (car.x > 200) {
requestAnimationFrame(update);
}
})();
})
.catch(err => console.error(err))
;
<canvas id="canvas" width="600" height="400"></canvas>

Javascript crop image stored in buffer from coordinates

I found code that crops images in javascript using canvas but I need to crop an image that is never actually displayed anywhere since all I need is to get data from the image. There is a screenshot and then the buffered screenshot image needs to be cropped from specific coordinates.
The image is simply stored in a variable to begin with let img = new Image(). How could this code be modified to crop an image stored in the buffer only?
function resizeImage(url, width, height, x, y, callback) {
var canvas = document.createElement("canvas");
var context = canvas.getContext('2d');
var imageObj = new Image();
// set canvas dimensions
canvas.width = width;
canvas.height = height;
imageObj.onload = function () {
context.drawImage(imageObj, x, y, width, height, 0, 0, width, height);
callback(canvas.toDataURL());
};
imageObj.src = url;
}
Since no one answered I will post what I found. In the end I achieved what I needed using the library Sharp's extract feature.
img.onload = resizeImg;
img.src = 'image.png';
function resizeImg() {
this.path = this.path = 'image.png';
sharp(this.path)
.resize(this.width * 2, this.height * 2)
.extract({ width: 100, height: 20, left: 250, top: 100 })
.toBuffer({ resolveWithObject: true })
.then(({ data, info }) => {
//process data
})
}

jpg loaded with python keras is different from jpg loaded in javascript

I am loading jpg image in python on the server. Then I am loading the same jpg image with javascript on the client. Finally, I am trying to compare it with the python output. But loaded data are different so images do not match. Where do I have a mistake?
Python code
from keras.preprocessing.image import load_img
from keras.preprocessing.image import img_to_array
filename = './rcl.jpg'
original = load_img(filename)
numpy_image = img_to_array(original)
print(numpy_image)
JS code
import * as tf from '#tensorflow/tfjs';
photo() {
var can = document.createElement('canvas');
var ctx = can.getContext("2d");
var img = new Image();
img.onload = function() {
ctx.drawImage(img, 0, 0);
};
img.crossOrigin = "anonymous";
img.src = './rcl.jpg';
var tensor = tf.fromPixels(can).toFloat();
tensor.print()
}
You are drawing the image on a canvas before rendering the canvas as a tensor. Drawing on a canvas can alter the shape of the initial image. For instance, unless specified otherwise - which is the case with your code - the canvas is created with a width of 300 px and a height of 150 px. Therefore the resulting shape of the tensor will be more or less something like the following [150, 300, 3].
1- Using Canvas
Canvas are suited to resize an image as one can draw on the canvas all or part of the initial image. In that case, one needs to resize the canvas.
const canvas = document.create('canvas')
// canvas has initial width: 300px and height: 150px
canvas.width = image.width
canvas.height = image.heigth
// canvas is set to redraw the initial image
const ctx = canvas.getContext('2d')
ctx.drawImage(image, 0, 0) // to draw the entire image
One word of caution though: all the above piece should be executed after the image has finished loading using the event handler onload as the following
const im = new Image()
im.crossOrigin = 'anonymous'
im.src = 'url'
// document.body.appendChild(im) (optional if the image should be displayed)
im.onload = () => {
const canvas = document.create('canvas')
canvas.width = image.width
canvas.height = image.heigth
const ctx = canvas.getContext('2d')
ctx.drawImage(image, 0, 0)
}
or using async/await
function load(url){
return new Promise((resolve, reject) => {
const im = new Image()
im.crossOrigin = 'anonymous'
im.src = 'url'
im.onload = () => {
resolve(im)
}
})
}
// use the load function inside an async function
(async() => {
const image = await load(url)
const canvas = document.create('canvas')
canvas.width = image.width
canvas.height = image.heigth
const ctx = canvas.getContext('2d')
ctx.drawImage(image, 0, 0)
})()
2- Using fromPixel on the image directly
If the image is not to be resized, you can directly render the image as a tensor using fromPixel on the image itself

image preview before uploading -IOS

I have been trying to setup up an app to allow user to capture a photo and preview on canvas before uploading. So far i have been able to capture image and place onto canvas(android chrome), but when it comes to ios using safari i am having no such luck (tried Ipad, 5C)
here is the script i have manage to piece together thanks to the help of stackoverflow community (many thanks)
The issue I am having is that when i choose selected image it should display in my iframe (as it does in chrome) when i try safari it shows no image after selecting
here is a sample link to my app
SampleAPP
HTML
<img src="" id="image">
<input id="input" type="file" onchange="handleFiles()">
JAVASCRIPT
<script>
function handleFiles()
{
var filesToUpload = document.getElementById('input').files;
var file = filesToUpload[0];
// Create an image
var img = document.createElement("img");
// Create a file reader
var reader = new FileReader();
// Set the image once loaded into file reader
reader.onload = function(e)
{
img.src = e.target.result;
var canvas = document.createElement("canvas");
var MAX_WIDTH = 400;
var MAX_HEIGHT = 300;
var width = img.width;
var height = img.height;
if (width > height) {
if (width > MAX_WIDTH) {
height *= MAX_WIDTH / width;
width = MAX_WIDTH;
}
} else {
if (height > MAX_HEIGHT) {
width *= MAX_HEIGHT / height;
height = MAX_HEIGHT;
}
}
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, width, height);
var dataurl = canvas.toDataURL("image/png");
document.getElementById('image').src = dataurl;
}
// Load files into file reader
reader.readAsDataURL(file);
// Post the data
/*
var fd = new FormData();
fd.append("name", "some_filename.jpg");
fd.append("image", dataurl);
fd.append("info", "lah_de_dah");
*/
}
</script>
You can remove using <canvas> and set existing <img> src to e.target.result : data URI of uploaded File object at FileReader() load event.
You can defined variable width, use if condition at #image load event when new src is set to check #image .naturalWidth property, if value is greater than width , set #image.width to width variable.
<img src="" id="image">
<input id="input" type="file" onchange="handleFiles()">
<script>
var img = document.getElementById("image");
var width = 400;
function handleFiles() {
var filesToUpload = document.getElementById('input').files;
var file = filesToUpload[0];
// Create a file reader
var reader = new FileReader();
// Set the image once loaded into file reader
reader.onload = function(e) {
img.onload = function() {
if (this.naturalWidth > width) {
this.width = width;
}
}
img.src = e.target.result;
}
reader.readAsDataURL(file);
}
</script>

Image gets distorted when using css to set canvas height/width 100%

I am currently trying to draw an image to canvas, I have this so far:
"use strict";
var debugging = true;
var canvas = document.getElementById('astoniaCanvas');
var ctx = canvas.getContext('2d');
function loadUI() {
var topOverlay = new Image();
topOverlay.src = "/images/00000999.png";
topOverlay.onload = function() {
ctx.drawImage(topOverlay, 0, 0, canvas.width, 10);
}
var bottomOverlay = new Image();
bottomOverlay.src = "/images/00000998.png";
if (debugging) {
console.log('Drawing');
}
}
loadUI();
That works fine, but the image loads and looks like this:
When it should look like this:
The dimensions of the good looking picture are 800x40.
If I remove the
canvas {
width: 100%;
height: 100%;
}
the image goes back to looking normal, how can I scale my canvas?
Any information would be great thanks.
You arent accounting for height. Canvas can be confusing when it comes to height/width vs clientHeight/clientWidth
When you create a canvas the css width and height has no bearing on the number of pixels the internal canvas contains. Unless specifically set a canvas comes with a width height of 300x150.
A trick I have used in the past is to use the clientWidth and a scale to set everything
"use strict";
var debugging = true;
var canvas = document.getElementById('astoniaCanvas');
var ctx = canvas.getContext('2d');
function loadUI() {
var topOverlay = new Image();
topOverlay.onload = function() {
// use a scale between the image width and the canvas clientWidth
var scale = topOverlay.width / canvas.clientWidth;
var newWidth = canvas.clientWidth;
var newHeight = topOverlay.height * scale;
// resize canvas based on clientWidth
canvas.width = newWidth;
canvas.height = newHeight;
ctx.drawImage(topOverlay, 0, 0, newWidth, newHeight);
}
topOverlay.src = "http://i.stack.imgur.com/AJnjh.png";
// var bottomOverlay = new Image();
// bottomOverlay.src = "/images/00000998.png";
if (debugging) {
console.log('Drawing');
}
}
loadUI()
<canvas id="astoniaCanvas" style="width: 100%"></canvas>

Categories

Resources