mirror of
https://github.com/immich-app/immich.git
synced 2026-06-12 19:11:52 -07:00
fix(web): use irot/imir tags for HEIF Orientation (#27820)
* fix(web): use irot/imir tags for HEIF Orientation * ignore Exif Orientation for HEIF images per MIAF standard compliance * add Rotation and Mirroring to exiftool numericTags * add isHeifBasedImage function to detect HEIF-based image extensions * add getHeifBasedOrientation method to map irot/imir tags to ExifOrientation * removed mirroring, simplified code * Removed "Based" in "heifBased" --------- Co-authored-by: Jason Rasmussen <jason@rasm.me>
This commit is contained in:
@@ -84,7 +84,7 @@ export class MetadataRepository {
|
||||
inferTimezoneFromDatestamps: true,
|
||||
inferTimezoneFromTimeStamp: true,
|
||||
useMWG: true,
|
||||
numericTags: [...DefaultReadTaskOptions.numericTags, 'FocalLength', 'FileSize'],
|
||||
numericTags: [...DefaultReadTaskOptions.numericTags, 'FocalLength', 'FileSize', 'Rotation'],
|
||||
/* eslint unicorn/no-array-callback-reference: off, unicorn/no-array-method-this-argument: off */
|
||||
geoTz: (lat, lon) => geotz.find(lat, lon)[0],
|
||||
geolocation: true,
|
||||
|
||||
@@ -616,6 +616,17 @@ export class MetadataService extends BaseService {
|
||||
// never use duration from sidecar
|
||||
delete sidecarTags?.Duration;
|
||||
|
||||
// don't use Exif Orientation for HEIF based images, it's usually missing or invalid.
|
||||
// prefer irot (ExifTool QuickTime:Rotation) mapped to ExifOrientation.
|
||||
if (mimeTypes.isHeifImage(asset.originalPath)) {
|
||||
const orientation = this.getHeifOrientation(mediaTags);
|
||||
if (orientation === null) {
|
||||
delete mediaTags.Orientation;
|
||||
} else {
|
||||
mediaTags.Orientation = orientation;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
tags: { ...mediaTags, ...videoResult?.tags, ...sidecarTags },
|
||||
audio: videoResult?.audio,
|
||||
@@ -1110,4 +1121,24 @@ export class MetadataService extends BaseService {
|
||||
|
||||
return { tags, audio, video, packets, format };
|
||||
}
|
||||
|
||||
private getHeifOrientation(exifTags: ImmichTags): ExifOrientation | null {
|
||||
// https://exiftool.org/TagNames/QuickTime.html#ItemPropCont
|
||||
const rotation = typeof exifTags.Rotation === 'number' ? exifTags.Rotation : undefined;
|
||||
switch (rotation) {
|
||||
case 0: {
|
||||
return ExifOrientation.Horizontal;
|
||||
}
|
||||
case 1: {
|
||||
return ExifOrientation.Rotate270CW;
|
||||
}
|
||||
case 2: {
|
||||
return ExifOrientation.Rotate180;
|
||||
}
|
||||
case 3: {
|
||||
return ExifOrientation.Rotate90CW;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +74,11 @@ const possiblyAnimatedImage: Record<string, string[]> = Object.fromEntries(
|
||||
Object.entries(image).filter(([key]) => possiblyAnimatedImageExtensions.has(key)),
|
||||
);
|
||||
|
||||
const heifImageExtensions = new Set(['.avif', '.heic', '.heif', '.hif']);
|
||||
const heifImage: Record<string, string[]> = Object.fromEntries(
|
||||
Object.entries(image).filter(([key]) => heifImageExtensions.has(key)),
|
||||
);
|
||||
|
||||
const extensionOverrides: Record<string, string> = {
|
||||
'image/jpeg': '.jpg',
|
||||
};
|
||||
@@ -147,6 +152,7 @@ export const mimeTypes = {
|
||||
isAsset: (filename: string) => isType(filename, image) || isType(filename, video),
|
||||
isImage: (filename: string) => isType(filename, image),
|
||||
isWebSupportedImage: (filename: string) => isType(filename, webSupportedImage),
|
||||
isHeifImage: (filename: string) => isType(filename, heifImage),
|
||||
isPossiblyAnimatedImage: (filename: string) => isType(filename, possiblyAnimatedImage),
|
||||
isProfile: (filename: string) => isType(filename, profile),
|
||||
isSidecar: (filename: string) => isType(filename, sidecar),
|
||||
|
||||
Reference in New Issue
Block a user