fix: face and edit handling (#25738)

* fix: handle edits when creating face
This commit is contained in:
Brandon Wees
2026-02-05 13:29:46 -06:00
committed by GitHub
parent cfc5ed5997
commit 37e5968a7a
6 changed files with 938 additions and 34 deletions

View File

@@ -44,6 +44,7 @@ import { getDimensions } from 'src/utils/asset.util';
import { ImmichFileResponse } from 'src/utils/file';
import { mimeTypes } from 'src/utils/mime-types';
import { isFacialRecognitionEnabled } from 'src/utils/misc';
import { Point, transformPoints } from 'src/utils/transform';
@Injectable()
export class PersonService extends BaseService {
@@ -634,15 +635,61 @@ export class PersonService extends BaseService {
this.requireAccess({ auth, permission: Permission.PersonRead, ids: [dto.personId] }),
]);
const asset = await this.assetRepository.getById(dto.assetId, { edits: true, exifInfo: true });
if (!asset) {
throw new NotFoundException('Asset not found');
}
const edits = asset.edits || [];
let topLeft: Point = { x: dto.x, y: dto.y };
let bottomRight: Point = { x: dto.x + dto.width, y: dto.y + dto.height };
// the coordinates received from the client are based on the edited preview image
// we need to convert them to the coordinate space of the original unedited image
if (edits.length > 0) {
if (!asset.width || !asset.height || !asset.exifInfo?.exifImageWidth || !asset.exifInfo?.exifImageHeight) {
throw new BadRequestException('Asset does not have valid dimensions');
}
// convert from preview to full dimensions
const scaleFactor = asset.width / dto.imageWidth;
topLeft = { x: topLeft.x * scaleFactor, y: topLeft.y * scaleFactor };
bottomRight = { x: bottomRight.x * scaleFactor, y: bottomRight.y * scaleFactor };
const {
points: [invertedTopLeft, invertedBottomRight],
} = transformPoints(
[topLeft, bottomRight],
edits,
{ width: asset.width, height: asset.height },
{ inverse: true },
);
// make sure topLeft is top-left and bottomRight is bottom-right
topLeft = {
x: Math.min(invertedTopLeft.x, invertedBottomRight.x),
y: Math.min(invertedTopLeft.y, invertedBottomRight.y),
};
bottomRight = {
x: Math.max(invertedTopLeft.x, invertedBottomRight.x),
y: Math.max(invertedTopLeft.y, invertedBottomRight.y),
};
// now coordinates are in original image space
dto.imageHeight = asset.exifInfo.exifImageHeight;
dto.imageWidth = asset.exifInfo.exifImageWidth;
}
await this.personRepository.createAssetFace({
personId: dto.personId,
assetId: dto.assetId,
imageHeight: dto.imageHeight,
imageWidth: dto.imageWidth,
boundingBoxX1: dto.x,
boundingBoxX2: dto.x + dto.width,
boundingBoxY1: dto.y,
boundingBoxY2: dto.y + dto.height,
boundingBoxX1: Math.round(topLeft.x),
boundingBoxX2: Math.round(bottomRight.x),
boundingBoxY1: Math.round(topLeft.y),
boundingBoxY2: Math.round(bottomRight.y),
sourceType: SourceType.Manual,
});
}