Harden image processing, improve image quality

This commit is contained in:
2026-04-20 18:10:48 +04:00
parent 4f55f26851
commit ec31d1a59b
7 changed files with 193 additions and 49 deletions

View File

@@ -1,5 +1,6 @@
import Service, { service } from '@ember/service';
import { EventFactory } from 'applesauce-core';
import { sha256 } from '@noble/hashes/sha2.js';
export const DEFAULT_BLOSSOM_SERVER = 'https://blossom.nostr.build';
@@ -78,7 +79,18 @@ export default class BlossomService extends Service {
if (!this.nostrAuth.isConnected) throw new Error('Not connected');
const buffer = await file.arrayBuffer();
const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);
let hashBuffer;
if (
typeof crypto !== 'undefined' &&
crypto.subtle &&
crypto.subtle.digest
) {
hashBuffer = await crypto.subtle.digest('SHA-256', buffer);
} else {
hashBuffer = sha256(new Uint8Array(buffer));
}
const payloadHash = bufferToHex(hashBuffer);
const servers = this.servers;

View File

@@ -51,24 +51,71 @@ export default class ImageProcessorService extends Service {
this._initWorker();
}
_getImageDimensions(file) {
return new Promise((resolve, reject) => {
const img = new Image();
const url = URL.createObjectURL(file);
img.onload = () => {
const dimensions = { width: img.width, height: img.height };
URL.revokeObjectURL(url);
resolve(dimensions);
};
img.onerror = () => {
URL.revokeObjectURL(url);
reject(new Error('Could not read image dimensions'));
};
img.src = url;
});
}
async process(file, maxDimension, quality, computeBlurhash = false) {
if (!this._worker) {
// Fallback if worker initialization failed (e.g. incredibly old browsers)
throw new Error('Image processor worker is not available.');
}
return new Promise((resolve, reject) => {
const id = ++this._msgId;
this._callbacks.set(id, { resolve, reject });
try {
// 1. Get dimensions safely on the main thread
const { width: origWidth, height: origHeight } =
await this._getImageDimensions(file);
this._worker.postMessage({
id,
file,
maxDimension,
quality,
computeBlurhash,
// 2. Calculate aspect-ratio preserving dimensions
let targetWidth = origWidth;
let targetHeight = origHeight;
if (origWidth > origHeight) {
if (origWidth > maxDimension) {
targetHeight = Math.round(origHeight * (maxDimension / origWidth));
targetWidth = maxDimension;
}
} else {
if (origHeight > maxDimension) {
targetWidth = Math.round(origWidth * (maxDimension / origHeight));
targetHeight = maxDimension;
}
}
// 3. Send to worker for processing
return new Promise((resolve, reject) => {
const id = ++this._msgId;
this._callbacks.set(id, { resolve, reject });
this._worker.postMessage({
type: 'PROCESS_IMAGE',
id,
file,
targetWidth,
targetHeight,
quality,
computeBlurhash,
});
});
});
} catch (e) {
throw new Error(`Failed to process image: ${e.message}`);
}
}
willDestroy() {