How to crop screenshot or image (.png) in nodejs? - javascript

Consider a image file .png
Consider you have the xy-cords of some element like x:400, y:500
Consider you have the size of image to be cropped: width: 50, height: 20
I have below snippet from nodejs pack easyimage and I have installed ImageMagick too.
When I run below code, it just passes but unable to crop image.
easyimage.crop(
{
src: "F:/screenshot.png", // Contains fullscreen image
dst: "F:/screenshot.png", // New image with cropped name
x: 400,
y: 500,
cropwidth: 50,
cropheight: 20,
gravity: "North-West",
},
(err, stdout, stderr) => {
if (err) throw err
}
)

I use sharp for this and it works pretty well
Try this
const sharp = require('sharp')
sharp('./kangta.jpg')
.extract({ left: 0, top: 0, width: 100, height: 100 })
.toFile('./kangta.new.jpg', function (err) {
if (err) console.log(err);
})
sharp: https://www.npmjs.com/package/sharp

Here I extend the example given above with a Puppeteer screenshot that gets split/cropped into multiple images with Sharp:
const puppeteer = require('puppeteer');
const sharp = require('sharp');
// original image
let originalImage = 'originalImage.jpg';
// file name for cropped image
let outputImage = 'croppedImage.jpg';
let outputConcat = '';
async function run(){
const browser = await puppeteer.launch({headless:true})
const page = await browser.newPage();
await page.setViewport({
width: 1920,
height: 1080,
deviceScaleFactor: 1,
});
await page.goto('https://en.wikipedia.org/wiki/Main_Page');
await page.screenshot({path: 'originalImage.jpg', fullPage:true});
await browser.close();
var sizeOf = require('image-size');
var dimensions = sizeOf('originalImage.jpg');
console.log(dimensions.width, dimensions.height);
const printText = (newHeight, newTop, imageIndex) => {
console.log('newHeight: ' + newHeight + ', newTop: ' + newTop + ', imageIndex: ' + imageIndex);
};
const cropImage = (newHeight, newTop, imageIndex) => {
sharp('originalImage.jpg')
.extract({left: 0, width: dimensions.width, height: newHeight, top: newTop})
.toFile(outputConcat.concat(imageIndex, outputImage))
};
var remainingTop = dimensions.height;
var cumulitiveTop = 0;
var amountOfImages = Math.ceil(dimensions.height / 1080);
for (let i = 0; i < amountOfImages; i++)
{
if(remainingTop >= 1080)
{
cropImage(1080, cumulitiveTop, i);
//printText(1080, cumulitiveTop, i);
}
else
{
cropImage(remainingTop, dimensions.height - remainingTop, i);
//printText(remainingTop, dimensions.height - remainingTop, i);
break;
}
remainingTop = remainingTop - 1080;
cumulitiveTop += 1080;
}
};
run();

Related

Face-api.js for detecting face expression not working on IOS

I am using face-api.js for detecting face expression.On IOS devices(Ipad, Iphone) camera is not getting opened but in android it is working fine.
Code That i am using
Can anyone help me why it is not getting opened on IOS please.
`
async ngOnInit() {
await Promise.all([faceapi.nets.tinyFaceDetector.loadFromUri('../../../assets/models'),
await faceapi.nets.faceLandmark68Net.loadFromUri('../../../assets/models'),
await faceapi.nets.faceRecognitionNet.loadFromUri('../../../assets/models'),
await faceapi.nets.faceExpressionNet.loadFromUri('../../../assets/models'),]).then(() => this.startVideo());
}
startVideo() {
this.videoInput = this.video.nativeElement;
navigator.getUserMedia(
{ video: {}, audio: false },
(stream:any) =>{ this.videoInput.srcObject = stream},
(err:any) =>{ console.log(err)}
);
this.detect_Faces();
}
async detect_Faces() {
this.elRef.nativeElement.querySelector('video').addEventListener('play', async () => {
this.show_tip = true;
this.canvas = await faceapi.createCanvasFromMedia(this.videoInput);
this.canvasEl = this.canvasRef.nativeElement;
this.canvasEl.appendChild(this.canvas);
this.canvas.setAttribute('id', 'canvass');
this.canvas.setAttribute(
'style',`position: fixed;
top: 0;
left: 0;
autoplay: true;
controls: true;
playsinline: true;
loop: true;`
);
this.displaySize = {
width: this.videoInput.width,
height: this.videoInput.height,
};
faceapi.matchDimensions(this.canvas, this.displaySize);
// setInterval(async () => {
this.detection = await faceapi.detectAllFaces(this.videoInput, new faceapi.TinyFaceDetectorOptions()).withFaceLandmarks().withFaceExpressions();
this.resizedDetections = faceapi.resizeResults(
this.detection,
this.displaySize
);
this.canvas.getContext('2d').clearRect(0, 0, this.canvas.width,this.canvas.height);
if (this.resizedDetections.length > 0 ) {
const canvas = document.createElement('canvas');
canvas.width = 1600;
canvas.height = 1200;
canvas.getContext('2d').drawImage(this.video.nativeElement, 0, 0);
const img = document.createElement("img");
// const dataUrl =
// img.src = canvas.toDataURL("image/png");
// img.src = URL.createObjectURL(p);
img.src = canvas.toDataURL().replace("image/base64", "image/webp");
// document.getElementById('screenshot').appendChild(img)
console.log(img.src);
this.faceSearch(img.src);
}
});
}
`
the same code is working on Android but not on IOS

Recording video from PIXI canvas with CCapture.js not working

I'm stuck with one task, maybe someone has experience to help with it.
For recording video I using CCapture.js, but when I start it everything stops with no errors.
My basic code is below.
I also created other example and you can see it stops at the beginning too:
https://codepen.io/fjtwmjzf-the-lessful/pen/zYZJwvQ
const
videoContainer = document.getElementById('videoContainer');
vw = 1280,
vh = 720,
videoUrl = 'assets/video/landscape.mp4';
PIXI.settings.RESOLUTION = 2;
app = new PIXI.Application({
width: vw,
height: vh,
backgroundColor: bgColor,
});
const videoBg = PIXI.Texture.from(videoUrl);
const videoSprite = new PIXI.Sprite(videoBg);
const videoControler = videoSprite._texture.baseTexture.resource.source;
videoContainer.appendChild(app.view);
let capturer = new CCapture( { format: 'webm' } );
let n = 0;
app.ticker.add(() => {
if(n == 0){
capturer.start();
}
capturer.capture(app.view);
if(videoControler.currentTime >= videoControler.duration){
capturer.stop();
capturer.save();
app.ticker.destroy();
}
n += 1;
});

Converting babel compiled code into regular js

I got an example code from codepen and I wanted to understand it better. I noticed that the js code is compiled with Babel. Since I'm quite new to JS I would be more comfortable to look at a standard javascript code, so I wanted to ask you if there's some way to convert a babel js into a regular js. I did some research but I couldn't find anything
By the way, this is the Babel code
const parent = document.getElementById("projects");
const closeButton = document.getElementById("project-close");
const projectItems = document.querySelectorAll(".project-item");
closeButton.addEventListener("click", onProjectClose);
projectItems.forEach(item => item.addEventListener("click", onProjectClick));
function onProjectClick(event) {
const { target } = event;
const { width, height, top, left } = target.getBoundingClientRect();
const clone = document.createElement("div");
clone.style.height = height + "px";
clone.style.width = width + "px";
clone.style.top = top + "px";
clone.style.left = left + "px";
clone.style.position = "absolute";
clone.style.zIndex = 10;
clone.classList.add("project-item");
clone.classList.add("clone");
clone.innerHTML = target.innerHTML;
document.body.appendChild(clone);
gsap.timeline().
to(clone, 1.5, {
position: "fixed",
top: 0,
left: 0,
width: "100%",
height: "100vh",
ease: Expo.easeInOut }).
add(() => document.body.classList.add("project-page")).
set(clone, {
overflow: "auto" });
}
function onProjectClose() {
document.body.classList.remove("project-page");
const clone = document.querySelector(".clone");
gsap.to(clone, 1, {
clipPath: "inset(100% 0 100% 0)",
ease: Sine.easeInOut,
onComplete() {
clone.remove();
} });
gsap.to(clone.querySelector("img"), 1, {
scale: 0.7,
ease: Sine.easeInOut });
}

Fabric js fit image in given size without stretching

Hello i am working on online print application where we create some designs in FabricJS and then users can edit those designing replacing text and image with their own...everything is working perfect but we are facing an issue with image replace when users replace image we want it to fit in already present image on canvas also maintain aspect ratio..below is current code for replacing image but its does not not fit image if image is vertical.
o = activeCanvas.getActiveObject();
fabric.Image.fromURL(src, function(m) {
var i = m.set({
id: o.id,
left: o.left,
top: o.top,
width: m.width,
height: m.height
});
i.scaleToWidth(o.getScaledWidth());
activeCanvas.remove(o);
activeCanvas.add(i);
renderAppChange();
zoomoutIn(1);
setActiveNew(i);
});
From what I see, you want to scale your new image to fit the smallest of width and height dimensions of the old image:
const widthFactor = old.getScaledWidth() / newImg.width
const heightFactor = old.getScaledHeight() / newImg.height
const minFactor = Math.min(widthFactor, heightFactor)
newImg.scale(minFactor)
Here, scale() will preserve the aspect ratio.
And a snippet to test:
const canvas = new fabric.Canvas("c")
const url = "https://via.placeholder.com/100x50"
const url2 = "https://via.placeholder.com/50x100"
const url3 = "https://via.placeholder.com/100x100"
fabric.Image.fromURL(url, (img) => {
canvas.add(img)
}, {
left: 0,
top: 10,
})
fabric.Image.fromURL(url2, (img) => {
canvas.add(img)
}, {
left: 120,
top: 10,
})
fabric.Image.fromURL(url3, (img) => {
canvas.add(img)
}, {
left: 200,
top: 10,
})
function insertAndFit (imageURL) {
const o = canvas.getActiveObject();
if (!o) {
throw new Error('select an object first')
}
fabric.Image.fromURL(imageURL, function(m) {
m.set({
left: o.left,
top: o.top
})
const widthFactor = o.getScaledWidth() / m.width
const heightFactor = o.getScaledHeight() / m.height
const minFactor = Math.min(widthFactor, heightFactor)
m.scale(minFactor)
canvas.remove(o)
canvas.add(m)
})
}
document.getElementById('b1').onclick = () => {
insertAndFit("https://via.placeholder.com/100x300")
}
document.getElementById('b2').onclick = () => {
insertAndFit("https://via.placeholder.com/300x100")
}
document.getElementById('b3').onclick = () => {
insertAndFit("https://via.placeholder.com/200x200")
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.3.2/fabric.js"></script>
<canvas id='c' width="400" height="200"></canvas>
<button id='b1'>insert 100x300</button>
<button id='b2'>insert 300x100</button>
<button id='b3'>insert 200x200</button>

Running an async method in a syncronized manner

I have a simple for loop, which basically checks if the images are stored in the file system, if not, then download it and render the UI:
for (var t = 0; t < toJSON.length; t++) {
if (t < 3) {
var view = Titanium.UI.createImageView({
width: 320,
height: 310,
//top: 10
});
image_url = toJSON[t];
//start
if (utilities.CheckIfImageExist(utilities.ExtractImageName(image_url))) {
var parent = Titanium.Filesystem.getApplicationDataDirectory();
var picture = Titanium.Filesystem.getFile(parent, 'pictures');
var picturePath = parent + 'pictures/';
Ti.API.info('picturePath: ' + picturePath);
var f = Titanium.Filesystem.getFile(picturePath, utilities.ExtractImageName(image_url));
var blob = f.read();
// here is saved blog file
console.log('Image already downloaded');
var width = blob.width;
var height = blob.height;
//crop so it fits in image view
if (width > height) {
view.image = ImageFactory.imageAsCropped(blob, {
width: height,
height: height,
x: 60,
y: 0
});
} else {
view.image = ImageFactory.imageAsCropped(blob, {
width: (width - 1),
height: (width - 1),
x: 60,
y: 0
});
}
} else {
//do new loop - async causing problems
alert('not downloaded');
// if image is not downloaded we will download it here
utilities.APIGetRequestImage(image_url, function (e) {
alert('begin downloaded');
var status = this.status;
if (status == 200) {
Ti.API.info(this.responseData);
//save to directory
utilities.SaveImageToDirectory(this.responseData, image_url);
//create view
var view = Titanium.UI.createImageView({
width: 320,
height: 310,
//top: 10
});
var width = this.responseData.width;
var height = this.responseData.height;
//crop so it fits in image view
if (width > height) {
var view = Titanium.UI.createImageView({
width: 320,
height: 310,
//top: 10
});
view.image = ImageFactory.imageAsCropped(this.responseData, {
width: height,
height: height,
x: 60,
y: 0
});
// $.scrollableView.addView(view);
viewArr.push(view);
} else {
view.image = ImageFactory.imageAsCropped(this.responseData, {
width: (width - 1),
height: (width - 1),
x: 60,
y: 0
});
viewArr.push(view);
//when t = 3, all views are put inside array, set image view
//if(t==3){
//}
}
}
}, function (err) {
alert('error downloading image');
});
}
}
}
The code, where it says "begin download" only executes after the for loop executes the first half of the IF statement (where it says "not downloaded"), by that t=3.
The for loop then executes the else statement, the trouble I have is that I need it to do it in a synchronized manner, as I am reliant on the t value to know which image to download and place in the view.
utilities.APIGetRequestImage(image_url, function(e) {
is a callback method which gets the file from the server and downloads it.
How can I get both methods to run concurrently?
Check it out:
for (var t = 0; t < toJSON.length; t++) {
if (t < 3) {
var view = Titanium.UI.createImageView({
width: 320,
height: 310,
//top: 10
});
image_url = toJSON[t];
//start
if (utilities.CheckIfImageExist(utilities.ExtractImageName(image_url))) {
var parent = Titanium.Filesystem.getApplicationDataDirectory();
var picture = Titanium.Filesystem.getFile(parent, 'pictures');
var picturePath = parent + 'pictures/';
Ti.API.info('picturePath: ' + picturePath);
var f = Titanium.Filesystem.getFile(picturePath, utilities.ExtractImageName(image_url));
var blob = f.read();
// here is saved blog file
console.log('Image already downloaded');
var width = blob.width;
var height = blob.height;
//crop so it fits in image view
if (width > height) {
view.image = ImageFactory.imageAsCropped(blob, {
width: height,
height: height,
x: 60,
y: 0
});
} else {
view.image = ImageFactory.imageAsCropped(blob, {
width: (width - 1),
height: (width - 1),
x: 60,
y: 0
});
}
} else {
//do new loop - async causing problems
alert('not downloaded');
// if image is not downloaded we will download it here
utilities.APIGetRequestImage(image_url, (function (t, image_url) {
return function (e) { // <----- wrap callback function
alert('begin downloaded');
var status = this.status;
if (status == 200) {
Ti.API.info(this.responseData);
//save to directory
utilities.SaveImageToDirectory(this.responseData, image_url);
//create view
var view = Titanium.UI.createImageView({
width: 320,
height: 310,
//top: 10
});
var width = this.responseData.width;
var height = this.responseData.height;
//crop so it fits in image view
if (width > height) {
var view = Titanium.UI.createImageView({
width: 320,
height: 310,
//top: 10
});
view.image = ImageFactory.imageAsCropped(this.responseData, {
width: height,
height: height,
x: 60,
y: 0
});
// $.scrollableView.addView(view);
viewArr.push(view);
} else {
view.image = ImageFactory.imageAsCropped(this.responseData, {
width: (width - 1),
height: (width - 1),
x: 60,
y: 0
});
viewArr.push(view);
//when t = 3, all views are put inside array, set image view
//if(t==3){
//}
}
}
};
})(t, image_url), function (err) {
alert('error downloading image');
});
}
}
}
By wrapping utilities.APIGetRequestImage callback, t and image_url are passed correctly.
When saying that you "need it to do it in a synchronized manner", then you don't actually. You say that you want to "get both methods to run concurrently", which requires asynchrony.
Just swap the check if(t==3) (which is always 3, and even if you did put a closure around it like #wachme suggested then it would just be 3 for the download that started last - not the one that ended last) for a check of the number of items you've received: if(viewArr.length==3). It will be 3 when all three callbacks are executed, and you can continue executing your tasks.

Categories