2014-11-04 16:07:32 +01:00
|
|
|
|
|
|
|
module.exports = function(RED) {
|
|
|
|
"use strict";
|
|
|
|
var ExifImage = require('exif').ExifImage;
|
2015-01-12 20:14:04 +01:00
|
|
|
|
2014-11-04 16:07:32 +01:00
|
|
|
function convertDegreesMinutesSecondsToDecimals(degrees, minutes, seconds) {
|
|
|
|
var result;
|
|
|
|
result = degrees + (minutes / 60) + (seconds / 3600);
|
|
|
|
return result;
|
|
|
|
}
|
2015-01-12 20:14:04 +01:00
|
|
|
|
2015-03-31 14:18:25 +02:00
|
|
|
function ExifNode(n) {
|
|
|
|
RED.nodes.createNode(this,n);
|
|
|
|
var node = this;
|
|
|
|
|
|
|
|
/***
|
|
|
|
* Extracts GPS location information from Exif data. If enough information is
|
|
|
|
* provided, convert the Exif data into a pair of single floating point number
|
|
|
|
* latitude/longitude data pairs. Populates msg.location with these.
|
|
|
|
* Assumes that the msg object will always have exifData available as msg.exif.
|
|
|
|
* Assume that the GPS data saved into Exif provides a valid value
|
|
|
|
*/
|
|
|
|
function addMsgLocationDataFromExifGPSData(msg) {
|
2014-11-04 16:07:32 +01:00
|
|
|
var gpsData = msg.exif.gps; // declaring variable purely to make checks more readable
|
2015-05-10 20:27:35 +02:00
|
|
|
if (gpsData.GPSAltitude) {
|
|
|
|
/* istanbul ignore else */
|
|
|
|
if (!msg.location) { msg.location = {}; }
|
2014-11-04 16:07:32 +01:00
|
|
|
msg.location.alt = gpsData.GPSAltitude;
|
|
|
|
}
|
2015-05-10 20:27:35 +02:00
|
|
|
if (gpsData.GPSLatitudeRef && gpsData.GPSLatitude && gpsData.GPSLongitudeRef && gpsData.GPSLongitude) { // location can be determined, OK
|
2014-11-04 16:07:32 +01:00
|
|
|
// The data provided in Exif is in degrees, minutes, seconds, this is to be converted into a single floating point degree
|
2015-05-10 20:27:35 +02:00
|
|
|
if (gpsData.GPSLatitude.length === 3) { // OK to convert latitude
|
|
|
|
if (gpsData.GPSLongitude.length === 3) { // OK to convert longitude
|
2015-01-12 20:14:04 +01:00
|
|
|
|
2015-03-31 14:18:25 +02:00
|
|
|
var latitude = convertDegreesMinutesSecondsToDecimals(gpsData.GPSLatitude[0], gpsData.GPSLatitude[1], gpsData.GPSLatitude[2]);
|
|
|
|
latitude = Math.round(latitude * 100000)/100000; // 5dp is approx 1m resolution...
|
|
|
|
// (N)orth means positive latitude, (S)outh means negative latitude
|
|
|
|
if (gpsData.GPSLatitudeRef.toString() === 'S' || gpsData.GPSLatitudeRef.toString() === 's') {
|
2014-11-04 16:07:32 +01:00
|
|
|
latitude = latitude * -1;
|
|
|
|
}
|
2015-01-12 20:14:04 +01:00
|
|
|
|
2014-11-04 16:07:32 +01:00
|
|
|
var longitude = convertDegreesMinutesSecondsToDecimals(gpsData.GPSLongitude[0], gpsData.GPSLongitude[1], gpsData.GPSLongitude[2]);
|
2015-03-31 14:18:25 +02:00
|
|
|
longitude = Math.round(longitude * 100000)/100000; // 5dp is approx 1m resolution...
|
|
|
|
// (E)ast means positive longitude, (W)est means negative longitude
|
|
|
|
if (gpsData.GPSLongitudeRef.toString() === 'W' || gpsData.GPSLongitudeRef.toString() === 'w') {
|
2014-11-04 16:07:32 +01:00
|
|
|
longitude = longitude * -1;
|
|
|
|
}
|
2015-03-31 14:18:25 +02:00
|
|
|
// Create location property if not exists
|
|
|
|
if (!msg.location) { msg.location = {}; }
|
2014-11-04 16:07:32 +01:00
|
|
|
msg.location.lat = latitude;
|
|
|
|
msg.location.lon = longitude;
|
|
|
|
return;
|
2017-01-29 18:45:44 +01:00
|
|
|
}
|
|
|
|
else {
|
2014-11-04 16:07:32 +01:00
|
|
|
node.log("Invalid longitude data, no location information has been added to the message.");
|
|
|
|
}
|
2017-01-29 18:45:44 +01:00
|
|
|
}
|
|
|
|
else {
|
2014-11-04 16:07:32 +01:00
|
|
|
node.log("Invalid latitude data, no location information has been added to the message.");
|
|
|
|
}
|
2017-01-29 18:45:44 +01:00
|
|
|
}
|
|
|
|
else {
|
2014-11-04 16:07:32 +01:00
|
|
|
node.log("The location of this image cannot be determined safely so no location information has been added to the message.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this.on("input", function(msg) {
|
|
|
|
try {
|
2015-01-12 20:14:04 +01:00
|
|
|
if (msg.payload) {
|
|
|
|
if (Buffer.isBuffer(msg.payload)) {
|
2014-11-04 16:07:32 +01:00
|
|
|
new ExifImage({ image : msg.payload }, function (error, exifData) {
|
2015-01-12 20:14:04 +01:00
|
|
|
if (error) {
|
2015-03-31 14:18:25 +02:00
|
|
|
node.log(error.toString());
|
2017-01-29 18:45:44 +01:00
|
|
|
}
|
|
|
|
else {
|
2018-01-07 16:26:57 +01:00
|
|
|
if (exifData) {
|
2015-01-12 20:14:04 +01:00
|
|
|
msg.exif = exifData;
|
2018-01-07 16:26:57 +01:00
|
|
|
if((exifData.hasOwnProperty("gps")) && (Object.keys(exifData.gps).length !== 0)) {
|
|
|
|
addMsgLocationDataFromExifGPSData(msg);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
node.log("The incoming image did not contain Exif GPS data.");
|
|
|
|
}
|
2017-01-29 18:45:44 +01:00
|
|
|
}
|
|
|
|
else {
|
2018-01-07 16:26:57 +01:00
|
|
|
node.warn("The incoming image did not contain any Exif data, nothing to do. ");
|
2014-11-04 16:07:32 +01:00
|
|
|
}
|
2015-01-12 20:14:04 +01:00
|
|
|
}
|
|
|
|
node.send(msg);
|
|
|
|
});
|
2017-01-29 18:45:44 +01:00
|
|
|
}
|
|
|
|
else {
|
2014-11-04 16:07:32 +01:00
|
|
|
node.error("Invalid payload received, the Exif node cannot proceed, no messages sent.");
|
|
|
|
return;
|
|
|
|
}
|
2017-01-29 18:45:44 +01:00
|
|
|
}
|
|
|
|
else {
|
2014-11-04 16:07:32 +01:00
|
|
|
node.error("No payload received, the Exif node cannot proceed, no messages sent.");
|
|
|
|
return;
|
|
|
|
}
|
2017-01-29 18:45:44 +01:00
|
|
|
}
|
|
|
|
catch (error) {
|
2014-11-04 16:07:32 +01:00
|
|
|
node.error("An error occurred while extracting Exif information. Please check the log for details.");
|
|
|
|
node.log('Error: '+error.message);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
RED.nodes.registerType("exif",ExifNode);
|
|
|
|
}
|