Add in-browser image compression

This commit is contained in:
Evan Fiordeliso 2025-07-18 12:10:15 -04:00
parent 05daa707d8
commit 2ba8523a24
2 changed files with 89 additions and 11 deletions

View File

@ -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<void> {

72
src/utils/image.ts Normal file
View File

@ -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<HTMLImageElement>((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<Blob>((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());
}