feat(server): use embedded preview from raw images (#8773)
* extract embedded * update api * add tests * move temp file logic outside of media repo * formatting * revert `toSorted` * disable by default * clarify setting description * wording * wording * update docs * check extracted image dimensions * test that it unlinks * formatting --------- Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
@@ -393,14 +393,12 @@ describe(MediaService.name, () => {
|
||||
});
|
||||
|
||||
it('should generate a P3 thumbnail for a wide gamut image', async () => {
|
||||
assetMock.getByIds.mockResolvedValue([
|
||||
{ ...assetStub.image, exifInfo: { profileDescription: 'Adobe RGB', bitsPerSample: 14 } as ExifEntity },
|
||||
]);
|
||||
assetMock.getByIds.mockResolvedValue([assetStub.imageDng]);
|
||||
await sut.handleGenerateThumbnail({ id: assetStub.image.id });
|
||||
|
||||
expect(storageMock.mkdirSync).toHaveBeenCalledWith('upload/thumbs/user-id/as/se');
|
||||
expect(mediaMock.resize).toHaveBeenCalledWith(
|
||||
'/original/path.jpg',
|
||||
assetStub.imageDng.originalPath,
|
||||
'upload/thumbs/user-id/as/se/asset-id-thumbnail.webp',
|
||||
{
|
||||
format: ImageFormat.WEBP,
|
||||
@@ -415,7 +413,96 @@ describe(MediaService.name, () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleGenerateThumbhashThumbnail', () => {
|
||||
it('should extract embedded image if enabled and available', async () => {
|
||||
mediaMock.extract.mockResolvedValue(true);
|
||||
mediaMock.getImageDimensions.mockResolvedValue({ width: 3840, height: 2160 });
|
||||
configMock.load.mockResolvedValue([{ key: SystemConfigKey.IMAGE_EXTRACT_EMBEDDED, value: true }]);
|
||||
assetMock.getByIds.mockResolvedValue([assetStub.imageDng]);
|
||||
|
||||
await sut.handleGenerateThumbnail({ id: assetStub.image.id });
|
||||
|
||||
const extractedPath = mediaMock.extract.mock.calls.at(-1)?.[1].toString();
|
||||
expect(mediaMock.resize.mock.calls).toEqual([
|
||||
[
|
||||
extractedPath,
|
||||
'upload/thumbs/user-id/as/se/asset-id-thumbnail.webp',
|
||||
{
|
||||
format: ImageFormat.WEBP,
|
||||
size: 250,
|
||||
quality: 80,
|
||||
colorspace: Colorspace.P3,
|
||||
},
|
||||
],
|
||||
]);
|
||||
expect(extractedPath?.endsWith('.tmp')).toBe(true);
|
||||
expect(storageMock.unlink).toHaveBeenCalledWith(extractedPath);
|
||||
});
|
||||
|
||||
it('should resize original image if embedded image is too small', async () => {
|
||||
mediaMock.extract.mockResolvedValue(true);
|
||||
mediaMock.getImageDimensions.mockResolvedValue({ width: 1000, height: 1000 });
|
||||
configMock.load.mockResolvedValue([{ key: SystemConfigKey.IMAGE_EXTRACT_EMBEDDED, value: true }]);
|
||||
assetMock.getByIds.mockResolvedValue([assetStub.imageDng]);
|
||||
|
||||
await sut.handleGenerateThumbnail({ id: assetStub.image.id });
|
||||
|
||||
expect(mediaMock.resize.mock.calls).toEqual([
|
||||
[
|
||||
assetStub.imageDng.originalPath,
|
||||
'upload/thumbs/user-id/as/se/asset-id-thumbnail.webp',
|
||||
{
|
||||
format: ImageFormat.WEBP,
|
||||
size: 250,
|
||||
quality: 80,
|
||||
colorspace: Colorspace.P3,
|
||||
},
|
||||
],
|
||||
]);
|
||||
const extractedPath = mediaMock.extract.mock.calls.at(-1)?.[1].toString();
|
||||
expect(extractedPath?.endsWith('.tmp')).toBe(true);
|
||||
expect(storageMock.unlink).toHaveBeenCalledWith(extractedPath);
|
||||
});
|
||||
|
||||
it('should resize original image if embedded image not found', async () => {
|
||||
configMock.load.mockResolvedValue([{ key: SystemConfigKey.IMAGE_EXTRACT_EMBEDDED, value: true }]);
|
||||
assetMock.getByIds.mockResolvedValue([assetStub.imageDng]);
|
||||
|
||||
await sut.handleGenerateThumbnail({ id: assetStub.image.id });
|
||||
|
||||
expect(mediaMock.resize).toHaveBeenCalledWith(
|
||||
assetStub.imageDng.originalPath,
|
||||
'upload/thumbs/user-id/as/se/asset-id-thumbnail.webp',
|
||||
{
|
||||
format: ImageFormat.WEBP,
|
||||
size: 250,
|
||||
quality: 80,
|
||||
colorspace: Colorspace.P3,
|
||||
},
|
||||
);
|
||||
expect(mediaMock.getImageDimensions).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should resize original image if embedded image extraction is not enabled', async () => {
|
||||
configMock.load.mockResolvedValue([{ key: SystemConfigKey.IMAGE_EXTRACT_EMBEDDED, value: false }]);
|
||||
assetMock.getByIds.mockResolvedValue([assetStub.imageDng]);
|
||||
|
||||
await sut.handleGenerateThumbnail({ id: assetStub.image.id });
|
||||
|
||||
expect(mediaMock.extract).not.toHaveBeenCalled();
|
||||
expect(mediaMock.resize).toHaveBeenCalledWith(
|
||||
assetStub.imageDng.originalPath,
|
||||
'upload/thumbs/user-id/as/se/asset-id-thumbnail.webp',
|
||||
{
|
||||
format: ImageFormat.WEBP,
|
||||
size: 250,
|
||||
quality: 80,
|
||||
colorspace: Colorspace.P3,
|
||||
},
|
||||
);
|
||||
expect(mediaMock.getImageDimensions).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('handleGenerateThumbhash', () => {
|
||||
it('should skip thumbhash generation if asset not found', async () => {
|
||||
assetMock.getByIds.mockResolvedValue([]);
|
||||
await sut.handleGenerateThumbhash({ id: assetStub.image.id });
|
||||
|
||||
Reference in New Issue
Block a user