add worldmap features to exif node.

field of view, popup, filename, icon, etc.
This commit is contained in:
Dave Conway-Jones 2020-12-06 17:34:27 +00:00
parent 9e948b9fdf
commit 466b1c3deb
No known key found for this signature in database
GPG Key ID: 88BA2B8A411BE9FF
5 changed files with 73 additions and 41 deletions

View File

@ -40,22 +40,22 @@
"grunt-lint-inline": "^1.0.0",
"grunt-simple-mocha": "^0.4.1",
"imap": "^0.8.19",
"mailparser": "^3.0.0",
"mailparser": "~3.0.1",
"markdown-it": "^11.0.0",
"mocha": "~6.2.3",
"msgpack-lite": "^0.1.26",
"multilang-sentiment": "^1.2.0",
"ngeohash": "^0.6.3",
"node-red": "^1.1.3",
"node-red": "~1.2.6",
"node-red-node-test-helper": "~0.2.5",
"nodemailer": "^6.4.10",
"nodemailer": "~6.4.16",
"poplib": "^0.1.7",
"proxyquire": "^2.1.3",
"pushbullet": "^2.4.0",
"sentiment": "^2.1.0",
"should": "^13.2.3",
"sinon": "~7.5.0",
"smtp-server": "^3.7.0",
"smtp-server": "~3.8.0",
"supertest": "^4.0.2",
"when": "^3.7.8"
},

View File

@ -26,7 +26,7 @@ describe('exif node', function() {
//var data = fs.readFileSync("test/utility/exif/exif_test_image.jpg", null); // extracting genuine exif data to be fed back as the result of the stubbed ExifImage constructor
//var data = fs.readFileSync("exif_test_image.jpg", null); // extracting genuine exif data to be fed back as the result of the stubbed ExifImage constructor
var flow = [{id:"exifNode1", type:"exif", wires:[["helperNode1"]]},
{id:"helperNode1", type:"helper"}];
{id:"helperNode1", type:"helper"}];
var gpsmsg = { gps: { GPSLatitudeRef: 'N',
GPSLatitude: [ 50, 57, 22.4697 ],
@ -65,7 +65,7 @@ describe('exif node', function() {
//var data = fs.readFileSync("test/utility/exif/exif_test_image.jpg", null); // extracting genuine exif data to be fed back as the result of the stubbed ExifImage constructor
//var data = fs.readFileSync("exif_test_image.jpg", null); // extracting genuine exif data to be fed back as the result of the stubbed ExifImage constructor
var flow = [{id:"exifNode1", type:"exif", wires:[["helperNode1"]]},
{id:"helperNode1", type:"helper"}];
{id:"helperNode1", type:"helper"}];
var gpsmsg = { gps: { GPSLatitudeRef: 'S',
GPSLatitude: [ 50, 57, 22.4697 ],
@ -101,7 +101,7 @@ describe('exif node', function() {
var data = new Buffer.from("hello");
var eD;
var flow = [{id:"exifNode1", type:"exif", wires:[["helperNode1"]]},
{id:"helperNode1", type:"helper"}];
{id:"helperNode1", type:"helper"}];
helper.load(exifNode, flow, function() {
var exifNode1 = helper.getNode("exifNode1");
@ -127,7 +127,7 @@ describe('exif node', function() {
var data = "hello";
var eD;
var flow = [{id:"exifNode1", type:"exif", wires:[["helperNode1"]]},
{id:"helperNode1", type:"helper"}];
{id:"helperNode1", type:"helper"}];
helper.load(exifNode, flow, function() {
var exifNode1 = helper.getNode("exifNode1");
@ -153,7 +153,7 @@ describe('exif node', function() {
var data = new Buffer.from("hello");
var eD;
var flow = [{id:"exifNode1", type:"exif", wires:[["helperNode1"]]},
{id:"helperNode1", type:"helper"}];
{id:"helperNode1", type:"helper"}];
helper.load(exifNode, flow, function() {
var exifNode1 = helper.getNode("exifNode1");
@ -179,7 +179,7 @@ describe('exif node', function() {
var data = new Buffer.from("hello");
var eD;
var flow = [{id:"exifNode1", type:"exif", wires:[["helperNode1"]]},
{id:"helperNode1", type:"helper"}];
{id:"helperNode1", type:"helper"}];
var gpsmsg = { gps: { GPSLatitudeRef: 'N',
GPSLatitude: [ 50, 57 ],
@ -219,7 +219,7 @@ describe('exif node', function() {
var data = new Buffer.from("hello");
var eD;
var flow = [{id:"exifNode1", type:"exif", wires:[["helperNode1"]]},
{id:"helperNode1", type:"helper"}];
{id:"helperNode1", type:"helper"}];
var gpsmsg = { gps: { GPSLatitudeRef: 'N',
GPSLatitude: [ 50, 57, 1.3 ],
@ -259,7 +259,7 @@ describe('exif node', function() {
var data = new Buffer.from("hello");
var eD;
var flow = [{id:"exifNode1", type:"exif", wires:[["helperNode1"]]},
{id:"helperNode1", type:"helper"}];
{id:"helperNode1", type:"helper"}];
var gpsmsg = { gps: { GPSLatitudeRef: 'N',
GPSLatitude: [ 50, 57, 1.3 ],
@ -291,6 +291,4 @@ describe('exif node', function() {
});
});
});

View File

@ -1,17 +1,22 @@
<script type="text/x-red" data-template-name="exif">
<script type="text/html" data-template-name="exif">
<div class="form-row">
<label for="node-input-property"><i class="fa fa-ellipsis-h"></i> <span data-i18n="node-red:common.label.property"></span></label>
<input type="text" id="node-input-property" style="width:70%;"/>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
</script>
<script type="text/x-red" data-help-name="exif">
<script type="text/html" data-help-name="exif">
<p>Extract <a href="http://en.wikipedia.org/wiki/Exchangeable_image_file_format">Exif</a> information from JPEG images.</p>
<p>This node expects an incoming JPEG image buffer. If Exif data is present,
<p>This node expects an incoming JPEG image buffer in the selected property. If Exif data is present,
it extracts the data into the <code>msg.exif</code> object.</p>
<p>The node then adds location data as <code>msg.location</code>, should the Exif data carry this information.
<code>msg.payload</code> remains the original, unmodified image buffer. </p>
This also includes an icon, bearing and field of view arc suitable for use in the worldmap node.
The selected input property retains the original, unmodified image buffer.</p>
</script>
<script type="text/javascript">
@ -19,7 +24,8 @@
category: 'utility',
color:"#f1c2f0",
defaults: {
name: {value:""}
name: {value:""},
property: {value:"payload",required:true}
},
inputs:1,
outputs:1,
@ -29,6 +35,10 @@
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
if (this.property === undefined) { $("#node-input-property").val("payload"); }
$("#node-input-property").typedInput({default:'msg',types:['msg']});
}
});
</script>

View File

@ -11,6 +11,7 @@ module.exports = function(RED) {
function ExifNode(n) {
RED.nodes.createNode(this,n);
this.property = n.property || "payload";
var node = this;
/***
@ -20,7 +21,7 @@ module.exports = function(RED) {
* 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) {
function addMsgLocationDataFromExifGPSData(msg,val) {
var gpsData = msg.exif.gps; // declaring variable purely to make checks more readable
if (gpsData.GPSAltitude) {
/* istanbul ignore else */
@ -31,14 +32,12 @@ module.exports = function(RED) {
// The data provided in Exif is in degrees, minutes, seconds, this is to be converted into a single floating point degree
if (gpsData.GPSLatitude.length === 3) { // OK to convert latitude
if (gpsData.GPSLongitude.length === 3) { // OK to convert longitude
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') {
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
@ -49,7 +48,6 @@ module.exports = function(RED) {
if (!msg.location) { msg.location = {}; }
msg.location.lat = latitude;
msg.location.lon = longitude;
return;
}
else {
node.log("Invalid longitude data, no location information has been added to the message.");
@ -62,13 +60,32 @@ module.exports = function(RED) {
else {
node.log("The location of this image cannot be determined safely so no location information has been added to the message.");
}
msg.location.arc = {
ranges: [500,1000,2000],
pan: gpsData.GPSImgDirection,
fov: (2 * Math.atan(36 / (2 * msg.exif.exif.FocalLengthIn35mmFormat)) * 180 / Math.PI),
color: '#910000'
}
msg.location.icon = "fa-camera";
var na;
if (val.hasOwnProperty("name")) { na = val.name; }
else if (msg.hasOwnProperty("filename")) { na = msg.filename.split('/').pop(); }
else { na = msg.exif.image.Make+"_"+msg.exif.image.ModifyDate; }
msg.location.name = na;
msg.location.popup = '<img width="280" src="data:image/jpeg;base64,'+val.toString("base64")+'"/>'
}
this.on("input", function(msg) {
try {
if (msg.payload) {
if (Buffer.isBuffer(msg.payload)) {
new ExifImage({ image : msg.payload }, function (error, exifData) {
var value = RED.util.getMessageProperty(msg,node.property);
if (value !== undefined) {
if (typeof value === "string") { // it must be a base64 encoded inline image type
if (value.indexOf('data:image') !== -1) {
value = new Buffer.from(value.replace(/^data:image\/[a-z]+;base64,/, ""), 'base64');
}
}
if (Buffer.isBuffer(value)) { // or a proper jpg buffer
new ExifImage({ image:value }, function (error, exifData) {
if (error) {
node.log(error.toString());
}
@ -76,7 +93,7 @@ module.exports = function(RED) {
if (exifData) {
msg.exif = exifData;
if ((exifData.hasOwnProperty("gps")) && (Object.keys(exifData.gps).length !== 0)) {
addMsgLocationDataFromExifGPSData(msg);
addMsgLocationDataFromExifGPSData(msg,value);
}
//else { node.log("The incoming image did not contain Exif GPS data."); }
}
@ -93,7 +110,7 @@ module.exports = function(RED) {
}
}
else {
node.error("No payload received, the Exif node cannot proceed, no messages sent.",msg);
node.warn("No input received, the Exif node cannot proceed, no messages sent.",msg);
return;
}
}

View File

@ -1,23 +1,30 @@
{
"name" : "node-red-node-exif",
"version" : "0.0.7",
"description" : "A Node-RED node that extracts Exif information from JPEG image buffers.",
"dependencies" : {
"exif": "0.4.0"
"name": "node-red-node-exif",
"version": "0.1.0",
"description": "A Node-RED node that extracts Exif information from JPEG image buffers.",
"dependencies": {
"exif": "^0.6.0"
},
"repository" : {
"type":"git",
"url":"https://github.com/node-red/node-red-nodes/tree/master/utility/exif"
"repository": {
"type": "git",
"url": "https://github.com/node-red/node-red-nodes/tree/master/utility/exif"
},
"license": "Apache-2.0",
"keywords": [ "node-red", "exif"],
"node-red" : {
"nodes" : {
"keywords": [
"node-red",
"exif"
],
"node-red": {
"nodes": {
"exif": "94-exif.js"
}
},
"contributors": [
{"name": "Dave Conway-Jones"},
{"name": "Zoltan Balogh"}
{
"name": "Dave Conway-Jones"
},
{
"name": "Zoltan Balogh"
}
]
}