1
0
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:
Patrik J. Braun 2019-02-04 17:46:27 -05:00
parent 7f974a1c41
commit 8bf280dda7
10 changed files with 152 additions and 44 deletions

View File

@ -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>;
}

View File

@ -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;

View File

@ -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();
}
}

View File

@ -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});

View File

@ -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();
/**

View File

@ -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: '',

View File

@ -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 {

View File

@ -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);

View File

@ -59,6 +59,10 @@ export class SettingsService {
showItemCount: true
}
},
Faces: {
enabled: true,
keywordsToPersons: true
},
urlBase: '',
publicUrl: '',
applicationTitle: '',

View 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));
});
});