|
@@ -1,36 +1,32 @@
|
|
|
|
|
|
|
|
const fs = require('fs');
|
|
const fs = require('fs');
|
|
|
const tmp = require('tmp');
|
|
const tmp = require('tmp');
|
|
|
-const im = require('imagemagick');
|
|
|
|
|
|
|
+const im = require('./../imagemagickWrapper.js');
|
|
|
const geokit = require('geokit');
|
|
const geokit = require('geokit');
|
|
|
const geocoder = require('offline-geocoder')({ database: 'static/db.sqlite'});
|
|
const geocoder = require('offline-geocoder')({ database: 'static/db.sqlite'});
|
|
|
|
|
|
|
|
function readMeta(path) {
|
|
function readMeta(path) {
|
|
|
- return new Promise((ok, ko) => {
|
|
|
|
|
|
|
+ return new Promise(async (ok, ko) => {
|
|
|
try {
|
|
try {
|
|
|
- im.identify(['-format', '%[EXIF:*]Compression=%[compression]\nWidth=%w\nHeight=%h\n', path], function(err, stdout)
|
|
|
|
|
|
|
+ let stdout = await im.readMeta(path);
|
|
|
|
|
+ var meta = {};
|
|
|
|
|
+ for (const line of stdout.split(/\n/))
|
|
|
{
|
|
{
|
|
|
- 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);
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ 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);
|
|
|
} catch (err) {
|
|
} catch (err) {
|
|
|
console.error("readMeta from Imagemagick: ", err);
|
|
console.error("readMeta from Imagemagick: ", err);
|
|
|
- ok(null);
|
|
|
|
|
|
|
+ ko(err);
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
@@ -125,67 +121,66 @@ function exposureProgram(programId) {
|
|
|
module.exports.parse = async (fileObj) => {
|
|
module.exports.parse = async (fileObj) => {
|
|
|
if (!fileObj.mimeType.startsWith('image/'))
|
|
if (!fileObj.mimeType.startsWith('image/'))
|
|
|
return {};
|
|
return {};
|
|
|
- let imdata = await readMeta(fileObj.path);
|
|
|
|
|
- if (!imdata)
|
|
|
|
|
- return {};
|
|
|
|
|
let result = {};
|
|
let result = {};
|
|
|
- result.artist = imdata.artist || undefined;
|
|
|
|
|
- result.exposureProgram = exposureProgram(Number.parseInt(imdata.exposureProgram));
|
|
|
|
|
- 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();
|
|
|
|
|
- const address = await gpsData.toAddress();
|
|
|
|
|
- result.geoCountry = address?.country;
|
|
|
|
|
- result.geoAdmin = address?.admin;
|
|
|
|
|
- result.geoCity = address?.city;
|
|
|
|
|
- result.tags = readTags(imdata);
|
|
|
|
|
|
|
+ try {
|
|
|
|
|
+ let imdata = await readMeta(fileObj.path);
|
|
|
|
|
+ if (!imdata)
|
|
|
|
|
+ return {};
|
|
|
|
|
+ result.artist = imdata.artist || undefined;
|
|
|
|
|
+ result.exposureProgram = exposureProgram(Number.parseInt(imdata.exposureProgram));
|
|
|
|
|
+ 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();
|
|
|
|
|
+ const address = await gpsData.toAddress();
|
|
|
|
|
+ result.geoCountry = address?.country;
|
|
|
|
|
+ result.geoAdmin = address?.admin;
|
|
|
|
|
+ result.geoCity = address?.city;
|
|
|
|
|
+ result.tags = readTags(imdata);
|
|
|
|
|
+ }
|
|
|
|
|
+ catch (err) {
|
|
|
|
|
+ result.imException = err;
|
|
|
|
|
+ }
|
|
|
for (let i of Object.keys(result))
|
|
for (let i of Object.keys(result))
|
|
|
if (result[i] === undefined || result[i].length === 0)
|
|
if (result[i] === undefined || result[i].length === 0)
|
|
|
delete result[i];
|
|
delete result[i];
|
|
|
return result;
|
|
return result;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-module.exports.createThumbnail = (fileObj, width, height, quality) => {
|
|
|
|
|
- return new Promise((ok, ko) => {
|
|
|
|
|
- if (!fileObj?.meta?.width || !fileObj?.meta?.height)
|
|
|
|
|
- return null;
|
|
|
|
|
- if (!width && !height)
|
|
|
|
|
- width = height = 420;
|
|
|
|
|
- let ratio = Math.min((width / fileObj.meta.width) || 1, (height / fileObj.meta.height) || 1, 1);
|
|
|
|
|
- const output = tmp.fileSync({ discardDescriptor: true });
|
|
|
|
|
- try {
|
|
|
|
|
- im.convert([
|
|
|
|
|
- fileObj.path,
|
|
|
|
|
- '-strip',
|
|
|
|
|
- '-interlace', 'Plane',
|
|
|
|
|
- '-resize', (Math.floor(fileObj.meta.width * ratio)),
|
|
|
|
|
- '-quality', '' + (Math.floor(Math.max(0, Math.min(100, (quality *10))))) + '%',
|
|
|
|
|
- '-sampling-factor', '4:2:0',
|
|
|
|
|
- `JPG:${output.name}`,
|
|
|
|
|
- ], err => {
|
|
|
|
|
- if (err) {
|
|
|
|
|
- console.error("Imagemagick createThumbnail error: ", err);
|
|
|
|
|
- ko();
|
|
|
|
|
- } else {
|
|
|
|
|
- ok(output);
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
- catch (err) {
|
|
|
|
|
- ko(err);
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
|
|
+module.exports.createThumbnail = async (fileObj, width, height, quality) => {
|
|
|
|
|
+ if (!fileObj?.meta?.width || !fileObj?.meta?.height)
|
|
|
|
|
+ return null;
|
|
|
|
|
+ if (!width && !height)
|
|
|
|
|
+ width = height = 420;
|
|
|
|
|
+ let ratio = Math.min((width / fileObj.meta.width) || 1, (height / fileObj.meta.height) || 1, 1);
|
|
|
|
|
+ const output = tmp.fileSync({ discardDescriptor: true });
|
|
|
|
|
+ try {
|
|
|
|
|
+ await im.convert([
|
|
|
|
|
+ fileObj.path,
|
|
|
|
|
+ '-strip',
|
|
|
|
|
+ '-interlace', 'Plane',
|
|
|
|
|
+ '-resize', (Math.floor(fileObj.meta.width * ratio)),
|
|
|
|
|
+ '-quality', '' + (Math.floor(Math.max(0, Math.min(100, (quality *10))))) + '%',
|
|
|
|
|
+ '-sampling-factor', '4:2:0',
|
|
|
|
|
+ `JPG:${output.name}`,
|
|
|
|
|
+ ]);
|
|
|
|
|
+ ok(output);
|
|
|
|
|
+ }
|
|
|
|
|
+ catch (err) {
|
|
|
|
|
+ console.error("Imagemagick createThumbnail error: ", err);
|
|
|
|
|
+ throw err;
|
|
|
|
|
+ }
|
|
|
|
|
+ return output;
|
|
|
};
|
|
};
|
|
|
|
|
|