|
|
@@ -0,0 +1,117 @@
|
|
|
+
|
|
|
+const im = require('imagemagick');
|
|
|
+const geokit = require('geokit');
|
|
|
+
|
|
|
+function readMeta(path) {
|
|
|
+ return new Promise((ok, ko) => {
|
|
|
+ im.identify(['-format', '%[EXIF:*]Compression=%[compression]\nWidth=%w\nHeight=%h\n', path], function(err, stdout)
|
|
|
+ {
|
|
|
+ if (err)
|
|
|
+ return ok(null);
|
|
|
+ var meta = {};
|
|
|
+ for (const line of stdout.split(/\n/))
|
|
|
+ {
|
|
|
+ var eq_p = line.indexOf('=');
|
|
|
+ if (eq_p === -1)
|
|
|
+ continue;
|
|
|
+ var key = line.substr(0, eq_p).replace('/','-'),
|
|
|
+ value = line.substr(eq_p+1).trim();
|
|
|
+ var p = key.indexOf(':');
|
|
|
+ if (p !== -1)
|
|
|
+ key = key.substr(p+1);
|
|
|
+ key = key.charAt(0).toLowerCase() + key.slice(1);
|
|
|
+ meta[key] = value;
|
|
|
+ }
|
|
|
+ ok(meta);
|
|
|
+ });
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+function exifDate(value) {
|
|
|
+ if (!value)
|
|
|
+ return undefined;
|
|
|
+ value = value.split(/ /);
|
|
|
+ return new Date(value[0].replace(/:/g, '-')+' '+value[1]+' +0000');
|
|
|
+}
|
|
|
+
|
|
|
+function exifSlash(value) {
|
|
|
+ if (!value)
|
|
|
+ return undefined;
|
|
|
+ if (!(/[0-9]+\/[0-9]+/).test(value))
|
|
|
+ return value;
|
|
|
+ return eval(value);
|
|
|
+}
|
|
|
+
|
|
|
+function ExifGps(data) {
|
|
|
+ /*
|
|
|
+ * gPSLatitude: '46/1,54/1,3500/100',
|
|
|
+ gPSLatitudeRef: 'N',
|
|
|
+ gPSLongitude: '23/1,48/1,3614/100',
|
|
|
+ gPSLongitudeRef: 'E',
|
|
|
+ */
|
|
|
+ this.data = null;
|
|
|
+ if (!data.gPSLatitude || !data.gPSLongitude || !(/^[0-9\-,\/]+$/).test(data.gPSLatitude) || !(/^[0-9\-,\/]+$/).test(data.gPSLongitude))
|
|
|
+ return;
|
|
|
+ try
|
|
|
+ {
|
|
|
+ this.data = {
|
|
|
+ lat: data.gPSLatitude.split(',').map(eval),
|
|
|
+ lon: data.gPSLongitude.split(',').map(eval)
|
|
|
+ };
|
|
|
+ }
|
|
|
+ catch(err)
|
|
|
+ {
|
|
|
+ this.data = null;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (data.gPSLatitudeRef && data.gPSLatitudeRef !== 'N' && this.data.lat[0] >= 0)
|
|
|
+ this.data.lat[0] *= -1;
|
|
|
+ if (data.gPSLongitudeRef && data.gPSLongitudeRef !== 'E' && this.data.lon[0] >= 0)
|
|
|
+ this.data.lon[0] *= -1;
|
|
|
+ this.data.lat = this.data.lat[0] + this.data.lat[1] / 60 + this.data.lat[2]/3600;
|
|
|
+ this.data.lon = this.data.lon[0] + this.data.lon[1] / 60 + this.data.lon[2]/3600;
|
|
|
+ if (!this.data.lat || isNaN(this.data.lat) || !this.data.lon || isNaN(this.data.lon))
|
|
|
+ this.data = null;
|
|
|
+}
|
|
|
+
|
|
|
+ExifGps.prototype.toGps = function() {
|
|
|
+ if (!this.data)
|
|
|
+ return undefined;
|
|
|
+ return JSON.stringify([this.data.lat, this.data.lon]);
|
|
|
+}
|
|
|
+
|
|
|
+ExifGps.prototype.toGeoHash = function() {
|
|
|
+ if (!this.data)
|
|
|
+ return undefined;
|
|
|
+ return geokit.hash({lat: this.data.lat, lng: this.data.lon});
|
|
|
+}
|
|
|
+
|
|
|
+module.exports.parse = async (fileObj) => {
|
|
|
+ if (!fileObj.mimeType.startsWith('image/'))
|
|
|
+ return {};
|
|
|
+ let imdata = await readMeta(fileObj.path);
|
|
|
+ if (!imdata)
|
|
|
+ return {};
|
|
|
+ let result = {};
|
|
|
+ result.artist = imdata.artist || undefined;
|
|
|
+ result.exposureTime = exifSlash(imdata.exposureTime);
|
|
|
+ result.exposureTimeStr = imdata.exposureTime || undefined;
|
|
|
+ result.dateTime = exifDate(imdata.dateTimeDigitized || imdata.dateTimeOriginal);
|
|
|
+ result.fNumber = exifSlash(imdata.fNumber);
|
|
|
+ result.focal = exifSlash(imdata.focalLength);
|
|
|
+ result.lensModel = imdata.lensModel || undefined;
|
|
|
+ result.camera = ((imdata.model || "") + (imdata.model && imdata.make ? " " : "") + (imdata.make || "")) || "";
|
|
|
+ result.software = imdata.software || undefined;
|
|
|
+ result.iso = Number.parseInt(imdata.photographicSensitivity) || undefined;
|
|
|
+ result.width = imdata.width || undefined;
|
|
|
+ result.height = imdata.height || undefined;
|
|
|
+ result.compression = imdata.compression || undefined;
|
|
|
+ const gpsData = new ExifGps(imdata);
|
|
|
+ result.gpsLocation = gpsData.toGps();
|
|
|
+ result.geoHash = gpsData.toGeoHash();
|
|
|
+ for (let i of Object.keys(result))
|
|
|
+ if (result[i] === undefined || result[i].length === 0)
|
|
|
+ delete result[i];
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|