Currently, I have an async function that pulls in an image from a remote URL, to then draw it on a canvas. I made sure that the canvas is the same size of the listing image. Below is the code that is not working:
async function loadAndprocessListingImage(listingImageURL){
const listingImage = await loadImage(listingImageURL);
const width = listingImage.width;
const height = listingImage.height;
const canvas = createCanvas(width, height);
const context = canvas.getContext('2d');
context.drawImage(listingImage, width, height); <=== (Code fails here)
return canvas.toDataURL();
}
I can't get any error logs either, I just get a timeout. I am running a NodeJS lambda.
Canvas is being pulled in a layer.
I can write to the canvas, but I cannot draw the image onto the canvas.
Related
I am using sharp to resize bulk of image. So I am resizing them to 500px by preserving their aspect ratio. Also I want to resize height to 500px and auto resize width if height is greater than with and vice versa. To do that I need to get image, height from Image buffer. I know there are pretty number of packages available to do so. But I was hoping if I can do that using sharp buffer itself.
Yes you can get the width and height of an image with sharp by using the metadata() function :
const image = await sharp(file.buffer)
const metadata = await image.metadata()
console.log(metadata.width, metadata.height)
You can get a lot more information from metadata , here is the documentation : https://sharp.pixelplumbing.com/api-input#metadata
To get the dimensions that are recorded in the header of the input image:
const image = await sharp(file.buffer);
const metadata = await image.metadata();
console.log(metadata.width, metadata.height);
However, operations like image.resize(...) will not affect the .metadata(). To get the dimensions after performing operations on the image, use .toBuffer({ resolveWithObject: true }):
const image = await sharp(file.buffer);
const resizedImage = image.resize(640);
const { info } = await resizedImage.png().toBuffer({ resolveWithObject: true });
console.log(info.width, info.height);
Sharp is very flexible, it has a number of options for resizing images. Using an option of fit: "contain" should accomplish what you wish.
Others are available of course, documented here: https://sharp.pixelplumbing.com/api-resize#resize
You can also specify the background color to fill space within the resized image, I'm using white here.
The code will look something like this:
const fs = require("fs");
const path = require("path");
const sharp = require("sharp");
const inputDir = "./input-images";
const outputDir = "./output-images";
const requiredDimension = 500;
const inputImages = fs.readdirSync(inputDir).map(file => path.join(inputDir, file));
function resizeImage(imagePath) {
sharp(imagePath)
.resize( { width: requiredDimension, height: requiredDimension, fit: "contain", background: { r: 255, g: 255, b: 255, alpha: 1 }})
.toFile(path.join(outputDir, path.basename(imagePath) + "-resized" + path.extname(imagePath)), (err, info) => {
if (err) {
console.error("An error occurred resizing image:", err);
}
});
}
// Ensure output dir exists...
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir)
}
inputImages.forEach(resizeImage);
I would like to tranform canvas ImageData (of type Uint8ClampedArray) into a n image matrix using opencv4nodejs npm package.
https://www.npmjs.com/package/opencv4nodejs
https://github.com/justadudewhohacks/opencv4nodejs#readme
The github README explains clearly how to transform an image matrix into canvas ImageData, but it does not show what methods to use for the opposite.
const img = ...
// convert your image to rgba color space
const matRGBA = img.channels === 1
? img.cvtColor(cv.COLOR_GRAY2RGBA)
: img.cvtColor(cv.COLOR_BGR2RGBA);
// create new ImageData from raw mat data
const imgData = new ImageData(
new Uint8ClampedArray(matRGBA.getData()),
img.cols,
img.rows
);
I would like to know how to convert a gray-scale canvas ImageData into the a matGRAY. (or a rgba ImageData into BGR matrix). Either strategy would be very helpful to me! I haven't found other documentation for this yet.
Goal:
const ctx = canvas.getContext('2d');
const imageData = ctx.getImageData(0,0,canvas.width, canvas.height);
//Then something like this....
// const matGRAY = opencv4nodejs.imagedata2matrix(imageData);
const _ = require('lodash'); // allows fast array transformations in javascript
const Canvas = require('canvas'); //node-canvas on server side
const cv = require('opencv4nodejs');
You can receive the Uint8ClampedArray image data from client directly
..but here we will create it from scratch.
const canvas = Canvas.createCanvas('2d');
const ctx = getContext('2d');
const image = new Canvas.Image();
image.onload = () => {
ctx.drawImage(image,0,0);
}
image.src = 'path/to/image.jpg'
//get imageData from the image on our canvas
const imageDataObject = ctx.getImageData(0,0,canvas.width,canvas.height);
const imageData = imageDataObject.data;
const width = imageDataObject.width;
const height = imageDataObject.height;
//imageData is Uint8ClampedArray
Now that we have the Uint8ClampedArray, we can convert to matrix
// convert to normal array
const normalArray = Array.from(imageData);
//nest the pixel channels
const channels = 4 //canvas pixels contain 4 elements: RGBA
const nestedChannelArray = _.chunk(normalArray, channels);
const nestedImageArray = _.chunk(nestedChannelArray, height);
//nestedImageArray is the correct shape to be converted to matrix.
const RGBAmat = new cv.Mat(nestedImageArray, cv.CV_8UC4);
//openCV often defaults to BGR-type image matrix, so lets color convert the pixel order
const BGRAmat = RGBAmat.cvtColor(cv.COLOR_RGBA2BGRA);
BGRAmat is an openCV matrix, ready for processing!
In case you are new to Node.js, here is the terminal code to get started.
First, install Node.js then run at your terminal
$ mkdir canvasToMatrix
$ cd canvasToMatrix
$ npm init -y
$ npm install lodash canvas opencv4nodejs
Create new file.js, and paste in the code above. After saving, run
$ node file.js
I am trying to read a image and the result i want to get is the same when you use a HTML canvas "Uint8ClampedArray"? var imageData = ctx.getImageData(0, 0, width, height); I found a NPM lib canvas but i cant get it to install.
So is there a another way to go without using Canvas?
To strictly answer the question:
So is there a another way to go without using Canvas?
The issue is that, even if we can load an image binary data, we need to be able to parse its binary format to represent it as raw pixel data (ImageData/Uint8Array objects).
This is why the canvas module needs to be compiled when installed: it rely on and links to libpng, libjpeg and other native libraries.
To load a Uint8Array representing pixel raw data from a file, without canvas (or native library wrapper), will requires decoders running only in Javascript.
For e.g. there exist decoders for png and jpeg as third-party libraries.
Decoding PNG
Using png.js:
const PNG = require('png-js');
PNG.decode('./image.png', function(pixels) {
// Pixels is a 1d array (in rgba order) of decoded pixel data
});
Decoding JPEG
Using inkjet:
const inkjet = require('inkjet');
inkjet.decode(fs.readFileSync('./image.jpg'), function(err, decoded) {
// decoded: { width: number, height: number, data: Uint8Array }
});
https://github.com/gchudnov/inkjet
Do not realy know what i did to get canvas to work. I used pixel-util to set image data.
var pixelUtil = require('pixel-util'),
Canvas = require('canvas');
var image = new Canvas.Image,
pixelUtil.createBuffer('http://127.0.0.1:8080/image/test.jpg').then(function(buffer){
image.src = buffer;
canvas = new Canvas(image.width, image.height);
var ctx = canvas.getContext('2d');
ctx.drawImage(image, 0, 0);
runImage(ctx.getImageData(0, 0, canvas.width, canvas.height));
});
After much struggling, I've managed to get node-canvas installed on Windows.
When I try to read in the image size of a GIF, however, it just gives me back 0 for the width and height.
var FileSystem = require('fs');
var Canvas = require('canvas');
FileSystem.readdir(baseDir, function(err, files) {
files.forEach(function(filename) {
var path = Path.join(baseDir, filename);
FileSystem.readFile(path, function(err, buf) {
var img = new Canvas.Image;
img.src = buf;
console.log(path, img.width, img.height);
});
});
Is it not supposed to be able to read GIFs?
You must install giflib and reinstall node-canvas like is said in here https://github.com/LearnBoost/node-canvas/wiki/Installation---OSX and then you will be able to manipulate your gif file (retrieve width/height). But beware, the image processed with canvas will stop being animated.
What I'm trying to do is draw svg image on canvas and then create a PNG image of this canvas.
Here is an example of what I do:
var canvas = document.getElementById('mycanvas');
var ctx = canvas.getContext('2d');
var img = new Image();
img.onload = function () {
ctx.drawImage(this, 0, 0, this.width, this.height);
var url = canvas.toDataURL("image/png");
}
img.crossorigin = "Anonymous"; //not sure this affects anything...
img.src="some image url"
When I set a source of png/jpeg image it works fine but then the src is of a svg image I get "Uncaught Error: SECURITY_ERR: DOM Exception 18" when calling "canvas.toDataURL("image/png")".
I don't understand what's the difference?
The same happens when I take an inline svg and render it inside the canvas and then try to create the png image. I don't have the code right now with me - I'll add it later if necessary.
I found a solution. Apparently canvas has another function to draw svgs "drawSvg" so I used it and it works.