|
|
|
|
@ -599,8 +599,11 @@ describe(MediaService.name, () => {
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should extract embedded image if enabled and available', async () => {
|
|
|
|
|
mocks.media.extract.mockResolvedValue({ buffer: extractedBuffer, format: RawExtractedFormat.Jpeg });
|
|
|
|
|
mocks.media.getImageDimensions.mockResolvedValue({ width: 3840, height: 2160 });
|
|
|
|
|
mocks.media.extract.mockResolvedValue({
|
|
|
|
|
buffer: extractedBuffer,
|
|
|
|
|
format: RawExtractedFormat.Jpeg,
|
|
|
|
|
dimensions: { width: 3840, height: 2160 },
|
|
|
|
|
});
|
|
|
|
|
mocks.systemMetadata.get.mockResolvedValue({ image: { extractEmbedded: true } });
|
|
|
|
|
mocks.assetJob.getForGenerateThumbnailJob.mockResolvedValue(assetStub.imageDng);
|
|
|
|
|
|
|
|
|
|
@ -615,8 +618,11 @@ describe(MediaService.name, () => {
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should resize original image if embedded image is too small', async () => {
|
|
|
|
|
mocks.media.extract.mockResolvedValue({ buffer: extractedBuffer, format: RawExtractedFormat.Jpeg });
|
|
|
|
|
mocks.media.getImageDimensions.mockResolvedValue({ width: 1000, height: 1000 });
|
|
|
|
|
mocks.media.extract.mockResolvedValue({
|
|
|
|
|
buffer: extractedBuffer,
|
|
|
|
|
format: RawExtractedFormat.Jpeg,
|
|
|
|
|
dimensions: { width: 1000, height: 1000 },
|
|
|
|
|
});
|
|
|
|
|
mocks.systemMetadata.get.mockResolvedValue({ image: { extractEmbedded: true } });
|
|
|
|
|
mocks.assetJob.getForGenerateThumbnailJob.mockResolvedValue(assetStub.imageDng);
|
|
|
|
|
|
|
|
|
|
@ -641,7 +647,6 @@ describe(MediaService.name, () => {
|
|
|
|
|
processInvalidImages: false,
|
|
|
|
|
size: 1440,
|
|
|
|
|
});
|
|
|
|
|
expect(mocks.media.getImageDimensions).not.toHaveBeenCalled();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should resize original image if embedded image extraction is not enabled', async () => {
|
|
|
|
|
@ -657,7 +662,6 @@ describe(MediaService.name, () => {
|
|
|
|
|
processInvalidImages: false,
|
|
|
|
|
size: 1440,
|
|
|
|
|
});
|
|
|
|
|
expect(mocks.media.getImageDimensions).not.toHaveBeenCalled();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should process invalid images if enabled', async () => {
|
|
|
|
|
@ -691,7 +695,6 @@ describe(MediaService.name, () => {
|
|
|
|
|
expect.objectContaining({ processInvalidImages: false }),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
expect(mocks.media.getImageDimensions).not.toHaveBeenCalled();
|
|
|
|
|
vi.unstubAllEnvs();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
@ -699,8 +702,11 @@ describe(MediaService.name, () => {
|
|
|
|
|
mocks.systemMetadata.get.mockResolvedValue({
|
|
|
|
|
image: { fullsize: { enabled: true, format: ImageFormat.Webp }, extractEmbedded: true },
|
|
|
|
|
});
|
|
|
|
|
mocks.media.extract.mockResolvedValue({ buffer: extractedBuffer, format: RawExtractedFormat.Jpeg });
|
|
|
|
|
mocks.media.getImageDimensions.mockResolvedValue({ width: 3840, height: 2160 });
|
|
|
|
|
mocks.media.extract.mockResolvedValue({
|
|
|
|
|
buffer: extractedBuffer,
|
|
|
|
|
format: RawExtractedFormat.Jpeg,
|
|
|
|
|
dimensions: { width: 3840, height: 2160 },
|
|
|
|
|
});
|
|
|
|
|
mocks.assetJob.getForGenerateThumbnailJob.mockResolvedValue(assetStub.imageDng);
|
|
|
|
|
|
|
|
|
|
await sut.handleGenerateThumbnails({ id: assetStub.image.id });
|
|
|
|
|
@ -731,8 +737,11 @@ describe(MediaService.name, () => {
|
|
|
|
|
mocks.systemMetadata.get.mockResolvedValue({
|
|
|
|
|
image: { fullsize: { enabled: true, format: ImageFormat.Webp }, extractEmbedded: true },
|
|
|
|
|
});
|
|
|
|
|
mocks.media.extract.mockResolvedValue({ buffer: extractedBuffer, format: RawExtractedFormat.Jxl });
|
|
|
|
|
mocks.media.getImageDimensions.mockResolvedValue({ width: 3840, height: 2160 });
|
|
|
|
|
mocks.media.extract.mockResolvedValue({
|
|
|
|
|
buffer: extractedBuffer,
|
|
|
|
|
format: RawExtractedFormat.Jxl,
|
|
|
|
|
dimensions: { width: 3840, height: 2160 },
|
|
|
|
|
});
|
|
|
|
|
mocks.assetJob.getForGenerateThumbnailJob.mockResolvedValue(assetStub.imageDng);
|
|
|
|
|
|
|
|
|
|
await sut.handleGenerateThumbnails({ id: assetStub.image.id });
|
|
|
|
|
@ -771,8 +780,11 @@ describe(MediaService.name, () => {
|
|
|
|
|
|
|
|
|
|
it('should generate full-size preview directly from RAW images when extractEmbedded is false', async () => {
|
|
|
|
|
mocks.systemMetadata.get.mockResolvedValue({ image: { fullsize: { enabled: true }, extractEmbedded: false } });
|
|
|
|
|
mocks.media.extract.mockResolvedValue({ buffer: extractedBuffer, format: RawExtractedFormat.Jpeg });
|
|
|
|
|
mocks.media.getImageDimensions.mockResolvedValue({ width: 3840, height: 2160 });
|
|
|
|
|
mocks.media.extract.mockResolvedValue({
|
|
|
|
|
buffer: extractedBuffer,
|
|
|
|
|
format: RawExtractedFormat.Jpeg,
|
|
|
|
|
dimensions: { width: 3840, height: 2160 },
|
|
|
|
|
});
|
|
|
|
|
mocks.assetJob.getForGenerateThumbnailJob.mockResolvedValue(assetStub.imageDng);
|
|
|
|
|
|
|
|
|
|
await sut.handleGenerateThumbnails({ id: assetStub.image.id });
|
|
|
|
|
@ -811,8 +823,11 @@ describe(MediaService.name, () => {
|
|
|
|
|
|
|
|
|
|
it('should generate full-size preview from non-web-friendly images', async () => {
|
|
|
|
|
mocks.systemMetadata.get.mockResolvedValue({ image: { fullsize: { enabled: true } } });
|
|
|
|
|
mocks.media.extract.mockResolvedValue({ buffer: extractedBuffer, format: RawExtractedFormat.Jpeg });
|
|
|
|
|
mocks.media.getImageDimensions.mockResolvedValue({ width: 3840, height: 2160 });
|
|
|
|
|
mocks.media.extract.mockResolvedValue({
|
|
|
|
|
buffer: extractedBuffer,
|
|
|
|
|
format: RawExtractedFormat.Jpeg,
|
|
|
|
|
dimensions: { width: 3840, height: 2160 },
|
|
|
|
|
});
|
|
|
|
|
// HEIF/HIF image taken by cameras are not web-friendly, only has limited support on Safari.
|
|
|
|
|
mocks.assetJob.getForGenerateThumbnailJob.mockResolvedValue(assetStub.imageHif);
|
|
|
|
|
|
|
|
|
|
@ -840,8 +855,11 @@ describe(MediaService.name, () => {
|
|
|
|
|
|
|
|
|
|
it('should skip generating full-size preview for web-friendly images', async () => {
|
|
|
|
|
mocks.systemMetadata.get.mockResolvedValue({ image: { fullsize: { enabled: true } } });
|
|
|
|
|
mocks.media.extract.mockResolvedValue({ buffer: extractedBuffer, format: RawExtractedFormat.Jpeg });
|
|
|
|
|
mocks.media.getImageDimensions.mockResolvedValue({ width: 3840, height: 2160 });
|
|
|
|
|
mocks.media.extract.mockResolvedValue({
|
|
|
|
|
buffer: extractedBuffer,
|
|
|
|
|
format: RawExtractedFormat.Jpeg,
|
|
|
|
|
dimensions: { width: 3840, height: 2160 },
|
|
|
|
|
});
|
|
|
|
|
mocks.assetJob.getForGenerateThumbnailJob.mockResolvedValue(assetStub.image);
|
|
|
|
|
|
|
|
|
|
await sut.handleGenerateThumbnails({ id: assetStub.image.id });
|
|
|
|
|
@ -863,9 +881,17 @@ describe(MediaService.name, () => {
|
|
|
|
|
|
|
|
|
|
it('should always generate full-size preview from non-web-friendly panoramas', async () => {
|
|
|
|
|
mocks.systemMetadata.get.mockResolvedValue({ image: { fullsize: { enabled: false } } });
|
|
|
|
|
mocks.media.extract.mockResolvedValue({ buffer: extractedBuffer, format: RawExtractedFormat.Jpeg });
|
|
|
|
|
mocks.media.getImageDimensions.mockResolvedValue({ width: 3840, height: 2160 });
|
|
|
|
|
mocks.media.copyTagGroup.mockResolvedValue(true);
|
|
|
|
|
mocks.media.extract.mockResolvedValue({
|
|
|
|
|
buffer: extractedBuffer,
|
|
|
|
|
format: RawExtractedFormat.Jpeg,
|
|
|
|
|
dimensions: { width: 3840, height: 2160 },
|
|
|
|
|
});
|
|
|
|
|
mocks.metadata.readTags.mockResolvedValue({
|
|
|
|
|
ProjectionType: 'equirectangular',
|
|
|
|
|
PoseHeadingDegrees: 127,
|
|
|
|
|
FullPanoWidthPixels: 3840,
|
|
|
|
|
FullPanoHeightPixels: 2160,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
mocks.assetJob.getForGenerateThumbnailJob.mockResolvedValue(assetStub.panoramaTif);
|
|
|
|
|
|
|
|
|
|
@ -892,10 +918,14 @@ describe(MediaService.name, () => {
|
|
|
|
|
expect.any(String),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
expect(mocks.media.copyTagGroup).toHaveBeenCalledTimes(2);
|
|
|
|
|
expect(mocks.media.copyTagGroup).toHaveBeenCalledWith(
|
|
|
|
|
'XMP-GPano',
|
|
|
|
|
assetStub.panoramaTif.originalPath,
|
|
|
|
|
expect(mocks.media.writeTags).toHaveBeenCalledTimes(2);
|
|
|
|
|
expect(mocks.media.writeTags).toHaveBeenCalledWith(
|
|
|
|
|
{
|
|
|
|
|
ProjectionType: 'equirectangular',
|
|
|
|
|
PoseHeadingDegrees: 127,
|
|
|
|
|
FullPanoWidthPixels: 2560,
|
|
|
|
|
FullPanoHeightPixels: 1440,
|
|
|
|
|
},
|
|
|
|
|
expect.any(String),
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
@ -904,8 +934,11 @@ describe(MediaService.name, () => {
|
|
|
|
|
mocks.systemMetadata.get.mockResolvedValue({
|
|
|
|
|
image: { fullsize: { enabled: true, format: ImageFormat.Webp, quality: 90 } },
|
|
|
|
|
});
|
|
|
|
|
mocks.media.extract.mockResolvedValue({ buffer: extractedBuffer, format: RawExtractedFormat.Jpeg });
|
|
|
|
|
mocks.media.getImageDimensions.mockResolvedValue({ width: 3840, height: 2160 });
|
|
|
|
|
mocks.media.extract.mockResolvedValue({
|
|
|
|
|
buffer: extractedBuffer,
|
|
|
|
|
format: RawExtractedFormat.Jpeg,
|
|
|
|
|
dimensions: { width: 3840, height: 2160 },
|
|
|
|
|
});
|
|
|
|
|
// HEIF/HIF image taken by cameras are not web-friendly, only has limited support on Safari.
|
|
|
|
|
mocks.assetJob.getForGenerateThumbnailJob.mockResolvedValue(assetStub.imageHif);
|
|
|
|
|
|
|
|
|
|
@ -1190,9 +1223,8 @@ describe(MediaService.name, () => {
|
|
|
|
|
const extracted = Buffer.from('');
|
|
|
|
|
const data = Buffer.from('');
|
|
|
|
|
const info = { width: 2160, height: 3840 } as OutputInfo;
|
|
|
|
|
mocks.media.extract.mockResolvedValue({ buffer: extracted, format: RawExtractedFormat.Jpeg });
|
|
|
|
|
mocks.media.extract.mockResolvedValue({ buffer: extracted, format: RawExtractedFormat.Jpeg, dimensions: info });
|
|
|
|
|
mocks.media.decodeImage.mockResolvedValue({ data, info });
|
|
|
|
|
mocks.media.getImageDimensions.mockResolvedValue(info);
|
|
|
|
|
|
|
|
|
|
await expect(sut.handleGeneratePersonThumbnail({ id: personStub.primaryPerson.id })).resolves.toBe(
|
|
|
|
|
JobStatus.Success,
|
|
|
|
|
@ -1268,8 +1300,7 @@ describe(MediaService.name, () => {
|
|
|
|
|
const data = Buffer.from('');
|
|
|
|
|
const info = { width: 1000, height: 1000 } as OutputInfo;
|
|
|
|
|
mocks.media.decodeImage.mockResolvedValue({ data, info });
|
|
|
|
|
mocks.media.extract.mockResolvedValue({ buffer: extracted, format: RawExtractedFormat.Jpeg });
|
|
|
|
|
mocks.media.getImageDimensions.mockResolvedValue(info);
|
|
|
|
|
mocks.media.extract.mockResolvedValue({ buffer: extracted, format: RawExtractedFormat.Jpeg, dimensions: info });
|
|
|
|
|
|
|
|
|
|
await expect(sut.handleGeneratePersonThumbnail({ id: personStub.primaryPerson.id })).resolves.toBe(
|
|
|
|
|
JobStatus.Success,
|
|
|
|
|
|