mirror of
https://github.com/KevinMidboe/immich.git
synced 2026-01-05 08:45:50 +00:00
use imagemagick and libraw for raw image support (#2668)
* use imagemagick and libraw for raw image support imagemagick and libraw have generally good support for raw images, including Sony's ARW format. These tools should also allow Immich to support many more image formats in future without any major code changes. https://www.libraw.org/supported-cameras I've tested and verified this change with .ARW files and other standard formats. Fixes: #2156 * Add additional type for awr * pr feedback --------- Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
@@ -2,7 +2,7 @@ FROM node:18.16.0-alpine3.18@sha256:f41850f74ff16a33daff988e2ea06ef8f5daeb6fb849
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
RUN apk add --update-cache build-base python3 vips-heif vips-dev ffmpeg perl
|
||||
RUN apk add --update-cache build-base imagemagick-dev python3 ffmpeg libraw-dev perl vips-dev vips-heif vips-magick
|
||||
|
||||
COPY package.json package-lock.json ./
|
||||
|
||||
@@ -23,7 +23,7 @@ ENV NODE_ENV=production
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
RUN apk add --no-cache vips-heif vips vips-cpp ffmpeg perl
|
||||
RUN apk add --no-cache ffmpeg imagemagick-dev libraw-dev perl vips-dev vips-heif vips-magick
|
||||
|
||||
COPY --from=prod /usr/src/app/node_modules ./node_modules
|
||||
COPY --from=prod /usr/src/app/dist ./dist
|
||||
|
||||
2
server/package-lock.json
generated
2
server/package-lock.json
generated
@@ -45,7 +45,7 @@
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rxjs": "^7.2.0",
|
||||
"sanitize-filename": "^1.6.3",
|
||||
"sharp": "^0.31.0",
|
||||
"sharp": "^0.31.3",
|
||||
"typeorm": "^0.3.11",
|
||||
"typesense": "^1.5.3",
|
||||
"ua-parser-js": "^1.0.35"
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rxjs": "^7.2.0",
|
||||
"sanitize-filename": "^1.6.3",
|
||||
"sharp": "^0.31.0",
|
||||
"sharp": "^0.31.3",
|
||||
"typeorm": "^0.3.11",
|
||||
"typesense": "^1.5.3",
|
||||
"ua-parser-js": "^1.0.35"
|
||||
|
||||
@@ -60,9 +60,9 @@ export class MediaService {
|
||||
size: JPEG_THUMBNAIL_SIZE,
|
||||
format: 'jpeg',
|
||||
});
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
this.logger.warn(
|
||||
`Failed to generate jpeg thumbnail using sharp, trying with exiftool-vendored (asset=${asset.id})`,
|
||||
`Failed to generate jpeg thumbnail using sharp, trying with exiftool-vendored (asset=${asset.id}): ${error.message}`,
|
||||
);
|
||||
await this.mediaRepository.extractThumbnailFromExif(asset.originalPath, jpegThumbnailPath);
|
||||
}
|
||||
|
||||
@@ -49,77 +49,37 @@ describe('assetUploadOption', () => {
|
||||
expect(name).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should allow images', async () => {
|
||||
const file = { mimetype: 'image/jpeg', originalname: 'test.jpg' } as any;
|
||||
fileFilter(mock.userRequest, file, callback);
|
||||
expect(callback).toHaveBeenCalledWith(null, true);
|
||||
});
|
||||
|
||||
it('should allow videos', async () => {
|
||||
const file = { mimetype: 'video/mp4', originalname: 'test.mp4' } as any;
|
||||
fileFilter(mock.userRequest, file, callback);
|
||||
expect(callback).toHaveBeenCalledWith(null, true);
|
||||
});
|
||||
|
||||
it('should allow webm videos', async () => {
|
||||
const file = { mimetype: 'video/webm', originalname: 'test.webm' } as any;
|
||||
fileFilter(mock.userRequest, file, callback);
|
||||
expect(callback).toHaveBeenCalledWith(null, true);
|
||||
});
|
||||
|
||||
it('should allow .raf recognized', () => {
|
||||
const file = { mimetype: 'image/x-fuji-raf', originalname: 'test.raf' } as any;
|
||||
fileFilter(mock.userRequest, file, callback);
|
||||
expect(callback).toHaveBeenCalledWith(null, true);
|
||||
});
|
||||
|
||||
it('should allow .srw recognized', () => {
|
||||
const file = { mimetype: 'image/x-samsung-srw', originalname: 'test.srw' } as any;
|
||||
fileFilter(mock.userRequest, file, callback);
|
||||
expect(callback).toHaveBeenCalledWith(null, true);
|
||||
});
|
||||
|
||||
it('should allow .wmv videos', () => {
|
||||
const file = { mimetype: 'video/x-ms-wmv', originalname: 'test.wmv' } as any;
|
||||
fileFilter(mock.userRequest, file, callback);
|
||||
expect(callback).toHaveBeenCalledWith(null, true);
|
||||
});
|
||||
|
||||
it('should allow .mkv videos', () => {
|
||||
const file = { mimetype: 'video/x-matroska', originalname: 'test.mkv' } as any;
|
||||
fileFilter(mock.userRequest, file, callback);
|
||||
expect(callback).toHaveBeenCalledWith(null, true);
|
||||
});
|
||||
|
||||
it('should allow .mpg videos', () => {
|
||||
const file = { mimetype: 'video/mpeg', originalname: 'test.mpg' } as any;
|
||||
fileFilter(mock.userRequest, file, callback);
|
||||
expect(callback).toHaveBeenCalledWith(null, true);
|
||||
});
|
||||
|
||||
it('should allow .flv videos', () => {
|
||||
const file = { mimetype: 'video/x-flv', originalname: 'test.flv' } as any;
|
||||
fileFilter(mock.userRequest, file, callback);
|
||||
expect(callback).toHaveBeenCalledWith(null, true);
|
||||
});
|
||||
|
||||
it('should allow .mov videos with video/mov mimetype', () => {
|
||||
const file = { mimetype: 'video/mov', originalname: 'test.mov' } as any;
|
||||
fileFilter(mock.userRequest, file, callback);
|
||||
expect(callback).toHaveBeenCalledWith(null, true);
|
||||
});
|
||||
|
||||
it('should allow .avi videos with video/avi mimetype', () => {
|
||||
const file = { mimetype: 'video/avi', originalname: 'test.avi' } as any;
|
||||
fileFilter(mock.userRequest, file, callback);
|
||||
expect(callback).toHaveBeenCalledWith(null, true);
|
||||
});
|
||||
|
||||
it('should allow .avi videos with video/x-msvideo mimetype', () => {
|
||||
const file = { mimetype: 'video/x-msvideo', originalname: 'test.avi' } as any;
|
||||
fileFilter(mock.userRequest, file, callback);
|
||||
expect(callback).toHaveBeenCalledWith(null, true);
|
||||
});
|
||||
for (const { mimetype, extension } of [
|
||||
{ mimetype: 'image/dng', extension: 'dng' },
|
||||
{ mimetype: 'image/gif', extension: 'gif' },
|
||||
{ mimetype: 'image/heic', extension: 'heic' },
|
||||
{ mimetype: 'image/heif', extension: 'heif' },
|
||||
{ mimetype: 'image/jpeg', extension: 'jpeg' },
|
||||
{ mimetype: 'image/jpeg', extension: 'jpg' },
|
||||
{ mimetype: 'image/png', extension: 'png' },
|
||||
{ mimetype: 'image/tiff', extension: 'tiff' },
|
||||
{ mimetype: 'image/webp', extension: 'webp' },
|
||||
{ mimetype: 'image/x-adobe-dng', extension: 'dng' },
|
||||
{ mimetype: 'image/x-fuji-raf', extension: 'raf' },
|
||||
{ mimetype: 'image/x-nikon-nef', extension: 'nef' },
|
||||
{ mimetype: 'image/x-samsung-srw', extension: 'srw' },
|
||||
{ mimetype: 'image/x-sony-arw', extension: 'arw' },
|
||||
{ mimetype: 'video/avi', extension: 'avi' },
|
||||
{ mimetype: 'video/mov', extension: 'mov' },
|
||||
{ mimetype: 'video/mp4', extension: 'mp4' },
|
||||
{ mimetype: 'video/mpeg', extension: 'mpg' },
|
||||
{ mimetype: 'video/webm', extension: 'webm' },
|
||||
{ mimetype: 'video/x-flv', extension: 'flv' },
|
||||
{ mimetype: 'video/x-matroska', extension: 'mkv' },
|
||||
{ mimetype: 'video/x-ms-wmv', extension: 'wmv' },
|
||||
{ mimetype: 'video/x-msvideo', extension: 'avi' },
|
||||
]) {
|
||||
const name = `test.${extension}`;
|
||||
it(`should allow ${name} (${mimetype})`, async () => {
|
||||
fileFilter(mock.userRequest, { mimetype, originalname: name }, callback);
|
||||
expect(callback).toHaveBeenCalledWith(null, true);
|
||||
});
|
||||
}
|
||||
|
||||
it('should not allow unknown types', async () => {
|
||||
const file = { mimetype: 'application/html', originalname: 'test.html' } as any;
|
||||
|
||||
@@ -55,7 +55,7 @@ function fileFilter(req: AuthRequest, file: any, cb: any) {
|
||||
}
|
||||
if (
|
||||
file.mimetype.match(
|
||||
/\/(jpg|jpeg|png|gif|avi|mov|mp4|webm|x-msvideo|quicktime|heic|heif|dng|x-adobe-dng|webp|tiff|3gpp|nef|x-nikon-nef|x-fuji-raf|x-samsung-srw|mpeg|x-flv|x-ms-wmv|x-matroska)$/,
|
||||
/\/(jpg|jpeg|png|gif|avi|mov|mp4|webm|x-msvideo|quicktime|heic|heif|dng|x-adobe-dng|webp|tiff|3gpp|nef|x-nikon-nef|x-fuji-raf|x-samsung-srw|mpeg|x-flv|x-ms-wmv|x-matroska|x-sony-arw|arw)$/,
|
||||
)
|
||||
) {
|
||||
cb(null, true);
|
||||
|
||||
Reference in New Issue
Block a user