mirror of
https://github.com/bpatrik/pigallery2.git
synced 2024-12-23 01:27:14 +02:00
commit
8c3bd650ad
6
.gitignore
vendored
6
.gitignore
vendored
@ -9,10 +9,14 @@ src/frontend/dist
|
|||||||
test/coverage
|
test/coverage
|
||||||
test/backend/**/*.js
|
test/backend/**/*.js
|
||||||
test/backend/**/*.js.map
|
test/backend/**/*.js.map
|
||||||
|
test/frontend/**/*.js
|
||||||
|
test/frontend/**/*.js.map
|
||||||
test/common/**/*.js
|
test/common/**/*.js
|
||||||
test/common/**/*.js.map
|
test/common/**/*.js.map
|
||||||
test/e2e/**/*.js
|
test/e2e/**/*.js
|
||||||
test/e2e/**/*.js.map
|
test/e2e/**/*.js.map
|
||||||
|
test/*.js
|
||||||
|
test/*.js.map
|
||||||
benchmark/**/*.js
|
benchmark/**/*.js
|
||||||
benchmark/**/*.js.map
|
benchmark/**/*.js.map
|
||||||
gulpfile.js
|
gulpfile.js
|
||||||
@ -34,3 +38,5 @@ test.*
|
|||||||
*.sublime-project
|
*.sublime-project
|
||||||
*.sublime-workspace
|
*.sublime-workspace
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
/coverage/
|
||||||
|
.nyc_output/
|
@ -13,7 +13,8 @@ In general, I'm happy to merge PRs, but I recommend filling a ticket and ask fir
|
|||||||
1. Download the source files
|
1. Download the source files
|
||||||
2. install dependencies `npm install`
|
2. install dependencies `npm install`
|
||||||
3. Build client `npm run run-dev`
|
3. Build client `npm run run-dev`
|
||||||
* This will build the client with english localization and will keep building if you change the source files
|
* This will build the client with english localization and will keep building if you change the source files.
|
||||||
|
* Note: This process does not exit, so you need another terminal to run the next step.
|
||||||
4. Build the backend `npm run build-backend`
|
4. Build the backend `npm run build-backend`
|
||||||
* This runs `tsc` that transpiles `.ts` files to `.js` so node can run them.
|
* This runs `tsc` that transpiles `.ts` files to `.js` so node can run them.
|
||||||
* To rebuild on change run `tsc -w`
|
* To rebuild on change run `tsc -w`
|
||||||
|
BIN
demo/images/Chars_exiftool.jpg
Normal file
BIN
demo/images/Chars_exiftool.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 108 KiB |
27
package-lock.json
generated
27
package-lock.json
generated
@ -17,7 +17,6 @@
|
|||||||
"csurf": "1.11.0",
|
"csurf": "1.11.0",
|
||||||
"ejs": "3.1.8",
|
"ejs": "3.1.8",
|
||||||
"exifr": "7.1.3",
|
"exifr": "7.1.3",
|
||||||
"exifreader": "4.10.0",
|
|
||||||
"express": "4.18.2",
|
"express": "4.18.2",
|
||||||
"express-unless": "2.1.3",
|
"express-unless": "2.1.3",
|
||||||
"fluent-ffmpeg": "2.1.2",
|
"fluent-ffmpeg": "2.1.2",
|
||||||
@ -4810,14 +4809,6 @@
|
|||||||
"@xtuc/long": "4.2.2"
|
"@xtuc/long": "4.2.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@xmldom/xmldom": {
|
|
||||||
"version": "0.7.9",
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@xtuc/ieee754": {
|
"node_modules/@xtuc/ieee754": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@ -9660,14 +9651,6 @@
|
|||||||
"version": "7.1.3",
|
"version": "7.1.3",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/exifreader": {
|
|
||||||
"version": "4.10.0",
|
|
||||||
"hasInstallScript": true,
|
|
||||||
"license": "MPL-2.0",
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@xmldom/xmldom": "^0.7.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/exit-on-epipe": {
|
"node_modules/exit-on-epipe": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
@ -25032,10 +25015,6 @@
|
|||||||
"@xtuc/long": "4.2.2"
|
"@xtuc/long": "4.2.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@xmldom/xmldom": {
|
|
||||||
"version": "0.7.9",
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"@xtuc/ieee754": {
|
"@xtuc/ieee754": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"dev": true
|
"dev": true
|
||||||
@ -28208,12 +28187,6 @@
|
|||||||
"exifr": {
|
"exifr": {
|
||||||
"version": "7.1.3"
|
"version": "7.1.3"
|
||||||
},
|
},
|
||||||
"exifreader": {
|
|
||||||
"version": "4.10.0",
|
|
||||||
"requires": {
|
|
||||||
"@xmldom/xmldom": "^0.7.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"exit-on-epipe": {
|
"exit-on-epipe": {
|
||||||
"version": "1.0.1"
|
"version": "1.0.1"
|
||||||
},
|
},
|
||||||
|
@ -44,7 +44,6 @@
|
|||||||
"csurf": "1.11.0",
|
"csurf": "1.11.0",
|
||||||
"ejs": "3.1.8",
|
"ejs": "3.1.8",
|
||||||
"exifr": "7.1.3",
|
"exifr": "7.1.3",
|
||||||
"exifreader": "4.10.0",
|
|
||||||
"express": "4.18.2",
|
"express": "4.18.2",
|
||||||
"express-unless": "2.1.3",
|
"express-unless": "2.1.3",
|
||||||
"fluent-ffmpeg": "2.1.2",
|
"fluent-ffmpeg": "2.1.2",
|
||||||
|
@ -1,23 +1,22 @@
|
|||||||
import {VideoMetadata} from '../../../common/entities/VideoDTO';
|
|
||||||
import {FaceRegion, PhotoMetadata} from '../../../common/entities/PhotoDTO';
|
|
||||||
import {SideCar} from '../../../common/entities/MediaDTO';
|
|
||||||
import {Config} from '../../../common/config/private/Config';
|
|
||||||
import {Logger} from '../../Logger';
|
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import {imageSize} from 'image-size';
|
import { imageSize } from 'image-size';
|
||||||
|
import { Config } from '../../../common/config/private/Config';
|
||||||
|
import { SideCar } from '../../../common/entities/MediaDTO';
|
||||||
|
import { FaceRegion, PhotoMetadata } from '../../../common/entities/PhotoDTO';
|
||||||
|
import { VideoMetadata } from '../../../common/entities/VideoDTO';
|
||||||
|
import { Logger } from '../../Logger';
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import * as ExifReader from 'exifreader';
|
|
||||||
import {ExifParserFactory, OrientationTypes} from 'ts-exif-parser';
|
|
||||||
import {IptcParser} from 'ts-node-iptc';
|
|
||||||
import {FFmpegFactory} from '../FFmpegFactory';
|
|
||||||
import {FfprobeData} from 'fluent-ffmpeg';
|
|
||||||
import {Utils} from '../../../common/Utils';
|
|
||||||
import {ExtensionDecorator} from '../extension/ExtensionDecorator';
|
|
||||||
import * as exifr from 'exifr';
|
import * as exifr from 'exifr';
|
||||||
import * as path from 'path';
|
import { FfprobeData } from 'fluent-ffmpeg';
|
||||||
|
import { FileHandle } from 'fs/promises';
|
||||||
import * as util from 'node:util';
|
import * as util from 'node:util';
|
||||||
import {FileHandle} from 'fs/promises';
|
import * as path from 'path';
|
||||||
|
import { ExifParserFactory, OrientationTypes } from 'ts-exif-parser';
|
||||||
|
import { IptcParser } from 'ts-node-iptc';
|
||||||
|
import { Utils } from '../../../common/Utils';
|
||||||
|
import { FFmpegFactory } from '../FFmpegFactory';
|
||||||
|
import { ExtensionDecorator } from '../extension/ExtensionDecorator';
|
||||||
|
|
||||||
const LOG_TAG = '[MetadataLoader]';
|
const LOG_TAG = '[MetadataLoader]';
|
||||||
const ffmpeg = FFmpegFactory.get();
|
const ffmpeg = FFmpegFactory.get();
|
||||||
@ -358,33 +357,44 @@ export class MetadataLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// TODO: clean up the three different exif readers,
|
const exifrOptions = {
|
||||||
// and keep the minimum amount only
|
tiff: true,
|
||||||
const exif: ExifReader.Tags & ExifReader.XmpTags & ExifReader.IccTags = ExifReader.load(data);
|
xmp: true,
|
||||||
if (exif.Rating) {
|
icc: false,
|
||||||
metadata.rating = parseInt(exif.Rating.value as string, 10) as 0 | 1 | 2 | 3 | 4 | 5;
|
jfif: false, //not needed and not supported for png
|
||||||
|
ihdr: true,
|
||||||
|
iptc: false, //exifr reads UTF8-encoded data wrongly
|
||||||
|
exif: true,
|
||||||
|
gps: true,
|
||||||
|
translateValues: false, //don't translate orientation from numbers to strings etc.
|
||||||
|
mergeOutput: false //don't merge output, because things like Microsoft Rating (percent) and xmp.rating will be merged
|
||||||
|
};
|
||||||
|
|
||||||
|
const exif = await exifr.parse(data, exifrOptions);
|
||||||
|
if (exif.xmp && exif.xmp.Rating) {
|
||||||
|
metadata.rating = exif.xmp.Rating;
|
||||||
if (metadata.rating < 0) {
|
if (metadata.rating < 0) {
|
||||||
metadata.rating = 0;
|
metadata.rating = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (
|
if (exif.dc &&
|
||||||
exif.subject &&
|
exif.dc.subject &&
|
||||||
exif.subject.value &&
|
exif.dc.subject.length > 0) {
|
||||||
exif.subject.value.length > 0
|
const subj = Array.isArray(exif.dc.subject) ? exif.dc.subject : [exif.dc.subject];
|
||||||
) {
|
|
||||||
if (metadata.keywords === undefined) {
|
if (metadata.keywords === undefined) {
|
||||||
metadata.keywords = [];
|
metadata.keywords = [];
|
||||||
}
|
}
|
||||||
for (const kw of exif.subject.value as ExifReader.XmpTag[]) {
|
for (const kw of subj) {
|
||||||
if (metadata.keywords.indexOf(kw.description) === -1) {
|
if (metadata.keywords.indexOf(kw) === -1) {
|
||||||
metadata.keywords.push(kw.description);
|
metadata.keywords.push(kw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let orientation = OrientationTypes.TOP_LEFT;
|
let orientation = OrientationTypes.TOP_LEFT;
|
||||||
if (exif.Orientation) {
|
if (exif.ifd0 &&
|
||||||
|
exif.ifd0.Orientation) {
|
||||||
orientation = parseInt(
|
orientation = parseInt(
|
||||||
exif.Orientation.value as any,
|
exif.ifd0.Orientation as any,
|
||||||
10
|
10
|
||||||
) as number;
|
) as number;
|
||||||
}
|
}
|
||||||
@ -396,9 +406,11 @@ export class MetadataLoader {
|
|||||||
metadata.size.height = height;
|
metadata.size.height = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Config.Faces.enabled) {
|
if (Config.Faces.enabled &&
|
||||||
|
exif["mwg-rs"] &&
|
||||||
|
exif["mwg-rs"].Regions) {
|
||||||
const faces: FaceRegion[] = [];
|
const faces: FaceRegion[] = [];
|
||||||
const regionListVal = ((exif.Regions?.value as any)?.RegionList)?.value;
|
const regionListVal = Array.isArray(exif["mwg-rs"].Regions.RegionList) ? exif["mwg-rs"].Regions.RegionList : [exif["mwg-rs"].Regions.RegionList];
|
||||||
if (regionListVal) {
|
if (regionListVal) {
|
||||||
for (const regionRoot of regionListVal) {
|
for (const regionRoot of regionListVal) {
|
||||||
let type;
|
let type;
|
||||||
@ -442,16 +454,16 @@ export class MetadataLoader {
|
|||||||
|
|
||||||
/* Adobe Lightroom based face region structure */
|
/* Adobe Lightroom based face region structure */
|
||||||
if (
|
if (
|
||||||
regionRoot.value &&
|
regionRoot &&
|
||||||
regionRoot.value['rdf:Description'] &&
|
regionRoot['rdf:Description'] &&
|
||||||
regionRoot.value['rdf:Description'].value &&
|
regionRoot['rdf:Description'] &&
|
||||||
regionRoot.value['rdf:Description'].value['mwg-rs:Area']
|
regionRoot['rdf:Description']['mwg-rs:Area']
|
||||||
) {
|
) {
|
||||||
const region = regionRoot.value['rdf:Description'];
|
const region = regionRoot['rdf:Description'];
|
||||||
const regionBox = region.value['mwg-rs:Area'].attributes;
|
const regionBox = region['mwg-rs:Area'].attributes;
|
||||||
|
|
||||||
name = region.attributes['mwg-rs:Name'];
|
name = region['mwg-rs:Name'];
|
||||||
type = region.attributes['mwg-rs:Type'];
|
type = region['mwg-rs:Type'];
|
||||||
box = createFaceBox(
|
box = createFaceBox(
|
||||||
regionBox['stArea:w'],
|
regionBox['stArea:w'],
|
||||||
regionBox['stArea:h'],
|
regionBox['stArea:h'],
|
||||||
@ -460,18 +472,19 @@ export class MetadataLoader {
|
|||||||
);
|
);
|
||||||
/* Load exiftool edited face region structure, see github issue #191 */
|
/* Load exiftool edited face region structure, see github issue #191 */
|
||||||
} else if (
|
} else if (
|
||||||
regionRoot.Area &&
|
regionRoot &&
|
||||||
regionRoot.Name &&
|
regionRoot.Name &&
|
||||||
regionRoot.Type
|
regionRoot.Type &&
|
||||||
|
regionRoot.Area
|
||||||
) {
|
) {
|
||||||
const regionBox = regionRoot.Area.value;
|
const regionBox = regionRoot.Area;
|
||||||
name = regionRoot.Name.value;
|
name = regionRoot.Name;
|
||||||
type = regionRoot.Type.value;
|
type = regionRoot.Type;
|
||||||
box = createFaceBox(
|
box = createFaceBox(
|
||||||
regionBox.w.value,
|
regionBox.w,
|
||||||
regionBox.h.value,
|
regionBox.h,
|
||||||
regionBox.x.value,
|
regionBox.x,
|
||||||
regionBox.y.value
|
regionBox.y
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BIN
test/backend/assets/Chars.jpg
Normal file
BIN
test/backend/assets/Chars.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 109 KiB |
49
test/backend/assets/Chars.json
Normal file
49
test/backend/assets/Chars.json
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"size": {
|
||||||
|
"width": 1920,
|
||||||
|
"height": 1080
|
||||||
|
},
|
||||||
|
"creationDate": 1706659327000,
|
||||||
|
"fileSize": 111432,
|
||||||
|
"positionData": {
|
||||||
|
"GPSData": {
|
||||||
|
"longitude": 14.162922,
|
||||||
|
"latitude": 57.780696
|
||||||
|
},
|
||||||
|
"country": "Sverige",
|
||||||
|
"state": "Jönköping",
|
||||||
|
"city": "Jönköping"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
],
|
||||||
|
"rating": 0,
|
||||||
|
"faces": [
|
||||||
|
{
|
||||||
|
"box": {
|
||||||
|
"width": 206,
|
||||||
|
"height": 257,
|
||||||
|
"left": 566,
|
||||||
|
"top": 144
|
||||||
|
},
|
||||||
|
"name": "æÆøØåÅéÉüÜäÄöÖïÏñÑ"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "abcdefghijklmnopqrstuvwxyz",
|
||||||
|
"box": {
|
||||||
|
"width": 212,
|
||||||
|
"height": 265,
|
||||||
|
"left": 866,
|
||||||
|
"top": 144
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "abcdefghijklmnopqrstuvwxyz",
|
||||||
|
"box": {
|
||||||
|
"width": 212,
|
||||||
|
"height": 265,
|
||||||
|
"left": 1162,
|
||||||
|
"top": 150
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
BIN
test/backend/assets/Chars_exiftool.jpg
Normal file
BIN
test/backend/assets/Chars_exiftool.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 108 KiB |
49
test/backend/assets/Chars_exiftool.json
Normal file
49
test/backend/assets/Chars_exiftool.json
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"size": {
|
||||||
|
"width": 1920,
|
||||||
|
"height": 1080
|
||||||
|
},
|
||||||
|
"creationDate": 1706616000000,
|
||||||
|
"fileSize": 111050,
|
||||||
|
"positionData": {
|
||||||
|
"GPSData": {
|
||||||
|
"longitude": 14.162922,
|
||||||
|
"latitude": 57.780696
|
||||||
|
},
|
||||||
|
"country": "Sverige",
|
||||||
|
"state": "Jönköping",
|
||||||
|
"city": "Jönköping"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
],
|
||||||
|
"rating": 0,
|
||||||
|
"faces": [
|
||||||
|
{
|
||||||
|
"box": {
|
||||||
|
"width": 206,
|
||||||
|
"height": 257,
|
||||||
|
"left": 566,
|
||||||
|
"top": 144
|
||||||
|
},
|
||||||
|
"name": "æÆøØåÅéÉüÜäÄöÖïÏñÑ"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "abcdefghijklmnopqrstuvwxyz",
|
||||||
|
"box": {
|
||||||
|
"width": 212,
|
||||||
|
"height": 265,
|
||||||
|
"left": 866,
|
||||||
|
"top": 144
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "abcdefghijklmnopqrstuvwxyz",
|
||||||
|
"box": {
|
||||||
|
"width": 212,
|
||||||
|
"height": 265,
|
||||||
|
"left": 1162,
|
||||||
|
"top": 150
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
31
test/backend/assets/png_with_keyword_and_dates.json
Normal file
31
test/backend/assets/png_with_keyword_and_dates.json
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
{
|
||||||
|
"size": {
|
||||||
|
"width": 26,
|
||||||
|
"height": 26
|
||||||
|
},
|
||||||
|
"creationDate": 1707167247786,
|
||||||
|
"fileSize": 5758,
|
||||||
|
"keywords": [
|
||||||
|
],
|
||||||
|
"faces": [
|
||||||
|
{
|
||||||
|
"name": "raspberry",
|
||||||
|
"box": {
|
||||||
|
"width": 21,
|
||||||
|
"height": 18,
|
||||||
|
"left": 3,
|
||||||
|
"top": 8
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "leaf",
|
||||||
|
"box": {
|
||||||
|
"width": 9,
|
||||||
|
"height": 7,
|
||||||
|
"left": 14,
|
||||||
|
"top": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
BIN
test/backend/assets/png_with_keyword_and_dates.png
Normal file
BIN
test/backend/assets/png_with_keyword_and_dates.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.6 KiB |
@ -24,12 +24,11 @@ describe('DiskMangerWorker', () => {
|
|||||||
ProjectPath.ImageFolder = path.join(__dirname, '/../../../assets');
|
ProjectPath.ImageFolder = path.join(__dirname, '/../../../assets');
|
||||||
const dir = await DiskManager.scanDirectory('/');
|
const dir = await DiskManager.scanDirectory('/');
|
||||||
// should match the number of media (photo/video) files in the assets folder
|
// should match the number of media (photo/video) files in the assets folder
|
||||||
expect(dir.media.length).to.be.equals(11);
|
expect(dir.media.length).to.be.equals(14);
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
const expected = require(path.join(__dirname, '/../../../assets/test image öüóőúéáű-.,.json'));
|
const expected = require(path.join(__dirname, '/../../../assets/test image öüóőúéáű-.,.json'));
|
||||||
const i = dir.media.findIndex(m => m.name === 'test image öüóőúéáű-.,.jpg');
|
const i = dir.media.findIndex(m => m.name === 'test image öüóőúéáű-.,.jpg');
|
||||||
expect(Utils.clone(dir.media[i].name)).to.be.deep.equal('test image öüóőúéáű-.,.jpg');
|
expect(Utils.clone(dir.media[i].name)).to.be.deep.equal('test image öüóőúéáű-.,.jpg');
|
||||||
expect(Utils.clone(dir.media[i].metadata)).to.be.deep.equal(expected);
|
expect(Utils.clone(dir.media[i].metadata)).to.be.deep.equal(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -58,6 +58,16 @@ describe('MetadataLoader', () => {
|
|||||||
const expected = require(path.join(__dirname, '/../../../assets/old_photo.json'));
|
const expected = require(path.join(__dirname, '/../../../assets/old_photo.json'));
|
||||||
expect(Utils.clone(data)).to.be.deep.equal(expected);
|
expect(Utils.clone(data)).to.be.deep.equal(expected);
|
||||||
});
|
});
|
||||||
|
it('should load jpg with special characters', async () => {
|
||||||
|
const data = await MetadataLoader.loadPhotoMetadata(path.join(__dirname, '/../../../assets/Chars.jpg'));
|
||||||
|
const expected = require(path.join(__dirname, '/../../../assets/Chars.json'));
|
||||||
|
expect(Utils.clone(data)).to.be.deep.equal(expected);
|
||||||
|
});
|
||||||
|
it('should load jpg with special characters saved by exiftool', async () => {
|
||||||
|
const data = await MetadataLoader.loadPhotoMetadata(path.join(__dirname, '/../../../assets/Chars_exiftool.jpg'));
|
||||||
|
const expected = require(path.join(__dirname, '/../../../assets/Chars_exiftool.json'));
|
||||||
|
expect(Utils.clone(data)).to.be.deep.equal(expected);
|
||||||
|
});
|
||||||
|
|
||||||
describe('should load jpg with proper height and orientation', () => {
|
describe('should load jpg with proper height and orientation', () => {
|
||||||
it('jpg 1', async () => {
|
it('jpg 1', async () => {
|
||||||
|
Loading…
Reference in New Issue
Block a user