diff --git a/src/main.ts b/src/main.ts index fd5c4da..9dfb636 100644 --- a/src/main.ts +++ b/src/main.ts @@ -33,6 +33,7 @@ import { ReloadReadingLogCommand } from "@commands/ReloadReadingLogCommand"; import { registerReadingCalendarCodeBlockProcessor } from "@ui/code-blocks/ReadingCalendarCodeBlock"; import { registerAToZChallengeCodeBlockProcessor } from "@ui/code-blocks/AToZChallengeCodeBlock"; import moment from "@external/moment"; +import { compressImage } from "@utils/image"; export default class BookTrackerPlugin extends Plugin { public settings: BookTrackerPluginSettings; @@ -127,23 +128,28 @@ export default class BookTrackerPlugin extends Plugin { } filePath += fileName + "." + extension; - const existingFile = this.app.vault.getFileByPath(filePath); - if (existingFile) { + let file = this.app.vault.getFileByPath(filePath); + if (file) { if (this.settings.overwriteExistingCovers || overwrite) { - await this.app.vault.modifyBinary( - existingFile, - response.arrayBuffer - ); + await this.app.vault.modifyBinary(file, response.arrayBuffer); } else { new Notice("Cover image already exists: " + filePath); + return file; } - return existingFile; + } else { + file = await this.app.vault.createBinary( + filePath, + response.arrayBuffer + ); } - return await this.app.vault.createBinary( - filePath, - response.arrayBuffer - ); + await compressImage(this.app, file, { + height: 400, + quality: 0.8, + maintainAspectRatio: true, + }); + + return file; } async createEntry(book: Book): Promise { diff --git a/src/utils/image.ts b/src/utils/image.ts new file mode 100644 index 0000000..e3bb6a2 --- /dev/null +++ b/src/utils/image.ts @@ -0,0 +1,72 @@ +import { type App, type TFile } from "obsidian"; + +interface CompressOptions { + width?: number; + height?: number; + maintainAspectRatio?: boolean; + quality?: number; +} + +export async function compressImage( + app: App, + file: TFile, + options: CompressOptions +) { + const img = await new Promise((resolve) => { + const img = new Image(); + img.src = app.vault.getResourcePath(file); + img.onload = () => { + resolve(img); + }; + }); + + const canvas = document.createElement("canvas"); + const ctx = canvas.getContext("2d")!; + + const quality = options.quality ?? 1; + let height = options.height; + let width = options.width; + + if (!width && !height) { + width = img.width; + height = img.height; + } else if (!width && height) { + width = height * (img.width / img.height); + } else if (!height && width) { + height = width * (img.height / img.width); + } + + if (options.maintainAspectRatio) { + const aspectRatio = img.width / img.height; + + if (options.height) + if (width! > height!) { + height = width! / aspectRatio; + } else { + width = height! * aspectRatio; + } + } + + console.log(width, height); + + canvas.width = width!; + canvas.height = height!; + + ctx.drawImage(img, 0, 0, width!, height!); + + const blob = await new Promise((resolve, reject) => { + canvas.toBlob( + (blob) => { + if (blob) { + resolve(blob); + } else { + reject(new Error("Failed to compress image")); + } + }, + "image/jpeg", + quality + ); + }); + + return app.vault.modifyBinary(file, await blob.arrayBuffer()); +}