Web Server saving images as 0 bytes - node.js

When I send an image to my web server through an http request, it manages to save the original image with its full size. But when I attempt to resize the image, it saves it as 0 bytes. Im using an npm module called sharp to do the image resizing. When I do any resizing, even massive resizing jobs on my local machine, there are no issues. Running this code on my Apache web server causes it to not actually save the images most of the time. It seems completely random which images it actually saves. The only consistent part is that it saves the original image sent through the http request.
In my filesystem there will be the original image EG: abcdefg.jpg, and then abcdefg-350x350.jpg will be 0 bytes.
const results = await temp.mv(path.resolve(folderName + name + '.' + extension))
bluebird.map(sizes, (size) => {
sharp(folderName + name + '.' + extension)
.resize(size.w, size.h, {
fit: 'cover'
})
.toFile(folderName + name + '-' + size.w + 'x' + size.h + '.' + extension)
console.log('Resized image')
})
.then(() => {
console.log('Images were resized')
if (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'testing') {
console.log('Images resized and going back');
res.status(200).json({'location': '/imageserving/uploads/' + year + '/' + month + '/' + name + '.' + extension, fileIndex: '1'});
}
else if (process.env.NODE_ENV === 'production') {
//possibly use req.hostname
res.status(200).json({'location': 'mysite/uploads/' + year + '/' + month + '/' + name + '.' + extension, fileIndex: '1'});
}
})

Try updating this line:
sharp(folderName + name + '.' + extension)
to this:
return sharp(folderName + name + '.' + extension)
...that should make sure the following then() section is properly chained to the promise and avoids potential race conditions that may be causing the inconsistent behavior.

Related

fs.rename not operative, however original and target name paths seem correct

I am using Node.js and Multer to upload some image files to an "uploads" folder. That part seems to be working fine. I wish to rename the files after uploading so the proper file extensions (.jpg, .png, .gif, etc) are appended to the filenames.
I am attempting to use 'fs.rename' to accomplish this however it fails. I receive no errors...and the 'original' path and the 'target' path to rename seem to be correct when I examine my console logs. My code is below...does anybody have an explanation for this? This is very confusing, I thank you in advance.
//A means of ensuring only images are uploaded.
//note 'files' is an array of image files, omitted for clarity
var len = files.length;
var i;
for (i = 0; i < len; i++) {
if (files[i] != "undefined") {
const host = req.hostname;
const filePath = req.protocol + "://" + host + '/' + files[i].path;
const image = files[i].mimetype.startsWith('image/');
const type = files[i].mimetype.toString();
if(image) {
console.log('photo #' + i + ' uploaded');
console.log('uploaded file: ' + files[i].filename + ' saved within: ' + files[i].destination + ' at path: ' + files[i].path);
console.log('photo #' + i + ' filepath: ' + filePath);
console.log('photo #' + i + ' image extension is: ' + type);
console.log('photo #' + i + ' TYPEOF is: ' + typeof type);
var cutoff = type.split("/"); //"split" on "backslash"
var oldPath = req.protocol + "://" + host + ':8080' + '/uploads/' + files[i].filename
var targetPath = req.protocol + "://" + host + ':8080' + '/uploads' + '/image' + i + "." + cutoff[1]
console.log('photo #' + i + ' cutoff: ' + cutoff[1]);
console.log('ORIGINAL path for photo #' + i + ' is: ' + oldPath);
console.log('RENAMED target path for photo #' + i + ' is: ' + targetPath);
fs.rename(oldPath, targetPath, function(err) {
if (err) {
console.log("Unable to rename photo #" + i + " file...!")
} else {
console.log("Successfully renamed the file!")
}
})
// ...save filePath to database...if desired...
} else {
console.log("file # " + i + " received--however wrong format");
}
} //if NOT 'undefined'
} //for loop
Here is the output of a run to show the console logs:
photo #0 uploaded
uploaded file: identification-1572752074000 saved within: ./uploads at path: uploads\identification-1572752074000
photo #0 filepath: http://localhost/uploads\identification-1572752074000
photo #0 image extension is: image/jpeg
photo #0 TYPEOF is: string
photo #0 cutoff: jpeg
ORIGINAL path for photo #0 is: http://localhost:8080/uploads/identification-1572752074000
RENAMED target path for photo #0 is: http://localhost:8080/uploads/image0.jpeg
photo #1 uploaded
uploaded file: identification-1572752074015 saved within: ./uploads at path: uploads\identification-1572752074015
photo #1 filepath: http://localhost/uploads\identification-1572752074015
photo #1 image extension is: image/jpeg
photo #1 TYPEOF is: string
photo #1 cutoff: jpeg
ORIGINAL path for photo #1 is: http://localhost:8080/uploads/identification-1572752074015
RENAMED target path for photo #1 is: http://localhost:8080/uploads/image1.jpeg
Unable to rename photo #2 file...!
Unable to rename photo #2 file...!
The other strange thing is the loop advances to 'photo #2'...which should not be since there are only 2 images in the 'files' array ('0' and '1')...not sure if that is related to my problem here. Thanks for any suggestions.
You are passing URLs to fs.rename(). It requires local OS file paths, not URLs.
I don't know exactly where things are in your local file system or if they even are in your local file system, but you could try changing this:
var oldPath = req.protocol + "://" + host + ':8080' + '/uploads/' + files[i].filename
var targetPath = req.protocol + "://" + host + ':8080' + '/uploads' + '/image' + i + "." + cutoff[1]
to this:
var oldPath = '/uploads/' + files[i].filename
var targetPath = '/uploads' + '/image' + i + "." + cutoff[1]
Assuming the /uploads directory is on the local file system and the /uploads/image directory already exists.

Extract original name & date from m2ts (mpeg2-ts) files

I want to extract the original name and date-taken from m2ts files in Node.
I found some dead code (m2ts-parser) using the package "packet". Though I'm too novice to really understand. But I want to learn :-)
So can anyone tell me how to extract the original filename and original creation date of the m2ts file (in node, but any pseudo code will do :-)
Thanks
update
I found - based on the answer of #aergistal a partial solution.
I am able to extract the Date/Time original from an m2ts file. Tested only on a Canon and Panasonic file:
var fs = require('fs');
fs.open('C:/temp/28685338476.mts', 'r', function (status, fd) {
if (status) {
console.log(status.message);
return;
}
var chunk = new Buffer(10000);
var syncFound = false;
var i, l;
fs.read(fd, chunk, 0, 10000, 0, function (err, num) {
for (i = 0, l = chunk.length; i < l; i++) {
if (chunk[i] === 0x47) {
syncFound = true;
}
if (syncFound) {
if (chunk[i] === 0x66 && chunk[i + 1] === 0x4D && chunk[i + 2] === 0x44 && chunk[i + 3] === 0x50 && chunk[i + 4] === 0x4D) {
console.log("GOT 'MDPM' at byte ", i);
var yy = chunk[i + 8].toString(16) + chunk[i + 9].toString(16);
var MM = chunk[i + 10].toString(16);
var dd = chunk[i + 12].toString(16);
var hh = chunk[i + 13].toString(16);
var mm = chunk[i + 14].toString(16);
var ss = chunk[i + 15].toString(16);
var timeStamp = yy + "/" + MM + "/" + dd + " " + hh + ":" + mm + ":" + ss;
console.log("TimeStamp: "+ timeStamp);
return timeStamp;
}
}
}
});
});
There is no such information in the MPEG-TS container.
This kind of metadata might be included in one of the elementary streams in which case its location will be different for every stream type. To make things worse there's no common standard even for the same type.
For example if your m2ts file contains a H.264 video stream such metadata might be found within the Supplemental Enhancement Information (SEI) if provided. The structure is described in the H.264 standard.
Once you know where the data is you will need to find out what format it uses. One example is the Modified Digital Video Pack Metadata (MDPM) which is supported by the exiftool and might contain a DateTimeOriginal tag. Example.
Of course, the metadata might not be present at all or stored in an auxiliary file.

const usage inside for loop, why this behaviour?

I have a for loop in my nodejs code
const saveDocument = co.wrap(function *(documentData, user, locale) {
var now = moment();
var creationDateLongString = now.format("YYYYMMDDHHmmss");
var creationDateShortString = now.format("YYYYMMDD");
var outputChildFolder = documentData.code + '_' + creationDateLongString + '_' + documentCounter;
var outputFolder = config.files.incomingDocumentsDir + '/' + outputChildFolder;
++documentCounter;
yield fs.mkdir(outputFolder)
var xmlFileName = documentData.code + "-" + creationDateLongString + ".xml";
var pdfFileName = documentData.code + "-" + creationDateLongString + ".pdf";
const pages = [];
for(var index=0;index < documentData.pages.length; ++index) {
const page = documentData.pages[index];
var data = new Buffer(page, "base64");
var dataEncoding = imageType(data).mime === "image/png" ? "png" : "jpg";
var fileName = "page" + index + "." + dataEncoding;
var targetFilePath = outputFolder + "/" + fileName
yield fs.writeFile(targetFilePath,data);
pages.push(fileName);
}
...
}
What I don't understand is why in the above code page only gets assigned once, on the first iteration, and holds that same value during the other iterations. So if I have 5 pages I end up 5 times with the data of the first page in that variable.
I am running node 4 without any special arguments or postprocessor. Simply npm run ... which maps to a node src/main/myApp.js in my package.json
I am probably missing something simple here but I've never seen this before when doing client side ES6 code. The big difference of course being that the client side code goes through Babel + Webpack and the server side code is ran directly through node.
Small addendum: if you are wondering why the "old school" for syntax and not something along the lines of pages.forEach(...., it's because this is existing code where I just did a few minor modifications.
This will work as you are expecting in strict mode. Try adding...
"use strict";
You will only see this behavior in environments (like Node) that actually respect and enforce the keyword. Babel simply converts all let and const to var right now to provide ES5 compatibility. To demonstrate, take a look at this Babel example. You can see in the output that const has been changed to var

Use jade mixin inside code block

Is there a way to use jade mixin inside javascript code block?
I have next use case:
mixin YYYYMMDD(date)
= date.getFullYear() + '-'
= ('0' + (date.getMonth() + 1)).slice(-2) + '-'
= ('0' + date.getDate()).slice(-2)
So I need to use this mixin inside
input(
value=YYYYMMDD(date)
)
Update:
I had to remake those mixins to js functions, so it looks similar to next:
- function YYYYMMDD(date)
- var flDate = date.getFullYear() + '-';
- flDate += ('0' + (date.getMonth() + 1)).slice(-2) + '-';
- flDate += ('0' + date.getDate()).slice(-2);
- return flDate;
the easiest way is, that you write this code on your server, then you can also use some other syntax, for instance coffeescript or even better in this case, some libraries like moment
When you render your template, you just add a helper object to your locals:
var moment = require('moment');
var YYYYMMDD = function(date) {
return moment(date).format('YYYYMMDD');
}
// express code
app.get('/test', function(req, res, next) {
var locals = getLocalsForTest();
locals.helpers = {
YYYYMMDD: YYYYMMDD
};
res.render('template.jade', {locals: locals});
});
and in your template you can just call this
input(value=helpers.YYYYMMDD(date))

How can I get the current datetime in the format "2014-04-01:08:00:00" in Node?

I need the current system datetime in the format "yyyy-mm-dd:hh:mm:ss".
https://stackoverflow.com/a/19079030/2663388 helped a lot.
new Date().toJSON() is showing "2014-07-14T13:41:23.521Z"
Can someone help me to extract "yyyy-mm-dd:hh:mm:ss" from "2014-07-14T13:41:23.521Z"?
Seems that there is no good way to do it with original code unless using Regex. There are some modules such as Moment.js though.
If you are using npm:
npm install moment --save
Then in your code:
var moment = require('moment');
moment().format('yyyy-mm-dd:hh:mm:ss');
That may be much easier to understand.
What about:
new Date().toString().replace(/T/, ':').replace(/\.\w*/, '');
Returns for me:
2014-07-14:13:41:23
But the more safe way is using Date class methods which works in javascript (browser) and node.js:
var date = new Date();
function getDateStringCustom(oDate) {
var sDate;
if (oDate instanceof Date) {
sDate = oDate.getYear() + 1900
+ ':'
+ ((oDate.getMonth() + 1 < 10) ? '0' + (oDate.getMonth() + 1) : oDate.getMonth() + 1)
+ ':' + oDate.getDate()
+ ':' + oDate.getHours()
+ ':' + ((oDate.getMinutes() < 10) ? '0' + (oDate.getMinutes()) : oDate.getMinutes())
+ ':' + ((oDate.getSeconds() < 10) ? '0' + (oDate.getSeconds()) : oDate.getSeconds());
} else {
throw new Error("oDate is not an instance of Date");
}
return sDate;
}
alert(getDateStringCustom(date));
Returns in node.js:
/usr/local/bin/node date.js 2014:07:14:16:13:10
And in Firebug:
2014:07:14:16:14:31
Install moment using
npm install moment --save
And in your code import the moment like this.
var moment = require('moment')
var created = moment().format('YYYY-MM-DD hh:mm:ss')
Though other answers are helpful I found the following code is working for me.
var d = new Date();
console.log(d.toJSON().slice(0,19).replace('T',':'));
The output on console is: 2014-07-15:06:10:16.
I am using Node.js Express on Ubuntu.
Cleaner version of #Bernhard code using padStart and without deprecated getYear
function getCurrentDateTimeString() {
const date = new Date();
return date.getFullYear() + '-' +
(date.getMonth() + 1).toString().padStart(2, '0') + '-' +
date.getDate().toString().padStart(2, '0') + ':' +
date.getHours().toString().padStart(2, '0') + ':' +
date.getMinutes().toString().padStart(2, '0') + ':' +
date.getSeconds().toString().padStart(2, '0');
}
console.log(getCurrentDateTimeString());
Explicity call each part of the Date:
function formatDate(date) {
return [date.getFullYear(), date.getMonth() + 1, date.getDate()].join('-') + ':' +
[date.getHours(), date.getMinutes(), date.getSeconds()].join(':');
}
function formatDatePart(part) {
return part < 10 ? ("0" + part) : part;
}
You can see an example on this fiddle.
Correct way is this
var moment = require('moment');
moment().format('Y-M-D H:m:s');
You can do it using toLocaleString() method in node.js
let date = new Date('2014-07-14T13:41:23.521Z');
console.log(date.toLocaleString('en-US'));
//Converting current date time without timezone
date = new Date()
console.log(date.toLocaleString('en-US'));

Resources