mirror of
https://github.com/bpatrik/pigallery2.git
synced 2025-01-26 05:27:35 +02:00
fixing sharp thumbnail creation
This commit is contained in:
parent
7f974a1c41
commit
8bf280dda7
@ -1,7 +1,10 @@
|
||||
import {PersonEntry} from '../sql/enitites/PersonEntry';
|
||||
import {MediaDTO} from '../../../common/entities/MediaDTO';
|
||||
|
||||
export interface IPersonManager {
|
||||
get(name: string): Promise<PersonEntry>;
|
||||
|
||||
saveAll(names: string[]): Promise<void>;
|
||||
|
||||
keywordsToPerson(media: MediaDTO[]): Promise<void>;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import {DiskManager} from '../DiskManger';
|
||||
import {PhotoEntity} from './enitites/PhotoEntity';
|
||||
import {Utils} from '../../../common/Utils';
|
||||
import {FaceRegion, PhotoMetadata} from '../../../common/entities/PhotoDTO';
|
||||
import {Connection, Repository} from 'typeorm';
|
||||
import {Connection, Repository} from 'typeorm';
|
||||
import {MediaEntity} from './enitites/MediaEntity';
|
||||
import {MediaDTO} from '../../../common/entities/MediaDTO';
|
||||
import {VideoEntity} from './enitites/VideoEntity';
|
||||
@ -14,10 +14,11 @@ import {FileDTO} from '../../../common/entities/FileDTO';
|
||||
import {NotificationManager} from '../NotifocationManager';
|
||||
import {FaceRegionEntry} from './enitites/FaceRegionEntry';
|
||||
import {ObjectManagerRepository} from '../ObjectManagerRepository';
|
||||
import {IIndexingManager} from '../interfaces/IIndexingManager';
|
||||
|
||||
const LOG_TAG = '[IndexingManager]';
|
||||
|
||||
export class IndexingManager {
|
||||
export class IndexingManager implements IIndexingManager {
|
||||
|
||||
private savingQueue: DirectoryDTO[] = [];
|
||||
private isSaving = false;
|
||||
|
@ -1,6 +1,8 @@
|
||||
import {IPersonManager} from '../interfaces/IPersonManager';
|
||||
import {PersonEntry} from './enitites/PersonEntry';
|
||||
import {SQLConnection} from './SQLConnection';
|
||||
import {PersonEntry} from './enitites/PersonEntry';
|
||||
import {MediaDTO} from '../../../common/entities/MediaDTO';
|
||||
import {PhotoDTO} from '../../../common/entities/PhotoDTO';
|
||||
|
||||
const LOG_TAG = '[PersonManager]';
|
||||
|
||||
@ -8,6 +10,38 @@ export class PersonManager implements IPersonManager {
|
||||
|
||||
persons: PersonEntry[] = [];
|
||||
|
||||
async loadAll(): Promise<void> {
|
||||
const connection = await SQLConnection.getConnection();
|
||||
const personRepository = connection.getRepository(PersonEntry);
|
||||
this.persons = await personRepository.find();
|
||||
|
||||
}
|
||||
|
||||
// TODO dead code, remove it
|
||||
async keywordsToPerson(media: MediaDTO[]) {
|
||||
await this.loadAll();
|
||||
const personFilter = (keyword: string) => this.persons.find(p => p.name.toLowerCase() === keyword.toLowerCase());
|
||||
(<PhotoDTO[]>media).forEach(m => {
|
||||
if (!m.metadata.keywords || m.metadata.keywords.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const personKeywords = m.metadata.keywords.filter(k => personFilter(k));
|
||||
if (personKeywords.length === 0) {
|
||||
return;
|
||||
}
|
||||
// remove persons
|
||||
m.metadata.keywords = m.metadata.keywords.filter(k => !personFilter(k));
|
||||
m.metadata.faces = m.metadata.faces || [];
|
||||
personKeywords.forEach((pk: string) => {
|
||||
m.metadata.faces.push({
|
||||
name: pk
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
async get(name: string): Promise<PersonEntry> {
|
||||
|
||||
let person = this.persons.find(p => p.name === name);
|
||||
@ -28,7 +62,7 @@ export class PersonManager implements IPersonManager {
|
||||
const toSave: { name: string }[] = [];
|
||||
const connection = await SQLConnection.getConnection();
|
||||
const personRepository = connection.getRepository(PersonEntry);
|
||||
this.persons = await personRepository.find();
|
||||
await this.loadAll();
|
||||
|
||||
for (let i = 0; i < names.length; i++) {
|
||||
|
||||
@ -42,7 +76,7 @@ export class PersonManager implements IPersonManager {
|
||||
for (let i = 0; i < toSave.length / 200; i++) {
|
||||
await personRepository.insert(toSave.slice(i * 200, (i + 1) * 200));
|
||||
}
|
||||
this.persons = await personRepository.find();
|
||||
this.persons = await personRepository.find();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -187,48 +187,48 @@ export class MetadataLoader {
|
||||
|
||||
metadata.creationDate = metadata.creationDate || 0;
|
||||
|
||||
if (Config.Client.Faces.enabled) {
|
||||
try {
|
||||
|
||||
try {
|
||||
|
||||
const ret = ExifReader.load(data);
|
||||
const faces: FaceRegion[] = [];
|
||||
if (ret.Regions && ret.Regions.value.RegionList && ret.Regions.value.RegionList.value) {
|
||||
for (let i = 0; i < ret.Regions.value.RegionList.value.length; i++) {
|
||||
if (!ret.Regions.value.RegionList.value[i].value ||
|
||||
!ret.Regions.value.RegionList.value[i].value['rdf:Description'] ||
|
||||
!ret.Regions.value.RegionList.value[i].value['rdf:Description'].value ||
|
||||
!ret.Regions.value.RegionList.value[i].value['rdf:Description'].value['mwg-rs:Area']) {
|
||||
continue;
|
||||
const ret = ExifReader.load(data);
|
||||
const faces: FaceRegion[] = [];
|
||||
if (ret.Regions && ret.Regions.value.RegionList && ret.Regions.value.RegionList.value) {
|
||||
for (let i = 0; i < ret.Regions.value.RegionList.value.length; i++) {
|
||||
if (!ret.Regions.value.RegionList.value[i].value ||
|
||||
!ret.Regions.value.RegionList.value[i].value['rdf:Description'] ||
|
||||
!ret.Regions.value.RegionList.value[i].value['rdf:Description'].value ||
|
||||
!ret.Regions.value.RegionList.value[i].value['rdf:Description'].value['mwg-rs:Area']) {
|
||||
continue;
|
||||
}
|
||||
const region = ret.Regions.value.RegionList.value[i].value['rdf:Description'];
|
||||
const regionBox = ret.Regions.value.RegionList.value[i].value['rdf:Description'].value['mwg-rs:Area'].attributes;
|
||||
if (region.attributes['mwg-rs:Type'] !== 'Face' ||
|
||||
!region.attributes['mwg-rs:Name']) {
|
||||
continue;
|
||||
}
|
||||
const name = region.attributes['mwg-rs:Name'];
|
||||
const box = {
|
||||
width: Math.round(regionBox['stArea:w'] * metadata.size.width),
|
||||
height: Math.round(regionBox['stArea:h'] * metadata.size.height),
|
||||
x: Math.round(regionBox['stArea:x'] * metadata.size.width),
|
||||
y: Math.round(regionBox['stArea:y'] * metadata.size.height)
|
||||
};
|
||||
faces.push({name: name, box: box});
|
||||
}
|
||||
const region = ret.Regions.value.RegionList.value[i].value['rdf:Description'];
|
||||
const regionBox = ret.Regions.value.RegionList.value[i].value['rdf:Description'].value['mwg-rs:Area'].attributes;
|
||||
if (region.attributes['mwg-rs:Type'] !== 'Face' ||
|
||||
!region.attributes['mwg-rs:Name']) {
|
||||
continue;
|
||||
}
|
||||
const name = region.attributes['mwg-rs:Name'];
|
||||
const box = {
|
||||
width: Math.round(regionBox['stArea:w'] * metadata.size.width),
|
||||
height: Math.round(regionBox['stArea:h'] * metadata.size.height),
|
||||
x: Math.round(regionBox['stArea:x'] * metadata.size.width),
|
||||
y: Math.round(regionBox['stArea:y'] * metadata.size.height)
|
||||
};
|
||||
faces.push({name: name, box: box});
|
||||
}
|
||||
if (Config.Client.Faces.keywordsToPersons && faces.length > 0) {
|
||||
metadata.faces = faces; // save faces
|
||||
// remove faces from keywords
|
||||
metadata.faces.forEach(f => {
|
||||
const index = metadata.keywords.indexOf(f.name);
|
||||
if (index !== -1) {
|
||||
metadata.keywords.splice(index, 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
}
|
||||
if (faces.length > 0) {
|
||||
metadata.faces = faces; // save faces
|
||||
// remove faces from keywords
|
||||
metadata.faces.forEach(f => {
|
||||
const index = metadata.keywords.indexOf(f.name);
|
||||
if (index !== -1) {
|
||||
metadata.keywords.splice(index, 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
}
|
||||
|
||||
return resolve(metadata);
|
||||
} catch (err) {
|
||||
return reject({file: fullPath, error: err});
|
||||
|
@ -169,7 +169,7 @@ export class ImageRendererFactory {
|
||||
return async (input: RendererInput): Promise<void> => {
|
||||
|
||||
Logger.silly('[SharpThRenderer] rendering thumbnail:' + input.mediaPath);
|
||||
const image: Sharp = sharp(input.mediaPath);
|
||||
const image: Sharp = sharp(input.mediaPath, {failOnError: false});
|
||||
const metadata: Metadata = await image.metadata();
|
||||
|
||||
/**
|
||||
|
@ -65,6 +65,10 @@ export module ClientConfig {
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
export interface FacesConfig {
|
||||
enabled: boolean;
|
||||
keywordsToPersons: boolean;
|
||||
}
|
||||
|
||||
export interface Config {
|
||||
applicationTitle: string;
|
||||
@ -81,6 +85,7 @@ export module ClientConfig {
|
||||
languages: string[];
|
||||
Video: VideoConfig;
|
||||
MetaFile: MetaFileConfig;
|
||||
Faces: FacesConfig;
|
||||
}
|
||||
|
||||
}
|
||||
@ -138,6 +143,10 @@ export class PublicConfigClass {
|
||||
showItemCount: true
|
||||
}
|
||||
},
|
||||
Faces: {
|
||||
enabled: true,
|
||||
keywordsToPersons: true
|
||||
},
|
||||
authenticationRequired: true,
|
||||
unAuthenticatedUserRole: UserRoles.Admin,
|
||||
publicUrl: '',
|
||||
|
@ -20,7 +20,7 @@ export interface FaceRegionBox {
|
||||
|
||||
export interface FaceRegion {
|
||||
name: string;
|
||||
box: FaceRegionBox;
|
||||
box?: FaceRegionBox; // some faces don t have region ass they are coming from keywords
|
||||
}
|
||||
|
||||
export interface PhotoMetadata extends MediaMetadata {
|
||||
|
@ -35,6 +35,15 @@ export class FixOrientationPipe implements PipeTransform {
|
||||
}
|
||||
|
||||
// transform context before drawing image
|
||||
|
||||
// transform function parameters:
|
||||
// a Horizontal scaling
|
||||
// b Horizontal skewing
|
||||
// c Vertical skewing
|
||||
// d Vertical scaling
|
||||
// e Horizontal moving
|
||||
// f Vertical moving
|
||||
|
||||
switch (orientation) {
|
||||
case OrientationTypes.TOP_RIGHT: // 2
|
||||
ctx.transform(-1, 0, 0, 1, width, 0);
|
||||
|
@ -59,6 +59,10 @@ export class SettingsService {
|
||||
showItemCount: true
|
||||
}
|
||||
},
|
||||
Faces: {
|
||||
enabled: true,
|
||||
keywordsToPersons: true
|
||||
},
|
||||
urlBase: '',
|
||||
publicUrl: '',
|
||||
applicationTitle: '',
|
||||
|
48
test/backend/unit/model/sql/PersonManager.ts
Normal file
48
test/backend/unit/model/sql/PersonManager.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import {expect} from 'chai';
|
||||
import {PersonManager} from '../../../../../backend/model/sql/PersonManager';
|
||||
import {FaceRegion, PhotoDTO} from '../../../../../common/entities/PhotoDTO';
|
||||
|
||||
|
||||
// to help WebStorm to handle the test cases
|
||||
declare let describe: any;
|
||||
declare const after: any;
|
||||
declare const it: any;
|
||||
|
||||
|
||||
describe('PersonManager', () => {
|
||||
|
||||
it('should upgrade keywords to person', async () => {
|
||||
const pm = new PersonManager();
|
||||
pm.loadAll = () => Promise.resolve();
|
||||
pm.persons = [{name: 'Han Solo', id: 0, faces: []},
|
||||
{name: 'Anakin', id: 2, faces: []}];
|
||||
|
||||
const p_noFaces = <PhotoDTO>{
|
||||
metadata: {
|
||||
keywords: ['Han Solo', 'just a keyword']
|
||||
}
|
||||
};
|
||||
|
||||
const p_wFace = <PhotoDTO>{
|
||||
metadata: {
|
||||
keywords: ['Han Solo', 'Anakin'],
|
||||
faces: [{name: 'Obivan'}]
|
||||
}
|
||||
};
|
||||
|
||||
const cmp = (a: FaceRegion, b: FaceRegion) => {
|
||||
return a.name.localeCompare(b.name);
|
||||
};
|
||||
|
||||
await pm.keywordsToPerson([p_noFaces]);
|
||||
expect(p_noFaces.metadata.keywords).to.be.deep.equal(['just a keyword']);
|
||||
expect(p_noFaces.metadata.faces.sort(cmp)).to.eql([{name: 'Han Solo'}].sort(cmp));
|
||||
|
||||
await pm.keywordsToPerson([p_wFace]);
|
||||
expect(p_wFace.metadata.keywords).to.be.deep.equal([]);
|
||||
expect(p_wFace.metadata.faces.sort(cmp)).to.be
|
||||
.eql([{name: 'Han Solo'}, {name: 'Obivan'}, {name: 'Anakin'}].sort(cmp));
|
||||
|
||||
});
|
||||
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user