From 72e8d9e1ce6379307dd8377df9997bae1ca19fc4 Mon Sep 17 00:00:00 2001 From: Skystryder Date: Sat, 28 Jan 2023 17:46:03 -0800 Subject: [PATCH] Cleaning up image conversions to use webp, and increasing the thumbnail size. --- .../src/server/file/send-drive-file.ts | 10 +-- .../backend/src/services/drive/add-file.ts | 20 +++--- .../drive/generate-video-thumbnail.ts | 5 +- .../src/services/drive/image-processor.ts | 71 +------------------ 4 files changed, 14 insertions(+), 92 deletions(-) diff --git a/packages/backend/src/server/file/send-drive-file.ts b/packages/backend/src/server/file/send-drive-file.ts index 26a755ad25..0877369025 100644 --- a/packages/backend/src/server/file/send-drive-file.ts +++ b/packages/backend/src/server/file/send-drive-file.ts @@ -11,11 +11,7 @@ import { InternalStorage } from "@/services/drive/internal-storage.js"; import { createTemp } from "@/misc/create-temp.js"; import { downloadUrl } from "@/misc/download-url.js"; import { detectType } from "@/misc/get-file-info.js"; -import { - convertToWebp, - convertToJpeg, - convertToPng, -} from "@/services/drive/image-processor.js"; +import { convertToWebp } from "@/services/drive/image-processor.js"; import { GenerateVideoThumbnail } from "@/services/drive/generate-video-thumbnail.js"; import { StatusError } from "@/misc/fetch.js"; import { FILE_TYPE_BROWSERSAFE } from "@/const.js"; @@ -77,7 +73,7 @@ export default async function (ctx: Koa.Context) { "image/avif", ].includes(mime) ) { - return await convertToWebp(path, 498, 280); + return await convertToWebp(path, 996, 560); } else if (mime.startsWith("video/")) { return await GenerateVideoThumbnail(path); } @@ -85,7 +81,7 @@ export default async function (ctx: Koa.Context) { if (isWebpublic) { if (["image/svg+xml"].includes(mime)) { - return await convertToPng(path, 2048, 2048); + return await convertToWebp(path, 2048, 2048, 100); } } diff --git a/packages/backend/src/services/drive/add-file.ts b/packages/backend/src/services/drive/add-file.ts index da69940248..b25375b947 100644 --- a/packages/backend/src/services/drive/add-file.ts +++ b/packages/backend/src/services/drive/add-file.ts @@ -30,11 +30,7 @@ import { IdentifiableError } from "@/misc/identifiable-error.js"; import { getS3 } from "./s3.js"; import { InternalStorage } from "./internal-storage.js"; import type { IImage } from "./image-processor.js"; -import { - convertSharpToJpeg, - convertSharpToWebp, - convertSharpToPng, -} from "./image-processor.js"; +import { convertSharpToWebp } from "./image-processor.js"; import { driveLogger } from "./logger.js"; import { GenerateVideoThumbnail } from "./generate-video-thumbnail.js"; import { deleteFile } from "./delete-file.js"; @@ -75,8 +71,8 @@ async function save( if (type === "image/vnd.mozilla.apng") ext = ".apng"; } - // 拡張子からContent-Typeを設定してそうな挙動を示すオブジェクトストレージ (upcloud?) も存在するので、 - // 許可されているファイル形式でしか拡張子をつけない + // Some cloud providers (notably upcloud) will infer the content-type based + // on extension, so we remove extensions from non-browser-safe types. if (!FILE_TYPE_BROWSERSAFE.includes(type)) { ext = ""; } @@ -282,13 +278,13 @@ export async function generateAlts( try { if (["image/jpeg"].includes(type)) { - webpublic = await convertSharpToJpeg(img, 2048, 2048); + webpublic = await convertSharpToWebp(img, 2048, 2048); } else if (["image/webp"].includes(type)) { - webpublic = await convertSharpToPng(img, 2048, 2048); + webpublic = await convertSharpToWebp(img, 2048, 2048); } else if (["image/png"].includes(type)) { - webpublic = await convertSharpToPng(img, 2048, 2048); + webpublic = await convertSharpToWebp(img, 2048, 2048, 100); } else if (["image/svg+xml"].includes(type)) { - webpublic = await convertSharpToPng(img, 2048, 2048); + webpublic = await convertSharpToWebp(img, 2048, 2048); } else { logger.debug("web image not created (not an required image)"); } @@ -315,7 +311,7 @@ export async function generateAlts( "image/avif", ].includes(type) ) { - thumbnail = await convertSharpToWebp(img, 498, 280); + thumbnail = await convertSharpToWebp(img, 996, 560); } else { logger.debug("thumbnail not created (not an required file)"); } diff --git a/packages/backend/src/services/drive/generate-video-thumbnail.ts b/packages/backend/src/services/drive/generate-video-thumbnail.ts index e12d00936e..356623e79a 100644 --- a/packages/backend/src/services/drive/generate-video-thumbnail.ts +++ b/packages/backend/src/services/drive/generate-video-thumbnail.ts @@ -1,7 +1,7 @@ import * as fs from "node:fs"; import { createTempDir } from "@/misc/create-temp.js"; import type { IImage } from "./image-processor.js"; -import { convertToJpeg } from "./image-processor.js"; +import { convertToWebp } from "./image-processor.js"; import FFmpeg from "fluent-ffmpeg"; export async function GenerateVideoThumbnail(source: string): Promise { @@ -22,8 +22,7 @@ export async function GenerateVideoThumbnail(source: string): Promise { }); }); - // JPEGに変換 (Webpでもいいが、MastodonはWebpをサポートせず表示できなくなる) - return await convertToJpeg(`${dir}/out.png`, 498, 280); + return await convertToWebp(`${dir}/out.png`, 996, 560); } finally { cleanup(); } diff --git a/packages/backend/src/services/drive/image-processor.ts b/packages/backend/src/services/drive/image-processor.ts index 23404139bc..0934aa8063 100644 --- a/packages/backend/src/services/drive/image-processor.ts +++ b/packages/backend/src/services/drive/image-processor.ts @@ -6,42 +6,6 @@ export type IImage = { type: string; }; -/** - * Convert to JPEG - * with resize, remove metadata, resolve orientation, stop animation - */ -export async function convertToJpeg( - path: string, - width: number, - height: number, -): Promise { - return convertSharpToJpeg(await sharp(path), width, height); -} - -export async function convertSharpToJpeg( - sharp: sharp.Sharp, - width: number, - height: number, -): Promise { - const data = await sharp - .resize(width, height, { - fit: "inside", - withoutEnlargement: true, - }) - .rotate() - .jpeg({ - quality: 85, - progressive: true, - }) - .toBuffer(); - - return { - data, - ext: "jpg", - type: "image/jpeg", - }; -} - /** * Convert to WebP * with resize, remove metadata, resolve orientation, stop animation @@ -61,7 +25,7 @@ export async function convertSharpToWebp( height: number, quality: number = 85, ): Promise { - const data = await sharp + const data = await sharp .resize(width, height, { fit: "inside", withoutEnlargement: true, @@ -78,36 +42,3 @@ export async function convertSharpToWebp( type: "image/webp", }; } - -/** - * Convert to PNG - * with resize, remove metadata, resolve orientation, stop animation - */ -export async function convertToPng( - path: string, - width: number, - height: number, -): Promise { - return convertSharpToPng(await sharp(path), width, height); -} - -export async function convertSharpToPng( - sharp: sharp.Sharp, - width: number, - height: number, -): Promise { - const data = await sharp - .resize(width, height, { - fit: "inside", - withoutEnlargement: true, - }) - .rotate() - .png() - .toBuffer(); - - return { - data, - ext: "png", - type: "image/png", - }; -}