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