diff --git a/utility/exif/94-exif.html b/utility/exif/94-exif.html new file mode 100644 index 00000000..689c290c --- /dev/null +++ b/utility/exif/94-exif.html @@ -0,0 +1,49 @@ + + + + + + + diff --git a/utility/exif/94-exif.js b/utility/exif/94-exif.js new file mode 100644 index 00000000..eb7140c7 --- /dev/null +++ b/utility/exif/94-exif.js @@ -0,0 +1,124 @@ +/** + * Copyright 2014 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +module.exports = function(RED) { + "use strict"; + var ExifImage = require('exif').ExifImage; + + function convertDegreesMinutesSecondsToDecimals(degrees, minutes, seconds) { + var result; + result = degrees + (minutes / 60) + (seconds / 3600); + return result; + } + + /*** + * 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) { + if(msg.exif.gps) { + var gpsData = msg.exif.gps; // declaring variable purely to make checks more readable + if(gpsData.GPSAltitude) { + if(!msg.location) { + msg.location = {}; + } + msg.location.alt = gpsData.GPSAltitude; + } + if(gpsData.GPSLatitudeRef && gpsData.GPSLatitude && gpsData.GPSLongitudeRef && gpsData.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(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; + + // (N)orth means positive latitude + // (S)outh means negative latitude + // (E)ast means positive longitude + // (W)est means negative longitude + 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; + + if(gpsData.GPSLongitudeRef.toString() === 'W' || gpsData.GPSLongitudeRef.toString() === 'w') { + longitude = longitude * -1; + } + 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."); + } + } else { + node.log("Invalid latitude data, no location information has been added to the message."); + } + } else { + node.log("The location of this image cannot be determined safely so no location information has been added to the message."); + } + } else { + node.log("No location info found in this image."); + } + } + + function ExifNode(n) { + RED.nodes.createNode(this,n); + var node = this; + this.on("input", function(msg) { + try { + + if(msg.payload) { + var isBuffer = Buffer.isBuffer(msg.payload); + if(isBuffer === true) { + new ExifImage({ image : msg.payload }, function (error, exifData) { + if (error) { + node.error('Failed to extract Exif data from image.'); + node.log('Failed to extract Exif data from image. '+ error); + } else { + //msg.payload remains the same buffer + if(exifData) { + msg.exif = exifData; + addMsgLocationDataFromExifGPSData(msg); + } else { + node.warn("The incoming buffer did not contain Exif data, nothing to do. "); + } + } + node.send(msg); + }); + } else { + node.error("Invalid payload received, the Exif node cannot proceed, no messages sent."); + return; + } + } else { + node.error("No payload received, the Exif node cannot proceed, no messages sent."); + return; + } + } catch (error) { + 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); +} diff --git a/utility/exif/package.json b/utility/exif/package.json new file mode 100644 index 00000000..ba12c7d0 --- /dev/null +++ b/utility/exif/package.json @@ -0,0 +1,23 @@ +{ + "name" : "node-red-node-exif", + "version" : "0.0.1", + "description" : "A Node-RED node that extracts Exif information from JPEG image buffers.", + "dependencies" : { + "exif": "0.4.0" + }, + "repository" : { + "type":"git", + "url":"https://github.com/node-red/node-red-nodes/tree/master/utility/exif" + }, + "license": "Apache-v2.0", + "keywords": [ "node-red", "exif"], + "node-red" : { + "nodes" : { + "exif": "94-exif.js" + } + }, + "contributors": [ + {"name": "Dave Conway-Jones"}, + {"name": "Zoltan Balogh"} + ] +}