Skip to content

Commit

Permalink
fix(server): prefer ImageSize over ImageWidth/Height metadata
Browse files Browse the repository at this point in the history
For some RAW formats/cameras, the ImageWidth/ImageHeight information represents
the dimensions of the preview image, i.e. much smaller than the actual image.
This also causes issues with (face/people) thumbnail generation.
The information in ImageSize seems to be correct, so we use this instead.

fixes #13049
  • Loading branch information
C-Otto committed Oct 11, 2024
1 parent 930df46 commit 93c9466
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 3 deletions.
24 changes: 24 additions & 0 deletions e2e/src/api/specs/asset.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1148,6 +1148,30 @@ describe('/asset', () => {
},
},
},
{
input: 'formats/raw/Canon/PowerShot_G12.CR2',
expected: {
type: AssetTypeEnum.Image,
originalFileName: 'PowerShot_G12.CR2',
fileCreatedAt: '2015-12-27T09:55:40.000Z',
exifInfo: {
make: 'Canon',
model: 'Canon PowerShot G12',
exifImageHeight: 2736,
exifImageWidth: 3648,
exposureTime: '1/1000',
fNumber: 4,
focalLength: 18.098,
iso: 80,
lensModel: null,
fileSizeInByte: 11113617,

Check failure on line 1167 in e2e/src/api/specs/asset.e2e-spec.ts

View workflow job for this annotation

GitHub Actions / End-to-End Lint

Invalid group length in numeric value
dateTimeOriginal: '2015-12-27T09:55:40.000Z',
latitude: null,
longitude: null,
orientation: '1',
},
},
}
];

it(`should upload and generate a thumbnail for different file types`, async () => {
Expand Down
2 changes: 1 addition & 1 deletion e2e/test-assets
29 changes: 27 additions & 2 deletions server/src/services/metadata.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ export class MetadataService extends BaseService {
const { dateTimeOriginal, localDateTime, timeZone, modifyDate } = this.getDates(asset, exifTags);
const { latitude, longitude, country, state, city } = await this.getGeo(exifTags, reverseGeocoding);

let imageDimensions = this.getImageDimensions(exifTags);

Check failure on line 195 in server/src/services/metadata.service.ts

View workflow job for this annotation

GitHub Actions / Test & Lint Server

'imageDimensions' is never reassigned. Use 'const' instead

const exifData: Partial<ExifEntity> = {
assetId: asset.id,

Expand All @@ -209,8 +211,8 @@ export class MetadataService extends BaseService {

// image/file
fileSizeInByte: stats.size,
exifImageHeight: validate(exifTags.ImageHeight),
exifImageWidth: validate(exifTags.ImageWidth),
exifImageHeight: validate(imageDimensions.height),
exifImageWidth: validate(imageDimensions.width),
orientation: validate(exifTags.Orientation)?.toString() ?? null,
projectionType: exifTags.ProjectionType ? String(exifTags.ProjectionType).toUpperCase() : null,
bitsPerSample: this.getBitsPerSample(exifTags),
Expand Down Expand Up @@ -334,6 +336,29 @@ export class MetadataService extends BaseService {
return JobStatus.SUCCESS;
}

private getImageDimensions(exifTags: ImmichTags): {width: number, height: number} {
/*
* The "true" values for width and height are a bit hidden, depending on the camera model and file format.
* For RAW images in the CR2 or RAF format, the "ImageSize" value seems to be correct,
* but ImageWidth and ImageHeight are not correct (the contain the dimensions of the preview image).
*/

let width = NaN;

Check failure on line 346 in server/src/services/metadata.service.ts

View workflow job for this annotation

GitHub Actions / Test & Lint Server

Prefer `Number.NaN` over `NaN`
let height = NaN;

Check failure on line 347 in server/src/services/metadata.service.ts

View workflow job for this annotation

GitHub Actions / Test & Lint Server

Prefer `Number.NaN` over `NaN`
let imageSize = exifTags.ImageSize;

Check failure on line 348 in server/src/services/metadata.service.ts

View workflow job for this annotation

GitHub Actions / Test & Lint Server

'imageSize' is never reassigned. Use 'const' instead
if (imageSize && imageSize.indexOf('x') > 0) {
// width x height (e.g. 100x200)
let split = imageSize.split('x');

Check failure on line 351 in server/src/services/metadata.service.ts

View workflow job for this annotation

GitHub Actions / Test & Lint Server

'split' is never reassigned. Use 'const' instead
width = parseInt(split[0]);

Check failure on line 352 in server/src/services/metadata.service.ts

View workflow job for this annotation

GitHub Actions / Test & Lint Server

Prefer `Number.parseInt` over `parseInt`
height = parseInt(split[1]);

Check failure on line 353 in server/src/services/metadata.service.ts

View workflow job for this annotation

GitHub Actions / Test & Lint Server

Prefer `Number.parseInt` over `parseInt`
}
if (!width || !height) {
width = exifTags.ImageWidth ?? NaN;

Check failure on line 356 in server/src/services/metadata.service.ts

View workflow job for this annotation

GitHub Actions / Test & Lint Server

Prefer `Number.NaN` over `NaN`
height = exifTags.ImageHeight ?? NaN;

Check failure on line 357 in server/src/services/metadata.service.ts

View workflow job for this annotation

GitHub Actions / Test & Lint Server

Prefer `Number.NaN` over `NaN`
}
return {width, height};
}

private async getExifTags(asset: AssetEntity): Promise<ImmichTags> {
const mediaTags = await this.metadataRepository.readTags(asset.originalPath);
const sidecarTags = asset.sidecarPath ? await this.metadataRepository.readTags(asset.sidecarPath) : {};
Expand Down

0 comments on commit 93c9466

Please sign in to comment.