Jimp : how to use new filename as parameter of write function? - node.js

I'm using Jimp module of NodeJS to do some image transformation in my (big) nodejs script inside a big loop where my filename is dynamically generated.
When doing my jimp image transformation, the filename provided to write function parameter is already changed. Because the write is inside a callback (so a another thread?) and my loop is already continue to process another loop step.
Here is an example overview:
for (var i = 0; i < 10; ++i) {
var filename = 'test' + i + '.png';
//some script to generate my image : pupperteer screenshot of a webpage
Jimp.read(filename).then(function (image) {
image.greyscale().write(filename);
}).catch(function (err) {
console.error(err);
});
}
In this example, my script create the file test1.png in color, then I can view a test2.png appear which is a copy of test1.png but in greyscale... Then it overwrite by a new color image named test2.png.
So I'm wondering how to solve this?
It's perfectly fine to have it in multithread, so how to use a copy of "filename" string to use it in parameter of write function?
Regards
Alex

use let instead of var
let filename = 'test' + i + '.png';

You have a problem with asynchrony. I think that you could create a method and send filename as param. For example:
for (var i = 0; i < 10; ++i) {
let filename = 'test' + i + '.png';
//some script to generate my image : pupperteer screenshot of a webpage
_saveImg(filename);
}
function _saveImg(name) {
const filename = name;
Jimp.read(filename).then(function (image) {
image.greyscale().write(filename);
}).catch(function (err) {
console.error(err);
});
}
=)

Related

Node Js Acessing a Jason File

still new to JSON and while ive searched the net and created a function to create a init file if none exists i'm coming up blank for search and retrive the data of the new existing file or how I add new entries or update new entries
so far i can do a read file and export the resits in a console log so i know the assignment work, its a global variable so the data should persist out of the read file loop but when i try and access it later to make the local array i'll pull data from and use for updating later it reads as undefined.
fs.readFile(path, 'utf8', (error, data) => {
if(error){
console.log(error);
return;
}
//console.log(JSON.parse(data));
JSONData = JSON.parse(data);
for (let i = 0; i < JSONData.length; i++) {
console.log(i+": ["+JSONData[i].unique+"] "+JSONData[i].name);
}
});//fs.readFile
var playerKey = "KuroTO";
playerKey = playerKey.toLowerCase();
for (let i = 0; i < JSONData.length; i++) {
if (JSONData[i].unique.toLowerCase() == playerKey){
console.log("["+i+"] "+JSONData[i].unique.toLowerCase()+": "+playerKey);
PlayerCard1.push(JSONData[i].userid);//0
PlayerCard1.push(JSONData[i].username);//1
PlayerCard1.push(JSONData[i].unique);//2
PlayerCard1.push(JSONData[i].name);//3
PlayerCard1.push(JSONData[i].avatarurl);//4
PlayerCard1.push(JSONData[i].level);//5
PlayerCard1.push(JSONData[i].Rank);//6
PlayerCard1.push(JSONData[i].henshined);//7
PlayerCard1.push(JSONData[i].Strength);//8
PlayerCard1.push(JSONData[i].Perception);//9
PlayerCard1.push(JSONData[i].Endurance);//10
PlayerCard1.push(JSONData[i].Wisdom);//11
PlayerCard1.push(JSONData[i].Intelligence)//12;
PlayerCard1.push(JSONData[i].Luck)//13;
PlayerCard1.push(JSONData[i].Agility)//14;
PlayerCard1.push(JSONData[i].Flexability)//15;
PlayerCard1.push(JSONData[i].RatedSpeed)//16;
};//if unique matches
};//for
this is ther psudo code concept im trying to do
if (JSONData.stringify.unique == {SearchUID}){toonname = JSONData.stringify.name;}
as i understand it you cant really apend just rewrite the file over again with new data and i think i can figure that out on my own once i cand figure out how to real the file into an array i can search like above
To read JSON, simply require the file.
JSON:
{
"key": "H"
}
JS:
let jsonFile = require("./path/to/json");
console.log(jsonFile.key); // H
Editing is just as simple.
let jsonFile = require("./path/to/json");
jsonFile.key = "A"
console.log(jsonFile.key) // A
Saving edits requires use of FileSystem:
const fs = require("fs")
let jsonFile = require("./path/to/json");
jsonFile.key = "A"
// first argument is the file path
// second argument is the JSON to write - the file is overwritten already
// due to above, so just JSON.stringify() the required file.
// third argument is an error callback
fs.writeFile("./path/to/jsonFile", JSON.stringify(jsonFile), (err) => {
if (err) throw new Error(err);
});
This can also be used to slightly clean up your current init function if you wanted, but that's up to you of course.

NodeJS - If moving multiple files fails, deleting ones that failed

I'm trying to upload multiple files with an HTTP post, and then NodeJS handles:
save files' info to database
move files from tmp folder to permanent folder
if any file move fails, delete the file from tmp folder
My two issues are described in the comments within code snippet below:
path.resolve isn't working
iterator isn't working within fs.rename
for (i = 0; i < req.files.length; i++) {
const file = new fileSchema({
_userId: req.body._userId,
_companyId: req.body._companyId,
_meetingId: response._id,
originalFilename: req.files[i].originalname,
savedFilename: req.files[i].filename,
});
file.save().then((response) => { }).catch(error => { console.log(error) });
const currentPath = path.resolve(temp_folder, req.files[i].filename);
const newPath = upload_folder +"/"+ req.body._userId +"/"+ req.body._companyId +"/"+ response._id +"/"+ req.files[i].filename;
// 1. why doesn't path.resolve work with the inputs on the line above? I have to concat a string as in line above?
fs.rename(currentPath, newPath, function(err) {
if (err) {
console.log("Error moving files");
try { removeTempFiles(temp_folder, req.files[i]); } // helper function which works written elsewhere
// 2. req.files[i] is undefined (even though req.files works) so the line above fails - i.e. the iterator isn't captured within rename?
catch(err) { console.log(err); }
} else {
console.log("Successfully moved the file!");
}
});
}
Any help appreciated, thanks.
Change this
for (i = 0; i < req.files.length; i++) {
to this:
for (let i = 0; i < req.files.length; i++) {
The addition of let will create a separate i for each iteration of the for loop so it will stay valid inside your fs.rename() callback.
And, path.join(), is probably a better choice than path.resolve() for combining path segments.

Loop problems with Telegram bot

I'm currently developping a telegram bot.
Here's my code:
bot.command('check', ctx => {
console.log(ctx.from.id, ctx.chat.id)
var files = getFilesFromDir("toSend", [".txt"])
if(files.length > 0){
for (i = 0; i < files.length; i++) {
const url = 'https://api.telegram.org/bot'+bot_token+'/sendDocument'
let r = request(url, (err, res, body) => {
if(err) console.log(err)
console.log(body)
})
console.log(files[i])
let f = r.form()
f.append('chat_id', '476090013')
f.append('document', fs.createReadStream("tosend/"+files))
}
}else{
console.log('r')
}
})
My problems is the loop, I tried the for but I can't figured out.
I have a folder named tosend, I want that every file in there to be transfered to telegram api.
For one file it's working but if in the folder there are more than one file, f.append('document', fs.createReadStream("tosend/"+files)) the +files take every name instead of one.
You're trying to create a stream from an array of files: +files (which will return a comma separated string with all the filenames).
You need to use files[i] to create a stream per file.
f.append('document', fs.createReadStream("tosend/" + files[i]))

Using socketio-file-upload to upload multiple files

Im using NodeJS with socket.io and socketio-file-upload to upload multiple files, it works great! However I'm having an issue where I'm trying to save the name attribute of the input these files come to save them into my DB.
When I upload 1 or more files, I can't seem to access the input field name or something that shows me which of the files come from which input field.
Here is my front:
var uploader = new SocketIOFileUpload(socket);
var array_files_lvl_3 = [
document.getElementById("l3_id_front"),
document.getElementById("l3_id_back"),
document.getElementById("l3_address_proof_1"),
document.getElementById("l3_address_proof_2"),
document.getElementById("l3_passport")
];
uploader.listenOnArraySubmit(document.getElementById("save_level_3"), array_files_lvl_3);
And here is my back:
var uploader = new siofu();
uploader.dir = "uploads/userL3";
uploader.listen(socket);
uploader.on('saved', function(evnt){
console.log(evnt);
//this "event" variable has a lot of information
//but none of it tells me the input name where it came from.
});
This is what the "evnt" variable holds:
Unfortunately the library doesn't send that information. So there is nothing existing config you can do. So this needs code modification.
client.js:374
var _fileSelectCallback = function (event) {
var files = event.target.files || event.dataTransfer.files;
event.preventDefault();
var source = event.target;
_baseFileSelectCallback(files, source);
client.js:343
var _baseFileSelectCallback = function (files, source) {
if (files.length === 0) return;
// Ensure existence of meta property on each file
for (var i = 0; i < files.length; i++) {
if (source) {
if (!files[i].meta) files[i].meta = {
sourceElementId: source.id || "",
sourceElementName: source.name || ""
};
} else {
if (!files[i].meta) files[i].meta = {};
}
}
After these changes I am able to get the details in event.file.meta
I'm the author of socketio-file-upload.
It looks like the specific input field is not currently being recorded, but this would not be a hard feature to add. Someone opened a new issue and left a backpointer to this SO question.
A workaround would be to directly use submitFiles instead of listenOnArraySubmit. Something like this might work (untested):
// add a manual listener on your submit button
document.getElementById("save_level_3").addEventListener("click", () => {
let index = 0;
for (let element of array_files_lvl_3) {
let files = element.files;
for (let file of files) {
file.meta = { index };
}
uploader.submitFiles(files);
index++;
}
});

Resize and Upload Image Flow in NodeJS

All,
I have an array of sizes such as sizes = [20,40,60,80]
I need to loop over those, resize the src image to each size and name them appropriately.
Then, using knox, upload them to s3, and then remove the resized image.
Here is what I have:
http://jsfiddle.net/bpoppa/ZAcA7/
The problem is the flow control. When knox tries to putFile, I get an error saying it doesn't exist, which means knox is either running before the resize is done or it is already deleted at that point.
Any tips? All help is appreciated.
Thanks!
You need to remember that node.js code runs asynchronously. In your original code, the knox code is running before image.resize has completed (the callback is used to tell you when the operation has completed, not just to handle errors). Node won't wait for the callback and just continues to execute code in your function. You also need to be careful of using anonymous callbacks in for loops without creating a closure.
In general you want to use the callbacks to control program flow like the code below so that you only do the following action when the preceding action has completed.
var src = name + '.jpg';
for (var i = sizes.length - 1; i >= 0; i--) {
var k = i;
var dest = sizes[k] + '.jpg';
var s3 = sizes[k] + '.jpg';
resizeAndPut(src, dest, s3, sizes[k]);
}
fs.unlink(src);​ /* delete the source file now */
var resizeAndPut = function (src, dest, s3, size) {
easyimage.resize(
{
src: src,
dst: dest,
width: size,
height: size
}, function(err, image) {
if (err) throw err;
knox.putFile(dest, s3, function(err, res) { /* does image contain the path?, if so, might want to use image.path or the like instead of dest here */
if (err) throw err;
fs.unlink(dest); /* delete the local file*/
});
});
};

Resources