stage 1
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Web Worker for image optimization (P1). Offloads the expensive bitmap decode,
|
||||
* resize, and JPEG/PNG compression to a background thread so the UI remains
|
||||
* responsive while processing large photos.
|
||||
*
|
||||
* Uses OffscreenCanvas which is available in Chrome 69+, Firefox 105+, and
|
||||
* Safari 16.4+. The main module (images.js) detects support at runtime and
|
||||
* falls back to the main thread for older browsers.
|
||||
*/
|
||||
|
||||
function fitIntoBox(originalWidth, originalHeight, maxWidth, maxHeight) {
|
||||
const ratio = Math.min(maxWidth / originalWidth, maxHeight / originalHeight, 1);
|
||||
|
||||
return {
|
||||
width: Math.round(originalWidth * ratio),
|
||||
height: Math.round(originalHeight * ratio)
|
||||
};
|
||||
}
|
||||
|
||||
self.onmessage = async (event) => {
|
||||
const { id, file, imageRules } = event.data;
|
||||
|
||||
try {
|
||||
const imageBitmap = await createImageBitmap(file);
|
||||
const maxWidth = imageRules?.maxWidthPx || imageBitmap.width;
|
||||
const maxHeight = imageRules?.maxHeightPx || imageBitmap.height;
|
||||
const { width, height } = fitIntoBox(imageBitmap.width, imageBitmap.height, maxWidth, maxHeight);
|
||||
|
||||
const canvas = new OffscreenCanvas(width, height);
|
||||
const context = canvas.getContext('2d');
|
||||
context.drawImage(imageBitmap, 0, 0, width, height);
|
||||
imageBitmap.close();
|
||||
|
||||
const targetMimeType = file.type === 'image/png' ? 'image/png' : 'image/jpeg';
|
||||
const quality = Math.min(Math.max((imageRules?.jpegQuality || 82) / 100, 0.2), 0.95);
|
||||
const blob = await canvas.convertToBlob({ type: targetMimeType, quality });
|
||||
|
||||
if (!blob) {
|
||||
throw new Error(`Failed to optimize image: ${file.name}`);
|
||||
}
|
||||
|
||||
if (imageRules?.maxFileSizeBytes && blob.size > imageRules.maxFileSizeBytes) {
|
||||
throw new Error(`Optimized image still exceeds limit: ${file.name}`);
|
||||
}
|
||||
|
||||
self.postMessage({
|
||||
id,
|
||||
result: {
|
||||
blob,
|
||||
width,
|
||||
height,
|
||||
extension: targetMimeType === 'image/png' ? 'png' : 'jpg'
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
self.postMessage({ id, error: error.message });
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user