mirror of
https://github.com/xuthus83/pigallery2.git
synced 2025-01-14 14:43:17 +08:00
Add face margin to be part of converted faces
This commit is contained in:
parent
7d3343a8ff
commit
4bbd8fb6b4
@ -24,11 +24,11 @@ export class PhotoProcessing {
|
|||||||
if (Config.Server.Threading.enabled === true) {
|
if (Config.Server.Threading.enabled === true) {
|
||||||
if (Config.Server.Threading.thumbnailThreads > 0) {
|
if (Config.Server.Threading.thumbnailThreads > 0) {
|
||||||
Config.Media.Thumbnail.concurrentThumbnailGenerations =
|
Config.Media.Thumbnail.concurrentThumbnailGenerations =
|
||||||
Config.Server.Threading.thumbnailThreads;
|
Config.Server.Threading.thumbnailThreads;
|
||||||
} else {
|
} else {
|
||||||
Config.Media.Thumbnail.concurrentThumbnailGenerations = Math.max(
|
Config.Media.Thumbnail.concurrentThumbnailGenerations = Math.max(
|
||||||
1,
|
1,
|
||||||
os.cpus().length - 1
|
os.cpus().length - 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -36,31 +36,31 @@ export class PhotoProcessing {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.taskQue = new TaskExecuter(
|
this.taskQue = new TaskExecuter(
|
||||||
Config.Media.Thumbnail.concurrentThumbnailGenerations,
|
Config.Media.Thumbnail.concurrentThumbnailGenerations,
|
||||||
(input): Promise<void> => PhotoWorker.render(input)
|
(input): Promise<void> => PhotoWorker.render(input)
|
||||||
);
|
);
|
||||||
|
|
||||||
this.initDone = true;
|
this.initDone = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async generatePersonThumbnail(
|
public static async generatePersonThumbnail(
|
||||||
person: PersonEntry
|
person: PersonEntry
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
// load parameters
|
// load parameters
|
||||||
const photo: PhotoDTO = person.sampleRegion.media;
|
const photo: PhotoDTO = person.sampleRegion.media;
|
||||||
const mediaPath = path.join(
|
const mediaPath = path.join(
|
||||||
ProjectPath.ImageFolder,
|
ProjectPath.ImageFolder,
|
||||||
photo.directory.path,
|
photo.directory.path,
|
||||||
photo.directory.name,
|
photo.directory.name,
|
||||||
photo.name
|
photo.name
|
||||||
);
|
);
|
||||||
const size: number = Config.Media.Thumbnail.personThumbnailSize;
|
const size: number = Config.Media.Thumbnail.personThumbnailSize;
|
||||||
const faceRegion = person.sampleRegion.media.metadata.faces.find(f => f.name === person.name);
|
const faceRegion = person.sampleRegion.media.metadata.faces.find(f => f.name === person.name);
|
||||||
// generate thumbnail path
|
// generate thumbnail path
|
||||||
const thPath = PhotoProcessing.generatePersonThumbnailPath(
|
const thPath = PhotoProcessing.generatePersonThumbnailPath(
|
||||||
mediaPath,
|
mediaPath,
|
||||||
faceRegion,
|
faceRegion,
|
||||||
size
|
size
|
||||||
);
|
);
|
||||||
|
|
||||||
// check if thumbnail already exist
|
// check if thumbnail already exist
|
||||||
@ -73,12 +73,12 @@ export class PhotoProcessing {
|
|||||||
|
|
||||||
const margin = {
|
const margin = {
|
||||||
x: Math.round(
|
x: Math.round(
|
||||||
faceRegion.box.width *
|
faceRegion.box.width *
|
||||||
Config.Media.Thumbnail.personFaceMargin
|
Config.Media.Thumbnail.personFaceMargin
|
||||||
),
|
),
|
||||||
y: Math.round(
|
y: Math.round(
|
||||||
faceRegion.box.height *
|
faceRegion.box.height *
|
||||||
Config.Media.Thumbnail.personFaceMargin
|
Config.Media.Thumbnail.personFaceMargin
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -91,10 +91,10 @@ export class PhotoProcessing {
|
|||||||
makeSquare: false,
|
makeSquare: false,
|
||||||
cut: {
|
cut: {
|
||||||
left: Math.round(
|
left: Math.round(
|
||||||
Math.max(0, faceRegion.box.left - margin.x / 2)
|
Math.max(0, faceRegion.box.left - margin.x / 2)
|
||||||
),
|
),
|
||||||
top: Math.round(
|
top: Math.round(
|
||||||
Math.max(0, faceRegion.box.top - margin.y / 2)
|
Math.max(0, faceRegion.box.top - margin.y / 2)
|
||||||
),
|
),
|
||||||
width: faceRegion.box.width + margin.x,
|
width: faceRegion.box.width + margin.x,
|
||||||
height: faceRegion.box.height + margin.y,
|
height: faceRegion.box.height + margin.y,
|
||||||
@ -104,12 +104,12 @@ export class PhotoProcessing {
|
|||||||
smartSubsample: Config.Media.Thumbnail.smartSubsample,
|
smartSubsample: Config.Media.Thumbnail.smartSubsample,
|
||||||
} as MediaRendererInput;
|
} as MediaRendererInput;
|
||||||
input.cut.width = Math.min(
|
input.cut.width = Math.min(
|
||||||
input.cut.width,
|
input.cut.width,
|
||||||
photo.metadata.size.width - input.cut.left
|
photo.metadata.size.width - input.cut.left
|
||||||
);
|
);
|
||||||
input.cut.height = Math.min(
|
input.cut.height = Math.min(
|
||||||
input.cut.height,
|
input.cut.height,
|
||||||
photo.metadata.size.height - input.cut.top
|
photo.metadata.size.height - input.cut.top
|
||||||
);
|
);
|
||||||
|
|
||||||
await fsp.mkdir(ProjectPath.FacesFolder, {recursive: true});
|
await fsp.mkdir(ProjectPath.FacesFolder, {recursive: true});
|
||||||
@ -120,34 +120,35 @@ export class PhotoProcessing {
|
|||||||
public static generateConvertedPath(mediaPath: string, size: number): string {
|
public static generateConvertedPath(mediaPath: string, size: number): string {
|
||||||
const file = path.basename(mediaPath);
|
const file = path.basename(mediaPath);
|
||||||
return path.join(
|
return path.join(
|
||||||
ProjectPath.TranscodedFolder,
|
ProjectPath.TranscodedFolder,
|
||||||
ProjectPath.getRelativePathToImages(path.dirname(mediaPath)),
|
ProjectPath.getRelativePathToImages(path.dirname(mediaPath)),
|
||||||
file + '_' + size + 'q' + Config.Media.Thumbnail.quality + (Config.Media.Thumbnail.smartSubsample ? 'cs' : '') + PhotoProcessing.CONVERTED_EXTENSION
|
file + '_' + size + 'q' + Config.Media.Thumbnail.quality + (Config.Media.Thumbnail.smartSubsample ? 'cs' : '') + PhotoProcessing.CONVERTED_EXTENSION
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static generatePersonThumbnailPath(
|
public static generatePersonThumbnailPath(
|
||||||
mediaPath: string,
|
mediaPath: string,
|
||||||
faceRegion: FaceRegion,
|
faceRegion: FaceRegion,
|
||||||
size: number
|
size: number
|
||||||
): string {
|
): string {
|
||||||
return path.join(
|
return path.join(
|
||||||
ProjectPath.FacesFolder,
|
ProjectPath.FacesFolder,
|
||||||
crypto
|
crypto
|
||||||
.createHash('md5')
|
.createHash('md5')
|
||||||
.update(
|
.update(
|
||||||
mediaPath +
|
mediaPath +
|
||||||
'_' +
|
'_' +
|
||||||
faceRegion.name +
|
faceRegion.name +
|
||||||
'_' +
|
'_' +
|
||||||
faceRegion.box.left +
|
faceRegion.box.left +
|
||||||
'_' +
|
'_' +
|
||||||
faceRegion.box.top
|
faceRegion.box.top
|
||||||
)
|
)
|
||||||
.digest('hex') +
|
.digest('hex') +
|
||||||
'_' +
|
'_' +
|
||||||
size +
|
size +
|
||||||
PhotoProcessing.CONVERTED_EXTENSION
|
'_' + Config.Media.Thumbnail.personFaceMargin +
|
||||||
|
PhotoProcessing.CONVERTED_EXTENSION
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,14 +157,14 @@ export class PhotoProcessing {
|
|||||||
* @param convertedPath
|
* @param convertedPath
|
||||||
*/
|
*/
|
||||||
public static async isValidConvertedPath(
|
public static async isValidConvertedPath(
|
||||||
convertedPath: string
|
convertedPath: string
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
const origFilePath = path.join(
|
const origFilePath = path.join(
|
||||||
ProjectPath.ImageFolder,
|
ProjectPath.ImageFolder,
|
||||||
path.relative(
|
path.relative(
|
||||||
ProjectPath.TranscodedFolder,
|
ProjectPath.TranscodedFolder,
|
||||||
convertedPath.substring(0, convertedPath.lastIndexOf('_'))
|
convertedPath.substring(0, convertedPath.lastIndexOf('_'))
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (path.extname(convertedPath) !== PhotoProcessing.CONVERTED_EXTENSION) {
|
if (path.extname(convertedPath) !== PhotoProcessing.CONVERTED_EXTENSION) {
|
||||||
@ -171,24 +172,24 @@ export class PhotoProcessing {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const sizeStr = convertedPath.substring(
|
const sizeStr = convertedPath.substring(
|
||||||
convertedPath.lastIndexOf('_') + 1,
|
convertedPath.lastIndexOf('_') + 1,
|
||||||
convertedPath.lastIndexOf('q')
|
convertedPath.lastIndexOf('q')
|
||||||
);
|
);
|
||||||
|
|
||||||
const size = parseInt(sizeStr, 10);
|
const size = parseInt(sizeStr, 10);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(size + '').length !== sizeStr.length ||
|
(size + '').length !== sizeStr.length ||
|
||||||
(Config.Media.Thumbnail.thumbnailSizes.indexOf(size) === -1 &&
|
(Config.Media.Thumbnail.thumbnailSizes.indexOf(size) === -1 &&
|
||||||
Config.Media.Photo.Converting.resolution !== size)
|
Config.Media.Photo.Converting.resolution !== size)
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let qualityStr = convertedPath.substring(
|
let qualityStr = convertedPath.substring(
|
||||||
convertedPath.lastIndexOf('q') + 1,
|
convertedPath.lastIndexOf('q') + 1,
|
||||||
convertedPath.length - path.extname(convertedPath).length
|
convertedPath.length - path.extname(convertedPath).length
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
@ -202,7 +203,7 @@ export class PhotoProcessing {
|
|||||||
const quality = parseInt(qualityStr, 10);
|
const quality = parseInt(qualityStr, 10);
|
||||||
|
|
||||||
if ((quality + '').length !== qualityStr.length ||
|
if ((quality + '').length !== qualityStr.length ||
|
||||||
quality !== Config.Media.Thumbnail.quality) {
|
quality !== Config.Media.Thumbnail.quality) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,16 +218,16 @@ export class PhotoProcessing {
|
|||||||
|
|
||||||
public static async convertPhoto(mediaPath: string): Promise<string> {
|
public static async convertPhoto(mediaPath: string): Promise<string> {
|
||||||
return this.generateThumbnail(
|
return this.generateThumbnail(
|
||||||
mediaPath,
|
mediaPath,
|
||||||
Config.Media.Photo.Converting.resolution,
|
Config.Media.Photo.Converting.resolution,
|
||||||
ThumbnailSourceType.Photo,
|
ThumbnailSourceType.Photo,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async convertedPhotoExist(
|
static async convertedPhotoExist(
|
||||||
mediaPath: string,
|
mediaPath: string,
|
||||||
size: number
|
size: number
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
// generate thumbnail path
|
// generate thumbnail path
|
||||||
const outPath = PhotoProcessing.generateConvertedPath(mediaPath, size);
|
const outPath = PhotoProcessing.generateConvertedPath(mediaPath, size);
|
||||||
@ -243,10 +244,10 @@ export class PhotoProcessing {
|
|||||||
|
|
||||||
|
|
||||||
public static async generateThumbnail(
|
public static async generateThumbnail(
|
||||||
mediaPath: string,
|
mediaPath: string,
|
||||||
size: number,
|
size: number,
|
||||||
sourceType: ThumbnailSourceType,
|
sourceType: ThumbnailSourceType,
|
||||||
makeSquare: boolean
|
makeSquare: boolean
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
// generate thumbnail path
|
// generate thumbnail path
|
||||||
const outPath = PhotoProcessing.generateConvertedPath(mediaPath, size);
|
const outPath = PhotoProcessing.generateConvertedPath(mediaPath, size);
|
||||||
@ -284,9 +285,9 @@ export class PhotoProcessing {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static async renderSVG(
|
public static async renderSVG(
|
||||||
svgString: SVGIconConfig,
|
svgIcon: SVGIconConfig,
|
||||||
outPath: string,
|
outPath: string,
|
||||||
color = '#000'
|
color = '#000'
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
|
|
||||||
// check if file already exist
|
// check if file already exist
|
||||||
@ -302,7 +303,7 @@ export class PhotoProcessing {
|
|||||||
const input = {
|
const input = {
|
||||||
type: ThumbnailSourceType.Photo,
|
type: ThumbnailSourceType.Photo,
|
||||||
svgString: `<svg fill="${color}" width="${size}" height="${size}" xmlns="http://www.w3.org/2000/svg"
|
svgString: `<svg fill="${color}" width="${size}" height="${size}" xmlns="http://www.w3.org/2000/svg"
|
||||||
viewBox="${Config.Server.svgIcon.viewBox || '0 0 512 512'}">d="${Config.Server.svgIcon.items}</svg>`,
|
viewBox="${svgIcon.viewBox || '0 0 512 512'}">d="${svgIcon.items}</svg>`,
|
||||||
size: size,
|
size: size,
|
||||||
outPath,
|
outPath,
|
||||||
makeSquare: false,
|
makeSquare: false,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user