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
})
}
Related
I have a Gatsby application using the CMS Contentful. I have implemented Image Focal Point on Contentful which returns x and y coordinates for image cropping. I have tried using HTML Canvas to resize the image based on the coordinates from Image Focal Point but with no luck.
Here is what I have tried:
const resizeImage = (url, width, height, x, y, callback) => {
const canvas = document.createElement("canvas")
const context = canvas.getContext("2d")
const imageObj = new Image()
canvas.width = width
canvas.height = height
imageObj.src = url
imageObj.setAttribute("crossorigin", "anonymous")
imageObj.onload = function () {
context.drawImage(imageObj, x, y, width, height, x, y, width, height)
callback(canvas.toDataURL())
}
return imageObj.src
}
I pass in the url for the image, the width and height of said image, the x and y coordinates from Image Focal Point and a callback:
resizeImage("my-image.png", 1000, 500, 300, 600, (url) => {url})
This returns the same src url as I inputted and does not crop the image to the desired xy coordinates. Any guidance is greatly appreciated!
You may have had security issues, specifically this: for security reasons, your local drive is declared as "other domain" and it will stain the canvas. and for this reason his image was not cropped. I ran into this problem with an image of a server while replicating your code, so be careful.
I generated a codesandbox with your code, let me know if you want to cut the image in this way
const resizeImage = (url, width, height, x, y, callback) => {
var canvas = document.createElement("canvas");
var context = canvas.getContext("2d");
const imageObj = new Image();
canvas.width = width;
canvas.height = height;
imageObj.src = url;
imageObj.crossOrigin = "anonymous"; //WARNING!
imageObj.onload = () => {
context.drawImage(imageObj, x, y, width, height, 0, 0, width, height);
const url = canvas.toDataURL();
callback(url);
};
};
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
I am trying to show previews of uploaded images in a canvas. The preview should be a square version of image.
What I have:
var img = new Image;
img.src = imageSrc;
var c = document.getElementById('file-preview-' + data.response.id);
var ctx = c.getContext("2d");
img.onload = function() {
ctx.drawImage(img, 0, 0);
};
And the preview:
So how can I draw on the canvas a 150x150 square with maintained ratio cropped version of the image?
For example for this image:
I should get:
Here's a method that yields precisely the result you desire, cropped, resized and centered (with commented out lines that yield a left based cropping instead)...
var ctx;
function init(event) {
ctx = document.getElementById('canvas').getContext('2d');
// Your preview is actually 120x120,
// but I've stuck with the textual description of
// your requirements here.
ctx.canvas.width = 150;
ctx.canvas.height = 150;
loadBackground('http://i.stack.imgur.com/PCKEo.png');
}
function loadBackground(path) {
var img = new Image();
img.onload = drawBackground;
img.src = path;
}
function drawBackground(event) {
var img = event.target;
var imgSize = Math.min(img.width, img.height);
// The following two lines yield a central based cropping.
// They can both be amended to be 0, if you wish it to be
// a left based cropped image.
var left = (img.width - imgSize) / 2;
var top = (img.height - imgSize) / 2;
//var left = 0; // If you wish left based cropping instead.
//var top = 0; // If you wish left based cropping instead.
ctx.drawImage(event.target, left, top, imgSize, imgSize, 0, 0, ctx.canvas.width, ctx.canvas.height);
}
window.addEventListener('load', init, false);
<canvas id="canvas"></canvas>
Based on information from this question: SO Question
I was able to modify what was done to create a square cropped image in canvas:
var img = new Image;
img.src = "http://cdn.bmwblog.com/wp-content/uploads/2016/02/M-Performance-Parts-BMW-M2-3.jpg"; //Or whatever image source you have
var c= document.getElementById('file-preview');
var ctx=c.getContext("2d");
img.onload = function(){
ctx.drawImage(img, img.width/2, img.height/2, img.width, img.height, 0, 0, img.width, img.height);
};
You just have to modify the arguments you are passing to the drawImage function as well as add some more.
You can see a fiddle here: https://jsfiddle.net/4d93pkoa/3/
Remember that the first two parameters specify the image's top left coordinates within the canvas element.
Remember to set the width and height of the canvas element in HTML to a square shape.
with this code I try to update a canvas with a drawn image when imageUpdated is true.
I use a timetag so the image isnt loaded from the browser cache.
But when i use timetags the canvas stays empty.
It works without the timetags.
var imageUpdated = true;
if(imageUpdated)
{
imageUpdated = false;
var heightImg = new Image;
heightImg.src = '/path/to/image.png?' + new Date().getTime().toString();
this.canvas = $('<canvas />')[0];
this.canvas.width = this.width;
this.canvas.height = this.height;
this.canvas.getContext('2d').drawImage(heightImg, 0, 0, this.width, this.height);
}
/*rest of event happens here*/
Thanks!
Probably it's because you're drawing the image before it is loaded.
I guess that's also the reason it works without the timetag, it's already in cache so can instantly be drawn.
A solution would be to draw after the image is loaded. So, add an eventListener on the image:
image.addEventListener('load', callback);
Within the callback, draw the image on the canvas.
For example:
// add eventlistener
heightImg.addEventListener('load', function(e) {
var width = heightImg.width;
var height = heightImg.height;
var canvas = document.querySelector('canvas');
canvas.width = width;
canvas.height = height;
canvas.getContext('2d').drawImage(heightImg, 0, 0, width, height);
});
// trigger the loading
heightImg.src = url + '?time=' + new Date().getTime().toString();
And a Fiddle
So I am creating a cordova app where I take a photo from the iphone library, draw it to canvas and add another image to it in order to save it as one photo. So far the photo I draw from the iphone photo library gets drawn without problems to the canvas, however the second image doesn't.
When I load the second image, it first gets added to a div with absolute positioning in order to move it to wherever I want. After that I get the actual image it's source and it's positions and try to draw it to canvas. The drawing of the second image happens when I call a method that also performs the canvas2ImagePlugin it's functions. In the end only the first photo without the second image gets saved.
The draw image to canvas function:
function drawImage(image_source, dx, dy)
{
var canvas = document.getElementById('Photo');
var image = new Image();
image.src = image_source;
image.onload = function() {
c=canvas.getContext("2d");
c.canvas.width = window.innerWidth;
c.canvas.height = window.innerHeight;
c.drawImage(image,dx,dy, window.innerWidth, window.innerHeight);
}
}
The method for drawing the second image and saving it:
function saveImage()
{
var img = $('.ObjectImage').attr('src', $('img:first').attr('src'));
var imagePosition = $('.ObjectImage').find('img:first').position();
drawImage(img, imgPosition.left, imgPosition.top);
window.canvas2ImagePlugin.saveImageDataToLibrary(
function(msg){
console.log(msg);
},
function(err){
console.log(err);
},
document.getElementById('Photo')
);
alert("Image saved");
}
The window.innerWidth, window.innerHeight on the canvas is done to get the canvas in full screen of the parent div.
EDIT to the comment:
function drawImage(image_source, dx, dy)
{
var canvas = document.getElementById('Photo');
var image = new Image();
image.onload = function() {
c=canvas.getContext("2d");
c.canvas.width = window.innerWidth;
c.canvas.height = window.innerHeight;
c.drawImage(image,dx,dy, window.innerWidth, window.innerHeight);
}
image.src = image_source;
}
Still not working
The drawImage function works asynchronously, it starts loading an image and exits immediately. Then, when the image loads, the canvas is updated. If you run something like:
drawImage('test.jpg',0,0);
drawImage('test2.jpg',0,0);
you will get both images updating the canvas at approximately the same time and only one will appear.
Also, what wolfhammer said is correct. If you set the size of the canvas, you clear it, so drawing one image after the other, even if they are smaller sizes and should both appear, will only show the last one. Check this link on how to solve it: Preventing Canvas Clear when Resizing Window
Further more, you are drawing all images with the width and height of the window, which doesn't make sense. Probably you want to use the width and height of the image (so this.width instead of window.innerWidth)
When you set the width and height of the canvas the data on "Photo" is cleared. I've provide a resize function if resizing is really needed.
function drawImage(image_source, dx, dy)
{
var canvas = document.getElementById('Photo');
var image = new Image();
image.src = image_source;
image.onload = function() {
c=canvas.getContext("2d");
//c.canvas.width = window.innerWidth;
//c.canvas.height = window.innerHeight;
c.drawImage(image,dx,dy, window.innerWidth, window.innerHeight);
}
}
var can = document.getElementById('can');
var ctx = can.getContext('2d');
ctx.fillStyle = "red";
ctx.beginPath();
ctx.moveTo(20, 90);
ctx.lineTo(50, 10);
ctx.lineTo(80, 90);
ctx.lineTo(10, 40);
ctx.lineTo(90, 40);
ctx.lineTo(20, 90);
ctx.fill();
var btn = document.getElementById('btnResize');
btn.addEventListener('click', function() {
resize(can, can.width * 2, can.height * 2);
});
function resize(can, w, h) {
var ctx = can.getContext('2d');
// copy
var can2 = document.createElement('canvas');
var ctx2 = can2.getContext('2d');
can2.width = can.width;
can2.height = can.height;
ctx2.drawImage(can, 0, 0);
// resize
can.width = w;
can.height = h;
ctx.drawImage(can2, 0, 0, can2.width, can2.height, 0, 0, w, h);
}
#can {
border:1px solid red;
}
<button id='btnResize'>Size x 2</button><br/>
<canvas id="can" width="100" height="100"></canvas>