mirror of
				https://github.com/immich-app/immich.git
				synced 2025-11-03 19:17:11 -05:00 
			
		
		
		
	fix(server): wrong image dimensions for RAW files (RAF, CR2) (also fixes face preview) (#13377)
This commit is contained in:
		
							parent
							
								
									b95bc32310
								
							
						
					
					
						commit
						cdabd08139
					
				@ -1148,6 +1148,78 @@ 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: 11_113_617,
 | 
				
			||||||
 | 
					            dateTimeOriginal: '2015-12-27T09:55:40.000Z',
 | 
				
			||||||
 | 
					            latitude: null,
 | 
				
			||||||
 | 
					            longitude: null,
 | 
				
			||||||
 | 
					            orientation: '1',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        input: 'formats/raw/Fujifilm/X100V_compressed.RAF',
 | 
				
			||||||
 | 
					        expected: {
 | 
				
			||||||
 | 
					          type: AssetTypeEnum.Image,
 | 
				
			||||||
 | 
					          originalFileName: 'X100V_compressed.RAF',
 | 
				
			||||||
 | 
					          fileCreatedAt: '2024-10-12T21:01:01.000Z',
 | 
				
			||||||
 | 
					          exifInfo: {
 | 
				
			||||||
 | 
					            make: 'FUJIFILM',
 | 
				
			||||||
 | 
					            model: 'X100V',
 | 
				
			||||||
 | 
					            exifImageHeight: 4160,
 | 
				
			||||||
 | 
					            exifImageWidth: 6240,
 | 
				
			||||||
 | 
					            exposureTime: '1/4000',
 | 
				
			||||||
 | 
					            fNumber: 16,
 | 
				
			||||||
 | 
					            focalLength: 23,
 | 
				
			||||||
 | 
					            iso: 160,
 | 
				
			||||||
 | 
					            lensModel: null,
 | 
				
			||||||
 | 
					            fileSizeInByte: 13_551_312,
 | 
				
			||||||
 | 
					            dateTimeOriginal: '2024-10-12T21:01:01.000Z',
 | 
				
			||||||
 | 
					            latitude: null,
 | 
				
			||||||
 | 
					            longitude: null,
 | 
				
			||||||
 | 
					            orientation: '6',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        input: 'formats/raw/Ricoh/GR3/Ricoh_GR3-450.DNG',
 | 
				
			||||||
 | 
					        expected: {
 | 
				
			||||||
 | 
					          type: AssetTypeEnum.Image,
 | 
				
			||||||
 | 
					          originalFileName: 'Ricoh_GR3-450.DNG',
 | 
				
			||||||
 | 
					          fileCreatedAt: '2024-06-08T13:48:39.000Z',
 | 
				
			||||||
 | 
					          exifInfo: {
 | 
				
			||||||
 | 
					            dateTimeOriginal: '2024-06-08T13:48:39.000Z',
 | 
				
			||||||
 | 
					            exifImageHeight: 4064,
 | 
				
			||||||
 | 
					            exifImageWidth: 6112,
 | 
				
			||||||
 | 
					            exposureTime: '1/400',
 | 
				
			||||||
 | 
					            fNumber: 5,
 | 
				
			||||||
 | 
					            fileSizeInByte: 31_175_472,
 | 
				
			||||||
 | 
					            focalLength: 18.3,
 | 
				
			||||||
 | 
					            iso: 100,
 | 
				
			||||||
 | 
					            latitude: 36.613_24,
 | 
				
			||||||
 | 
					            lensModel: 'GR LENS 18.3mm F2.8',
 | 
				
			||||||
 | 
					            longitude: -121.897_85,
 | 
				
			||||||
 | 
					            make: 'RICOH IMAGING COMPANY, LTD.',
 | 
				
			||||||
 | 
					            model: 'RICOH GR III',
 | 
				
			||||||
 | 
					            orientation: '1',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it(`should upload and generate a thumbnail for different file types`, async () => {
 | 
					    it(`should upload and generate a thumbnail for different file types`, async () => {
 | 
				
			||||||
 | 
				
			|||||||
@ -1 +1 @@
 | 
				
			|||||||
Subproject commit 3e057d2f58750acdf7ff281a3938e34a86cfef4d
 | 
					Subproject commit 99544a200412d553103cc7b8f1a28f339c7cffd9
 | 
				
			||||||
@ -187,6 +187,8 @@ export class MetadataService extends BaseService {
 | 
				
			|||||||
    const { dateTimeOriginal, localDateTime, timeZone, modifyDate } = this.getDates(asset, exifTags);
 | 
					    const { dateTimeOriginal, localDateTime, timeZone, modifyDate } = this.getDates(asset, exifTags);
 | 
				
			||||||
    const { latitude, longitude, country, state, city } = await this.getGeo(exifTags, reverseGeocoding);
 | 
					    const { latitude, longitude, country, state, city } = await this.getGeo(exifTags, reverseGeocoding);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { width, height } = this.getImageDimensions(exifTags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const exifData: Partial<ExifEntity> = {
 | 
					    const exifData: Partial<ExifEntity> = {
 | 
				
			||||||
      assetId: asset.id,
 | 
					      assetId: asset.id,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -204,8 +206,8 @@ export class MetadataService extends BaseService {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      // image/file
 | 
					      // image/file
 | 
				
			||||||
      fileSizeInByte: stats.size,
 | 
					      fileSizeInByte: stats.size,
 | 
				
			||||||
      exifImageHeight: validate(exifTags.ImageHeight),
 | 
					      exifImageHeight: validate(height),
 | 
				
			||||||
      exifImageWidth: validate(exifTags.ImageWidth),
 | 
					      exifImageWidth: validate(width),
 | 
				
			||||||
      orientation: validate(exifTags.Orientation)?.toString() ?? null,
 | 
					      orientation: validate(exifTags.Orientation)?.toString() ?? null,
 | 
				
			||||||
      projectionType: exifTags.ProjectionType ? String(exifTags.ProjectionType).toUpperCase() : null,
 | 
					      projectionType: exifTags.ProjectionType ? String(exifTags.ProjectionType).toUpperCase() : null,
 | 
				
			||||||
      bitsPerSample: this.getBitsPerSample(exifTags),
 | 
					      bitsPerSample: this.getBitsPerSample(exifTags),
 | 
				
			||||||
@ -333,6 +335,19 @@ export class MetadataService extends BaseService {
 | 
				
			|||||||
    return JobStatus.SUCCESS;
 | 
					    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 (they contain the dimensions of the preview image).
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    let [width, height] = exifTags.ImageSize?.split('x').map((dim) => Number.parseInt(dim) || undefined) || [];
 | 
				
			||||||
 | 
					    if (!width || !height) {
 | 
				
			||||||
 | 
					      [width, height] = [exifTags.ImageWidth, exifTags.ImageHeight];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return { width, height };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private async getExifTags(asset: AssetEntity): Promise<ImmichTags> {
 | 
					  private async getExifTags(asset: AssetEntity): Promise<ImmichTags> {
 | 
				
			||||||
    const mediaTags = await this.metadataRepository.readTags(asset.originalPath);
 | 
					    const mediaTags = await this.metadataRepository.readTags(asset.originalPath);
 | 
				
			||||||
    const sidecarTags = asset.sidecarPath ? await this.metadataRepository.readTags(asset.sidecarPath) : {};
 | 
					    const sidecarTags = asset.sidecarPath ? await this.metadataRepository.readTags(asset.sidecarPath) : {};
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user