diff --git a/packages/backend/src/server/file/send-drive-file.ts b/packages/backend/src/server/file/send-drive-file.ts index f3c6c518f..967df1d57 100644 --- a/packages/backend/src/server/file/send-drive-file.ts +++ b/packages/backend/src/server/file/send-drive-file.ts @@ -11,7 +11,7 @@ import { DriveFiles } from '@/models/index'; import { InternalStorage } from '@/services/drive/internal-storage'; import { downloadUrl } from '@/misc/download-url'; import { detectType } from '@/misc/get-file-info'; -import { convertToJpeg, convertToPng, convertToPngOrJpeg } from '@/services/drive/image-processor'; +import { convertToJpeg, convertToPng } from '@/services/drive/image-processor'; import { GenerateVideoThumbnail } from '@/services/drive/generate-video-thumbnail'; import { StatusError } from '@/misc/fetch'; import { FILE_TYPE_BROWSERSAFE } from '@/const'; @@ -68,7 +68,7 @@ export default async function(ctx: Koa.Context) { if (['image/jpeg', 'image/webp'].includes(mime)) { return await convertToJpeg(path, 498, 280); } else if (['image/png', 'image/svg+xml'].includes(mime)) { - return await convertToPngOrJpeg(path, 498, 280); + return await convertToPng(path, 498, 280); } else if (mime.startsWith('video/')) { return await GenerateVideoThumbnail(path); } diff --git a/packages/backend/src/services/drive/add-file.ts b/packages/backend/src/services/drive/add-file.ts index a91b00d0b..0135ca107 100644 --- a/packages/backend/src/services/drive/add-file.ts +++ b/packages/backend/src/services/drive/add-file.ts @@ -7,7 +7,7 @@ import { deleteFile } from './delete-file'; import { fetchMeta } from '@/misc/fetch-meta'; import { GenerateVideoThumbnail } from './generate-video-thumbnail'; import { driveLogger } from './logger'; -import { IImage, convertSharpToJpeg, convertSharpToWebp, convertSharpToPng, convertSharpToPngOrJpeg } from './image-processor'; +import { IImage, convertSharpToJpeg, convertSharpToWebp, convertSharpToPng } from './image-processor'; import { contentDisposition } from '@/misc/content-disposition'; import { getFileInfo } from '@/misc/get-file-info'; import { DriveFiles, DriveFolders, Users, Instances, UserProfiles } from '@/models/index'; @@ -178,7 +178,7 @@ export async function generateAlts(path: string, type: string, generateWeb: bool } let img: sharp.Sharp | null = null; - let webpublicNeeded: boolean; + let satisfyWebpublic: boolean; try { img = sharp(path); @@ -193,8 +193,11 @@ export async function generateAlts(path: string, type: string, generateWeb: bool }; } - webpublicNeeded = !!metadata.exif || !!metadata.icc || !!metadata.iptc || !!metadata.xmp || !!metadata.tifftagPhotoshop - || !metadata.width || metadata.width > 2048 || !metadata.height || metadata.height > 2048; + satisfyWebpublic = !!( + !(metadata.exif || metadata.iptc || metadata.xmp || metadata.tifftagPhotoshop) && + metadata.width && metadata.width <= 2048 && + metadata.height && metadata.height <= 2048 + ); } catch (e) { logger.warn(`sharp failed: ${e}`); return { @@ -206,18 +209,14 @@ export async function generateAlts(path: string, type: string, generateWeb: bool // #region webpublic let webpublic: IImage | null = null; - if (generateWeb) { + if (generateWeb && !satisfyWebpublic) { logger.info(`creating web image`); try { - if (['image/jpeg'].includes(type) && webpublicNeeded) { - webpublic = await convertSharpToJpeg(img, 2048, 2048); - } else if (['image/webp'].includes(type) && webpublicNeeded) { + if (['image/webp', 'image/jpeg'].includes(type)) { webpublic = await convertSharpToWebp(img, 2048, 2048); - } else if (['image/png'].includes(type) && webpublicNeeded) { - webpublic = await convertSharpToPng(img, 2048, 2048); - } else if (['image/svg+xml'].includes(type)) { - webpublic = await convertSharpToPng(img, 2048, 2048); + } else if (['image/png', 'image/svg+xml'].includes(type)) { + webpublic = await convertSharpToWebp(img, 2048, 2048, 100); } else { logger.debug(`web image not created (not an required image)`); } @@ -225,7 +224,8 @@ export async function generateAlts(path: string, type: string, generateWeb: bool logger.warn(`web image not created (an error occured)`, e); } } else { - logger.info(`web image not created (from remote)`); + if (satisfyWebpublic) logger.info(`web image not created (original satisfies webpublic)`); + else logger.info(`web image not created (from remote)`); } // #endregion webpublic @@ -233,10 +233,8 @@ export async function generateAlts(path: string, type: string, generateWeb: bool let thumbnail: IImage | null = null; try { - if (['image/jpeg', 'image/webp'].includes(type)) { - thumbnail = await convertSharpToJpeg(img, 498, 280); - } else if (['image/png', 'image/svg+xml'].includes(type)) { - thumbnail = await convertSharpToPngOrJpeg(img, 498, 280); + if (['image/jpeg', 'image/webp', 'image/png', 'image/svg+xml'].includes(type)) { + thumbnail = await convertSharpToWebp(img, 498, 280); } else { logger.debug(`thumbnail not created (not an required file)`); } diff --git a/packages/backend/src/services/drive/image-processor.ts b/packages/backend/src/services/drive/image-processor.ts index f3c4a2abd..bb31ca705 100644 --- a/packages/backend/src/services/drive/image-processor.ts +++ b/packages/backend/src/services/drive/image-processor.ts @@ -42,7 +42,7 @@ export async function convertToWebp(path: string, width: number, height: number) return convertSharpToWebp(await sharp(path), width, height); } -export async function convertSharpToWebp(sharp: sharp.Sharp, width: number, height: number): Promise { +export async function convertSharpToWebp(sharp: sharp.Sharp, width: number, height: number, quality: number = 85): Promise { const data = await sharp .resize(width, height, { fit: 'inside', @@ -50,7 +50,7 @@ export async function convertSharpToWebp(sharp: sharp.Sharp, width: number, heig }) .rotate() .webp({ - quality: 85, + quality, }) .toBuffer(); @@ -85,23 +85,3 @@ export async function convertSharpToPng(sharp: sharp.Sharp, width: number, heigh type: 'image/png', }; } - -/** - * Convert to PNG or JPEG - * with resize, remove metadata, resolve orientation, stop animation - */ -export async function convertToPngOrJpeg(path: string, width: number, height: number): Promise { - return convertSharpToPngOrJpeg(await sharp(path), width, height); -} - -export async function convertSharpToPngOrJpeg(sharp: sharp.Sharp, width: number, height: number): Promise { - const stats = await sharp.stats(); - const metadata = await sharp.metadata(); - - // 不透明で300x300pxの範囲を超えていればJPEG - if (stats.isOpaque && ((metadata.width && metadata.width >= 300) || (metadata.height && metadata!.height >= 300))) { - return await convertSharpToJpeg(sharp, width, height); - } else { - return await convertSharpToPng(sharp, width, height); - } -}