diff --git a/src/backend/model/fileaccess/MetadataLoader.ts b/src/backend/model/fileaccess/MetadataLoader.ts index 8ad45f07..a0aafe52 100644 --- a/src/backend/model/fileaccess/MetadataLoader.ts +++ b/src/backend/model/fileaccess/MetadataLoader.ts @@ -316,6 +316,8 @@ export class MetadataLoader { const orientation = MetadataLoader.getOrientation(exif); MetadataLoader.mapImageDimensions(metadata, exif, orientation); MetadataLoader.mapKeywords(metadata, exif); + MetadataLoader.mapTitle(metadata, exif); + MetadataLoader.mapCaption(metadata, exif); MetadataLoader.mapTimestampAndOffset(metadata, exif); MetadataLoader.mapCameraData(metadata, exif); MetadataLoader.mapGPS(metadata, exif); @@ -370,6 +372,14 @@ export class MetadataLoader { } } + private static mapTitle(metadata: PhotoMetadata, exif: any) { + metadata.title = exif.dc?.title?.value || metadata.title || exif.photoshop?.Headline || exif.acdsee?.caption; //acdsee caption holds the title when data is saved by digikam. Used as last resort if iptc and dc do not contain the data + } + + private static mapCaption(metadata: PhotoMetadata, exif: any) { + metadata.caption = exif.dc?.description?.value || metadata.caption || exif.ifd0?.ImageDescription || exif.exif?.UserComment?.value || exif.Iptc4xmpCore?.ExtDescrAccessibility?.value ||exif.acdsee?.notes; + } + private static mapTimestampAndOffset(metadata: PhotoMetadata, exif: any) { metadata.creationDate = Utils.timestampToMS(exif?.photoshop?.DateCreated, null) || Utils.timestampToMS(exif?.xmp?.CreateDate, null) || diff --git a/src/common/Utils.ts b/src/common/Utils.ts index a1fc4cac..2d69923f 100644 --- a/src/common/Utils.ts +++ b/src/common/Utils.ts @@ -132,7 +132,7 @@ export class Utils { //replace : with - in the yyyy-mm-dd part of the timestamp. let formattedTimestamp = timestamp.substring(0,9).replaceAll(':', '-') + timestamp.substring(9,timestamp.length); if (formattedTimestamp.indexOf("Z") > 0) { //replace Z (and what comes after the Z) with offset - formattedTimestamp.substring(0, formattedTimestamp.indexOf("Z")) + (offset ? offset : '+00:00'); + formattedTimestamp = formattedTimestamp.substring(0, formattedTimestamp.indexOf("Z")) + (offset ? offset : '+00:00'); } else if (formattedTimestamp.indexOf("+") > 0 || timestamp.substring(9,timestamp.length).indexOf("-") > 0) { //don't do anything } else { //add offset formattedTimestamp = formattedTimestamp + (offset ? offset : '+00:00'); diff --git a/test/backend/assets/title_caption/description.json b/test/backend/assets/title_caption/description.json new file mode 100644 index 00000000..677f3940 --- /dev/null +++ b/test/backend/assets/title_caption/description.json @@ -0,0 +1,35 @@ +{ + "size": { + "width": 3144, + "height": 2288 + }, + "creationDate": -2195790002000, + "fileSize": 8909621, + "keywords": [], + "faces": [ + { + "name": "Hulda Stein", + "box": { + "width": 645, + "height": 645, + "left": 1919, + "top": 547 + } + }, + { + "name": "John Amschler", + "box": { + "width": 709, + "height": 709, + "left": 544, + "top": 394 + } + } + ], + "cameraData": { + "make": "NIKON CORPORATION", + "model": "NIKON D200" + }, + "caption": "Hulda and John's Wedding", + "title": "The Wedding" +} \ No newline at end of file diff --git a/test/backend/assets/title_caption/description.png b/test/backend/assets/title_caption/description.png new file mode 100644 index 00000000..6f906d67 Binary files /dev/null and b/test/backend/assets/title_caption/description.png differ diff --git a/test/backend/assets/title_caption/digikam.jpg b/test/backend/assets/title_caption/digikam.jpg new file mode 100644 index 00000000..534135e4 Binary files /dev/null and b/test/backend/assets/title_caption/digikam.jpg differ diff --git a/test/backend/assets/title_caption/digikam.json b/test/backend/assets/title_caption/digikam.json new file mode 100644 index 00000000..87a627a1 --- /dev/null +++ b/test/backend/assets/title_caption/digikam.json @@ -0,0 +1,43 @@ +{ + "cameraData": { + "ISO": 200, + "exposure": 0.008, + "fStop": 2.8, + "focalLength": 9.4, + "make": "FUJIFILM", + "model": "FinePix F601 ZOOM" + }, + "creationDate": 1126423382000, + "creationDateOffset": "+09:00", + "fileSize": 14134, + "size": { + "height": 5, + "width": 7 + }, + "title": "Digikam Title field", + "caption": "Digikam Caption field", + "faces": [ + { + "box": { + "height": 2, + "left": 3, + "top": 2, + "width": 2 + }, + "name": "Æske Øllegård" + } + ], + "keywords": [ + "æÆøØåÅéÉüÜäÄöÖïÏñÑ" + ], + "positionData": { + "GPSData": { + "latitude": 35.9524, + "longitude": 139.863355 + }, + "city": "Shimizu", + "country": "Japan", + "state": "Chiba Ken" + }, + "rating": 4 +} \ No newline at end of file diff --git a/test/backend/unit/model/threading/MetaDataLoader.spec.ts b/test/backend/unit/model/threading/MetaDataLoader.spec.ts index 17bc5a44..76365e88 100644 --- a/test/backend/unit/model/threading/MetaDataLoader.spec.ts +++ b/test/backend/unit/model/threading/MetaDataLoader.spec.ts @@ -35,6 +35,19 @@ describe('MetadataLoader', () => { expect(Utils.clone(data)).to.be.deep.equal(expected); }); + + it('should load png with description', async () => { + const data = await MetadataLoader.loadPhotoMetadata(path.join(__dirname, '/../../../assets/title_caption/description.png')); + const expected = require(path.join(__dirname, '/../../../assets/title_caption/description.json')); + expect(Utils.clone(data)).to.be.deep.equal(expected); + }); + + it('should load image with metadata saved by digikam', async () => { + const data = await MetadataLoader.loadPhotoMetadata(path.join(__dirname, '/../../../assets/title_caption/digikam.jpg')); + const expected = require(path.join(__dirname, '/../../../assets/title_caption/digikam.json')); + expect(Utils.clone(data)).to.be.deep.equal(expected); + }); + it('should load jpg', async () => { const data = await MetadataLoader.loadPhotoMetadata(path.join(__dirname, '/../../../assets/test image öüóőúéáű-.,.jpg')); const expected = require(path.join(__dirname, '/../../../assets/test image öüóőúéáű-.,.json'));