mirror of
https://github.com/node-red/node-red-nodes.git
synced 2025-03-01 10:37:43 +00:00
move exif node to use supported exifreader library
This is a breaking change To close #1042
This commit is contained in:
parent
3e2d27b9f7
commit
fd5dd24dd8
@ -14,7 +14,7 @@ module.exports = function(RED) {
|
|||||||
if (this.mode === "worldmap") { this.property = "payload.content"; }
|
if (this.mode === "worldmap") { this.property = "payload.content"; }
|
||||||
else { this.property = n.property || "payload"; }
|
else { this.property = n.property || "payload"; }
|
||||||
var node = this;
|
var node = this;
|
||||||
var ExifImage = require('exif').ExifImage;
|
var ExifReader = require('exifreader');
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* Extracts GPS location information from Exif data. If enough information is
|
* Extracts GPS location information from Exif data. If enough information is
|
||||||
@ -24,39 +24,20 @@ module.exports = function(RED) {
|
|||||||
* Assume that the GPS data saved into Exif provides a valid value
|
* Assume that the GPS data saved into Exif provides a valid value
|
||||||
*/
|
*/
|
||||||
function addMsgLocationDataFromExifGPSData(msg,val) {
|
function addMsgLocationDataFromExifGPSData(msg,val) {
|
||||||
var gpsData = msg.exif.gps; // declaring variable purely to make checks more readable
|
if (msg.exif.GPSAltitude) {
|
||||||
if (gpsData.GPSAltitude) {
|
|
||||||
/* istanbul ignore else */
|
/* istanbul ignore else */
|
||||||
if (!msg.location) { msg.location = {}; }
|
if (!msg.location) { msg.location = {}; }
|
||||||
msg.location.alt = gpsData.GPSAltitude;
|
msg.location.alt = parseFloat(msg.exif.GPSAltitude);
|
||||||
}
|
}
|
||||||
if (gpsData.GPSLatitudeRef && gpsData.GPSLatitude && gpsData.GPSLongitudeRef && gpsData.GPSLongitude) { // location can be determined, OK
|
if (msg.exif.GPSLatitudeRef && msg.exif.GPSLatitude && msg.exif.GPSLongitudeRef && msg.exif.GPSLongitude) { // location can be determined, OK
|
||||||
// The data provided in Exif is in degrees, minutes, seconds, this is to be converted into a single floating point degree
|
if (!msg.location) { msg.location = {}; }
|
||||||
if (gpsData.GPSLatitude.length === 3) { // OK to convert latitude
|
msg.location.lat = msg.exif.GPSLatitude;
|
||||||
if (gpsData.GPSLongitude.length === 3) { // OK to convert longitude
|
msg.location.lon = msg.exif.GPSLongitude;
|
||||||
var latitude = convertDegreesMinutesSecondsToDecimals(gpsData.GPSLatitude[0], gpsData.GPSLatitude[1], gpsData.GPSLatitude[2]);
|
if (msg.exif.GPSLatitudeRef == "South latitude") {
|
||||||
latitude = Math.round(latitude * 100000)/100000; // 5dp is approx 1m resolution...
|
msg.location.lat *= -1;
|
||||||
// (N)orth means positive latitude, (S)outh means negative latitude
|
|
||||||
if (gpsData.GPSLatitudeRef.toString() === 'S' || gpsData.GPSLatitudeRef.toString() === 's') {
|
|
||||||
latitude = latitude * -1;
|
|
||||||
}
|
|
||||||
var longitude = convertDegreesMinutesSecondsToDecimals(gpsData.GPSLongitude[0], gpsData.GPSLongitude[1], gpsData.GPSLongitude[2]);
|
|
||||||
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') {
|
|
||||||
longitude = longitude * -1;
|
|
||||||
}
|
|
||||||
// Create location property if not exists
|
|
||||||
if (!msg.location) { msg.location = {}; }
|
|
||||||
msg.location.lat = latitude;
|
|
||||||
msg.location.lon = longitude;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
node.log("Invalid longitude data, no location information has been added to the message.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
if (msg.exif.GPSLongitudeRef == "West longitude") {
|
||||||
node.log("Invalid latitude data, no location information has been added to the message.");
|
msg.location.lon *= -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -65,24 +46,27 @@ module.exports = function(RED) {
|
|||||||
if (msg.location) {
|
if (msg.location) {
|
||||||
msg.location.arc = {
|
msg.location.arc = {
|
||||||
ranges: [100,300,500],
|
ranges: [100,300,500],
|
||||||
pan: gpsData.GPSImgDirection,
|
pan: msg.exif.GPSImgDirection ?? msg.exif.GimbalYawDegree,
|
||||||
fov: (2 * Math.atan(36 / (2 * msg.exif.exif.FocalLengthIn35mmFormat)) * 180 / Math.PI),
|
fov: (2 * Math.atan(36 / (2 * msg.exif.FocalLengthIn35mmFilm)) * 180 / Math.PI),
|
||||||
color: '#aaaa00'
|
color: '#aaaa00'
|
||||||
}
|
}
|
||||||
msg.location.icon = "fa-camera fa-lg";
|
msg.location.icon = "fa-camera fa-lg";
|
||||||
|
if (msg.exif.Make === "DJI") { msg.location.icon = "quad"; }
|
||||||
|
if (msg.exif.Make === "Potensic") { msg.location.icon = "quad"; }
|
||||||
|
if (msg.exif.Make === "Parrot") { msg.location.icon = "quad"; }
|
||||||
msg.location.iconColor = "orange";
|
msg.location.iconColor = "orange";
|
||||||
var na;
|
var na;
|
||||||
var pop = "";
|
var pop = "";
|
||||||
if (val.hasOwnProperty("name")) { na = val.name; }
|
if (val.hasOwnProperty("name")) { na = val.name; }
|
||||||
else if (msg.hasOwnProperty("filename")) {
|
else if (msg.hasOwnProperty("filename")) {
|
||||||
na = msg.filename.split('/').pop();
|
na = msg.filename.split('/').pop();
|
||||||
pop = "Timestamp: "+msg.exif.image.ModifyDate+"<br/>";
|
pop = "Timestamp: "+msg.exif.DateTimeOriginal+"<br/>";
|
||||||
}
|
}
|
||||||
else { na = msg.exif.image.Make+"_"+msg.exif.image.ModifyDate; }
|
else { na = msg.exif.Make+"_"+msg.exif.DateTimeOriginal; }
|
||||||
msg.location.name = na;
|
msg.location.name = na;
|
||||||
msg.location.layer = "Images";
|
msg.location.layer = "Images";
|
||||||
if (msg.exif.image.ImageDescription) {
|
if (msg.exif.ImageDescription) {
|
||||||
pop = "Caption: "+msg.exif.image.ImageDescription+"<br/>"+pop;
|
pop = "Caption: "+msg.exif.ImageDescription+"<br/>"+pop;
|
||||||
}
|
}
|
||||||
pop += '<img width="280" src="data:image/jpeg;base64,'+val.toString("base64")+'"/>'
|
pop += '<img width="280" src="data:image/jpeg;base64,'+val.toString("base64")+'"/>'
|
||||||
if (msg.location.lat && msg.location.lon) {
|
if (msg.location.lat && msg.location.lon) {
|
||||||
@ -104,34 +88,21 @@ module.exports = function(RED) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Buffer.isBuffer(value)) { // or a proper jpg buffer
|
if (Buffer.isBuffer(value)) { // or a proper jpg buffer
|
||||||
new ExifImage({ image:value }, function (error, exifData) {
|
msg.exif = ExifReader.load(msg.payload);
|
||||||
if (error) {
|
for (const p in msg.exif) {
|
||||||
if (node.mode !== "worldmap") {
|
msg.exif[p] = msg.exif[p].description
|
||||||
node.log(error.toString());
|
if (!isNaN(Number(msg.exif[p]))) {
|
||||||
}
|
msg.exif[p] = Number(msg.exif[p])
|
||||||
else {
|
|
||||||
msg.location = {name:msg.payload.name, lat:msg.payload.lat, lon:msg.payload.lon, layer:"Images", icon:"fa-camera fa-lg", draggable:true};
|
|
||||||
msg.location.popup = '<img width="280" src="data:image\/png;base64,'+msg.payload.content.toString('base64')+'"/><br/>';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
}
|
||||||
if (exifData) {
|
if (msg.exif && msg.exif.hasOwnProperty("GPSLatitude") && msg.exif.hasOwnProperty("GPSLongitude")) {
|
||||||
msg.exif = exifData;
|
addMsgLocationDataFromExifGPSData(msg,value);
|
||||||
if ((exifData.hasOwnProperty("gps")) && (Object.keys(exifData.gps).length !== 0)) {
|
}
|
||||||
addMsgLocationDataFromExifGPSData(msg,value);
|
if (node.mode === "worldmap") {
|
||||||
}
|
msg.payload = msg.location || {};
|
||||||
//else { node.log("The incoming image did not contain Exif GPS data."); }
|
delete msg.location;
|
||||||
}
|
}
|
||||||
else {
|
node.send(msg);
|
||||||
node.warn("The incoming image did not contain any Exif data, nothing to do.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (node.mode === "worldmap") {
|
|
||||||
msg.payload = msg.location;
|
|
||||||
delete msg.location;
|
|
||||||
}
|
|
||||||
node.send(msg);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
node.error("Invalid payload received, the Exif node cannot proceed, no messages sent.",msg);
|
node.error("Invalid payload received, the Exif node cannot proceed, no messages sent.",msg);
|
||||||
|
@ -10,6 +10,9 @@ Run the following command in your Node-RED user directory - typically `~/.node-r
|
|||||||
|
|
||||||
npm install node-red-node-exif
|
npm install node-red-node-exif
|
||||||
|
|
||||||
|
## Breaking Change - v1
|
||||||
|
|
||||||
|
This node now uses the more supported exifreader library so that it handles more features and recent exif spec uodates, for example data associated with drones. The output message has consequently changed into a much flatter set of properties and thus breaks all existing (0.x) instances.
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
-----
|
-----
|
||||||
@ -21,3 +24,5 @@ This node expects an incoming JPEG image as a buffer. If Exif data is present, i
|
|||||||
If the Exif data also contains location information this is extracted as `msg.location`.
|
If the Exif data also contains location information this is extracted as `msg.location`.
|
||||||
|
|
||||||
`msg.payload` retains the original, unmodified image buffer.
|
`msg.payload` retains the original, unmodified image buffer.
|
||||||
|
|
||||||
|
You can set it into "worldmap" node - in this mode the payload contains the "location" data, not the original image, but can be sent directly to a node-red-contrib-worldmap node for visualisation.
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "node-red-node-exif",
|
"name": "node-red-node-exif",
|
||||||
"version": "0.4.1",
|
"version": "1.0.0",
|
||||||
"description": "A Node-RED node that extracts Exif information from JPEG image buffers.",
|
"description": "A Node-RED node that extracts Exif information from JPEG image buffers.",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"exif": "^0.6.0"
|
"exifreader": "^4.20.0"
|
||||||
},
|
},
|
||||||
"bundledDependencies": [
|
"bundledDependencies": [
|
||||||
"exif"
|
"exifreader"
|
||||||
],
|
],
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user