mirror of
https://github.com/xuthus83/pigallery2.git
synced 2024-11-03 21:04:03 +08:00
Merge branch 'bug/gpstime_off_by_1_min' of https://github.com/grasdk/pigallery2 into feature/Clear-DateTime-Tag-Priority
This commit is contained in:
commit
f1b9a940a2
@ -380,27 +380,27 @@ export class MetadataLoader {
|
||||
if (!offset) { //Find offset among other options if possible
|
||||
offset = exif.exif.OffsetTimeDigitized || exif.exif.OffsetTime || Utils.getTimeOffsetByGPSStamp(exif.exif.DateTimeOriginal, exif.exif.GPSTimeStamp, exif.gps);
|
||||
}
|
||||
metadata.creationDate = Utils.timestampToMS(exif.exif.DateTimeOriginal, offset);
|
||||
metadata.creationDate = Utils.timestampToMS(exif.exif.DateTimeOriginal, offset) || metadata.creationDate;
|
||||
} else if (exif.exif.CreateDate) { //using else if here, because DateTimeOriginal has preceedence
|
||||
//Create is when the camera wrote the file (typically within the same ms as shutter close)
|
||||
offset = exif.exif.OffsetTimeDigitized; //OffsetTimeDigitized is the corresponding offset
|
||||
if (!offset) { //Find offset among other options if possible
|
||||
offset = exif.exif.OffsetTimeOriginal || exif.exif.OffsetTime || Utils.getTimeOffsetByGPSStamp(exif.exif.DateTimeOriginal, exif.exif.GPSTimeStamp, exif.gps);
|
||||
}
|
||||
metadata.creationDate = Utils.timestampToMS(exif.exif.CreateDate, offset);
|
||||
metadata.creationDate = Utils.timestampToMS(exif.exif.CreateDate, offset) || metadata.creationDate;
|
||||
} else if (exif.ifd0?.ModifyDate) { //using else if here, because DateTimeOriginal and CreatDate have preceedence
|
||||
offset = exif.exif.OffsetTime; //exif.Offsettime is the offset corresponding to ifd0.ModifyDate
|
||||
if (!offset) { //Find offset among other options if possible
|
||||
offset = exif.exif.DateTimeOriginal || exif.exif.OffsetTimeDigitized || Utils.getTimeOffsetByGPSStamp(exif.ifd0.ModifyDate, exif.exif.GPSTimeStamp, exif.gps);
|
||||
}
|
||||
metadata.creationDate = Utils.timestampToMS(exif.ifd0.ModifyDate, offset);
|
||||
metadata.creationDate = Utils.timestampToMS(exif.ifd0.ModifyDate, offset) || metadata.creationDate;
|
||||
} else if (exif.ihdr && exif.ihdr["Creation Time"]) {// again else if (another fallback date if the good ones aren't there) {
|
||||
const any_offset = exif.exif.DateTimeOriginal || exif.exif.OffsetTimeDigitized || exif.exif.OffsetTime || Utils.getTimeOffsetByGPSStamp(exif.ifd0.ModifyDate, exif.exif.GPSTimeStamp, exif.gps);
|
||||
metadata.creationDate = Utils.timestampToMS(exif.ihdr["Creation Time"], any_offset);
|
||||
offset = any_offset;
|
||||
} else if (exif.xmp?.MetadataDate) {// again else if (another fallback date if the good ones aren't there - metadata date is probably later than actual creation date, but much better than file time) {
|
||||
const any_offset = exif.exif.DateTimeOriginal || exif.exif.OffsetTimeDigitized || exif.exif.OffsetTime || Utils.getTimeOffsetByGPSStamp(exif.ifd0.ModifyDate, exif.exif.GPSTimeStamp, exif.gps);
|
||||
metadata.creationDate = Utils.timestampToMS(exif.xmp.MetadataDate, any_offset);
|
||||
metadata.creationDate = Utils.timestampToMS(exif.xmp.MetadataDate, any_offset) || metadata.creationDate;
|
||||
offset = any_offset;
|
||||
}
|
||||
metadata.creationDateOffset = offset || metadata.creationDateOffset;
|
||||
|
@ -186,12 +186,12 @@ export class Utils {
|
||||
gps.GPSDateStamp &&
|
||||
gps.GPSTimeStamp) { //else use exif.gps.GPS*Stamp if available
|
||||
//GPS timestamp is always UTC (+00:00)
|
||||
UTCTimestamp = gps.GPSDateStamp.replaceAll(':', '-') + gps.GPSTimeStamp.join(':');
|
||||
UTCTimestamp = gps.GPSDateStamp.replaceAll(':', '-') + " " + gps.GPSTimeStamp.map((num: any) => Utils.zeroPad(num ,2)).join(':');
|
||||
}
|
||||
if (UTCTimestamp && timestamp) {
|
||||
//offset in minutes is the difference between gps timestamp and given timestamp
|
||||
//to calculate this correctly, we have to work with the same offset
|
||||
const offsetMinutes = (Utils.timestampToMS(timestamp, '+00:00')- Utils.timestampToMS(UTCTimestamp, '+00:00')) / 1000 / 60;
|
||||
const offsetMinutes: number = Math.round((Utils.timestampToMS(timestamp, '+00:00')- Utils.timestampToMS(UTCTimestamp, '+00:00')) / 1000 / 60);
|
||||
return Utils.getOffsetString(offsetMinutes);
|
||||
} else {
|
||||
return undefined;
|
||||
@ -202,13 +202,22 @@ export class Utils {
|
||||
if (-720 <= offsetMinutes && offsetMinutes <= 840) {
|
||||
//valid offset is within -12 and +14 hrs (https://en.wikipedia.org/wiki/List_of_UTC_offsets)
|
||||
return (offsetMinutes < 0 ? "-" : "+") + //leading +/-
|
||||
("0" + Math.trunc(Math.abs(offsetMinutes) / 60)).slice(-2) + ":" + //zeropadded hours and ':'
|
||||
("0" + Math.abs(offsetMinutes) % 60).slice(-2); //zeropadded minutes
|
||||
Utils.zeroPad(Math.trunc(Math.abs(offsetMinutes) / 60), 2) + ":" + //zeropadded hours and ':'
|
||||
Utils.zeroPad((Math.abs(offsetMinutes) % 60), 2); //zeropadded minutes
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
static zeroPad(number: any, length: number): string {
|
||||
if (!isNaN(number)) {
|
||||
const zerosToAdd = Math.max(length - String(number).length, 0);
|
||||
return '0'.repeat(zerosToAdd) + number;
|
||||
} else {
|
||||
return '0'.repeat(number);
|
||||
}
|
||||
}
|
||||
|
||||
static getOffsetMinutes(offsetString: string) { //Convert offset string (+HH:MM or -HH:MM) into a minute value
|
||||
const regex = /^([+-](0[0-9]|1[0-4]):[0-5][0-9])$/; //checks if offset is between -14:00 and +14:00.
|
||||
//-12:00 is the lowest valid UTC-offset, but we allow down to -14 for efficiency
|
||||
|
@ -7,7 +7,8 @@
|
||||
"make": "HUAWEI",
|
||||
"model": "HUAWEI G6-L11"
|
||||
},
|
||||
"creationDate": 1460826466000,
|
||||
"creationDate": 1460819266000,
|
||||
"creationDateOffset": "+02:00",
|
||||
"fileSize": 1980,
|
||||
"size": {
|
||||
"height": 1,
|
||||
|
@ -7,7 +7,7 @@
|
||||
"make": "NIKON",
|
||||
"model": "E880"
|
||||
},
|
||||
"creationDate": 0,
|
||||
"creationDate": "fileModificationTime",
|
||||
"fileSize": 72850,
|
||||
"size": {
|
||||
"height": 768,
|
||||
|
@ -3,7 +3,8 @@
|
||||
"width": 3024,
|
||||
"height": 4032
|
||||
},
|
||||
"creationDate": 1518964712000,
|
||||
"creationDate": 1518982712000,
|
||||
"creationDateOffset": "-05:00",
|
||||
"fileSize": 256001,
|
||||
"cameraData": {
|
||||
"model": "Pixel 2",
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
@ -0,0 +1,25 @@
|
||||
{
|
||||
"size": {
|
||||
"width": 200,
|
||||
"height": 300
|
||||
},
|
||||
"creationDate": 1686141955000,
|
||||
"creationDateOffset": "+01:00",
|
||||
"fileSize": 18663,
|
||||
"cameraData": {
|
||||
"model": "Canon EOS R5",
|
||||
"make": "Canon"
|
||||
},
|
||||
"positionData": {
|
||||
"GPSData": {
|
||||
"longitude": -0.124575,
|
||||
"latitude": 51.500694
|
||||
},
|
||||
"country": "Storbritannien",
|
||||
"state": "England",
|
||||
"city": "St James's"
|
||||
},
|
||||
"keywords": [
|
||||
"Big Ben"
|
||||
]
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
@ -0,0 +1,25 @@
|
||||
{
|
||||
"size": {
|
||||
"width": 200,
|
||||
"height": 300
|
||||
},
|
||||
"creationDate": 1686141955000,
|
||||
"creationDateOffset": "+01:00",
|
||||
"fileSize": 18601,
|
||||
"cameraData": {
|
||||
"model": "Canon EOS R5",
|
||||
"make": "Canon"
|
||||
},
|
||||
"positionData": {
|
||||
"GPSData": {
|
||||
"longitude": -0.124575,
|
||||
"latitude": 51.500694
|
||||
},
|
||||
"country": "Storbritannien",
|
||||
"state": "England",
|
||||
"city": "St James's"
|
||||
},
|
||||
"keywords": [
|
||||
"Big Ben"
|
||||
]
|
||||
}
|
@ -11,6 +11,18 @@ import {DatabaseType} from '../../../../../src/common/config/private/PrivateConf
|
||||
|
||||
declare const before: any;
|
||||
|
||||
function getFileModificationTime(filename: string): Promise<Date | null> {
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.stat(filename, (err, stats) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(stats.mtime);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe('MetadataLoader', () => {
|
||||
// loading default settings (this might have been changed by other tests)
|
||||
|
||||
@ -114,6 +126,16 @@ describe('MetadataLoader', () => {
|
||||
const expected = require(path.join(__dirname, '/../../../assets/timestamps/big_ben_no_tsoffset_but_gps_utc.json'));
|
||||
expect(Utils.clone(data)).to.be.deep.equal(expected);
|
||||
});
|
||||
it('should load jpg with timestamps and gps (UTC) and calculate offset +1, but GPS is off by 1 min', async () => {
|
||||
const data = await MetadataLoader.loadPhotoMetadata(path.join(__dirname, '/../../../assets/timestamps/big_ben_no_tsoffset_but_gps_utc_off_by_1min.jpg'));
|
||||
const expected = require(path.join(__dirname, '/../../../assets/timestamps/big_ben_no_tsoffset_but_gps_utc_off_by_1min.json'));
|
||||
expect(Utils.clone(data)).to.be.deep.equal(expected);
|
||||
});
|
||||
it('should load jpg with timestamps and gps (UTC) and calculate offset +1, but GPS is off by 1 min - no XMP GPS', async () => {
|
||||
const data = await MetadataLoader.loadPhotoMetadata(path.join(__dirname, '/../../../assets/timestamps/big_ben_no_tsoffset_but_gps_utc_off_by_1min_no_xmpgps.jpg'));
|
||||
const expected = require(path.join(__dirname, '/../../../assets/timestamps/big_ben_no_tsoffset_but_gps_utc_off_by_1min_no_xmpgps.json'));
|
||||
expect(Utils.clone(data)).to.be.deep.equal(expected);
|
||||
});
|
||||
it('should load jpg with timestamps but no offset and no GPS to calculate it from', async () => {
|
||||
const data = await MetadataLoader.loadPhotoMetadata(path.join(__dirname, '/../../../assets/timestamps/big_ben_only_time.jpg'));
|
||||
const expected = require(path.join(__dirname, '/../../../assets/timestamps/big_ben_only_time.json'));
|
||||
@ -213,6 +235,16 @@ describe('MetadataLoader', () => {
|
||||
it(item, async () => {
|
||||
const data = await MetadataLoader.loadPhotoMetadata(fullFilePath);
|
||||
const expected = require(fullFilePath.split('.').slice(0, -1).join('.') + '.json');
|
||||
|
||||
if (expected.creationDate == "fileModificationTime") {
|
||||
await getFileModificationTime(fullFilePath).then((modificationTime: any) => {
|
||||
if (modificationTime) {
|
||||
expected.creationDate = new Date(modificationTime).getTime();
|
||||
} else {
|
||||
expected.creationDate = 0;
|
||||
}
|
||||
})
|
||||
}
|
||||
if (expected.skip) {
|
||||
expected.skip.forEach((s: string) => {
|
||||
delete (data as any)[s];
|
||||
|
Loading…
Reference in New Issue
Block a user