mirror of
https://github.com/immich-app/immich.git
synced 2024-12-29 15:11:58 +00:00
fix(server): orientation handling for person thumbnails (#10382)
fix orientation handling
This commit is contained in:
parent
0b08af7082
commit
e77e87b936
4 changed files with 17 additions and 27 deletions
|
@ -47,6 +47,10 @@ export interface ImageDimensions {
|
|||
height: number;
|
||||
}
|
||||
|
||||
export interface InputDimensions extends ImageDimensions {
|
||||
inputPath: string;
|
||||
}
|
||||
|
||||
export interface VideoInfo {
|
||||
format: VideoFormat;
|
||||
videoStreams: VideoStreamInfo[];
|
||||
|
|
|
@ -917,9 +917,9 @@ describe(PersonService.name, () => {
|
|||
colorspace: Colorspace.P3,
|
||||
crop: {
|
||||
left: 0,
|
||||
top: 428,
|
||||
width: 1102,
|
||||
height: 1102,
|
||||
top: 85,
|
||||
width: 510,
|
||||
height: 510,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
|
|
@ -41,13 +41,12 @@ import {
|
|||
} from 'src/interfaces/job.interface';
|
||||
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
||||
import { BoundingBox, IMachineLearningRepository } from 'src/interfaces/machine-learning.interface';
|
||||
import { CropOptions, IMediaRepository, ImageDimensions } from 'src/interfaces/media.interface';
|
||||
import { CropOptions, IMediaRepository, ImageDimensions, InputDimensions } from 'src/interfaces/media.interface';
|
||||
import { IMoveRepository } from 'src/interfaces/move.interface';
|
||||
import { IPersonRepository, UpdateFacesData } from 'src/interfaces/person.interface';
|
||||
import { ISearchRepository } from 'src/interfaces/search.interface';
|
||||
import { IStorageRepository } from 'src/interfaces/storage.interface';
|
||||
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
||||
import { Orientation } from 'src/services/metadata.service';
|
||||
import { CacheControl, ImmichFileResponse } from 'src/utils/file';
|
||||
import { mimeTypes } from 'src/utils/mime-types';
|
||||
import { isFacialRecognitionEnabled } from 'src/utils/misc';
|
||||
|
@ -520,7 +519,7 @@ export class PersonService {
|
|||
return JobStatus.FAILED;
|
||||
}
|
||||
|
||||
const { width, height, inputPath } = await this.getInputDimensions(asset);
|
||||
const { width, height, inputPath } = await this.getInputDimensions(asset, { width: oldWidth, height: oldHeight });
|
||||
|
||||
const thumbnailPath = StorageCore.getPersonThumbnailPath(person);
|
||||
this.storageCore.ensureFolders(thumbnailPath);
|
||||
|
@ -601,7 +600,7 @@ export class PersonService {
|
|||
return person;
|
||||
}
|
||||
|
||||
private async getInputDimensions(asset: AssetEntity): Promise<ImageDimensions & { inputPath: string }> {
|
||||
private async getInputDimensions(asset: AssetEntity, oldDims: ImageDimensions): Promise<InputDimensions> {
|
||||
if (!asset.exifInfo?.exifImageHeight || !asset.exifInfo.exifImageWidth) {
|
||||
throw new Error(`Asset ${asset.id} dimensions are unknown`);
|
||||
}
|
||||
|
@ -611,10 +610,11 @@ export class PersonService {
|
|||
}
|
||||
|
||||
if (asset.type === AssetType.IMAGE) {
|
||||
const { width, height } = this.withOrientation(asset.exifInfo.orientation as Orientation, {
|
||||
width: asset.exifInfo.exifImageWidth,
|
||||
height: asset.exifInfo.exifImageHeight,
|
||||
});
|
||||
let { exifImageWidth: width, exifImageHeight: height } = asset.exifInfo;
|
||||
if (oldDims.height > oldDims.width !== height > width) {
|
||||
[width, height] = [height, width];
|
||||
}
|
||||
|
||||
return { width, height, inputPath: asset.originalPath };
|
||||
}
|
||||
|
||||
|
@ -622,20 +622,6 @@ export class PersonService {
|
|||
return { width, height, inputPath: asset.previewPath };
|
||||
}
|
||||
|
||||
private withOrientation(orientation: Orientation, { width, height }: ImageDimensions): ImageDimensions {
|
||||
switch (orientation) {
|
||||
case Orientation.MirrorHorizontalRotate270CW:
|
||||
case Orientation.Rotate90CW:
|
||||
case Orientation.MirrorHorizontalRotate90CW:
|
||||
case Orientation.Rotate270CW: {
|
||||
return { width: height, height: width };
|
||||
}
|
||||
default: {
|
||||
return { width, height };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private getCrop(dims: { old: ImageDimensions; new: ImageDimensions }, { x1, y1, x2, y2 }: BoundingBox): CropOptions {
|
||||
const widthScale = dims.new.width / dims.old.width;
|
||||
const heightScale = dims.new.height / dims.old.height;
|
||||
|
|
4
server/test/fixtures/face.stub.ts
vendored
4
server/test/fixtures/face.stub.ts
vendored
|
@ -72,8 +72,8 @@ export const faceStub = {
|
|||
boundingBoxY1: 5,
|
||||
boundingBoxX2: 505,
|
||||
boundingBoxY2: 505,
|
||||
imageHeight: 1000,
|
||||
imageWidth: 1000,
|
||||
imageHeight: 2880,
|
||||
imageWidth: 2160,
|
||||
}),
|
||||
middle: Object.freeze<NonNullableProperty<AssetFaceEntity>>({
|
||||
id: 'assetFaceId6',
|
||||
|
|
Loading…
Reference in a new issue