From e438fb5e4c0fd960a03176c2f883d857fe8e625e Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Mon, 23 Feb 2026 19:23:36 +0000 Subject: [PATCH 1/2] Added image compression for large images Co-authored-by: akemmanuel --- src/components/PromptBox.tsx | 54 +++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/src/components/PromptBox.tsx b/src/components/PromptBox.tsx index d08bb79..68eb755 100644 --- a/src/components/PromptBox.tsx +++ b/src/components/PromptBox.tsx @@ -54,6 +54,58 @@ interface PromptBoxProps contextPercent?: number | null; } +const MAX_IMAGE_SIZE = 5 * 1024 * 1024; // 5 MB +const TARGET_IMAGE_SIZE = 4.5 * 1024 * 1024; // Target slightly under 5 MB +const MAX_DIMENSION = 4096; // Max width/height + +async function compressImage(file: File): Promise { + const dataUrl = await readFileAsDataURL(file); + if (file.size <= TARGET_IMAGE_SIZE) { + return dataUrl; + } + + return new Promise((resolve, reject) => { + const img = new Image(); + img.onload = () => { + const canvas = document.createElement("canvas"); + let width = img.width; + let height = img.height; + + if (width > MAX_DIMENSION || height > MAX_DIMENSION) { + const ratio = Math.min(MAX_DIMENSION / width, MAX_DIMENSION / height); + width = Math.round(width * ratio); + height = Math.round(height * ratio); + } + + canvas.width = width; + canvas.height = height; + const ctx = canvas.getContext("2d"); + if (!ctx) { + reject(new Error("Failed to get canvas context")); + return; + } + ctx.drawImage(img, 0, 0, width, height); + + let quality = 0.9; + const tryCompress = () => { + const result = canvas.toDataURL("image/jpeg", quality); + const base64Length = result.length - "data:image/jpeg;base64,".length; + const byteSize = Math.round((base64Length * 3) / 4); + + if (byteSize <= TARGET_IMAGE_SIZE || quality <= 0.1) { + resolve(result); + } else { + quality -= 0.1; + tryCompress(); + } + }; + tryCompress(); + }; + img.onerror = reject; + img.src = dataUrl; + }); +} + function readFileAsDataURL(file: File): Promise { return new Promise((resolve, reject) => { const reader = new FileReader(); @@ -254,7 +306,7 @@ export const PromptBox = React.forwardRef( f.type.startsWith("image/"), ); if (imageFiles.length === 0) return; - const results = await Promise.all(imageFiles.map(readFileAsDataURL)); + const results = await Promise.all(imageFiles.map(compressImage)); setImagePreviews((prev) => [...prev, ...results]); }, [isDisabled], From 8768f29743817ee49d923ad8e2b60aa7eff8b5c2 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Mon, 2 Mar 2026 21:38:08 +0000 Subject: [PATCH 2/2] Fixed 5 code review issues Co-authored-by: akemmanuel --- src/components/PromptBox.tsx | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/components/PromptBox.tsx b/src/components/PromptBox.tsx index 68eb755..31785a9 100644 --- a/src/components/PromptBox.tsx +++ b/src/components/PromptBox.tsx @@ -54,7 +54,6 @@ interface PromptBoxProps contextPercent?: number | null; } -const MAX_IMAGE_SIZE = 5 * 1024 * 1024; // 5 MB const TARGET_IMAGE_SIZE = 4.5 * 1024 * 1024; // Target slightly under 5 MB const MAX_DIMENSION = 4096; // Max width/height @@ -84,6 +83,8 @@ async function compressImage(file: File): Promise { reject(new Error("Failed to get canvas context")); return; } + ctx.fillStyle = "white"; + ctx.fillRect(0, 0, width, height); ctx.drawImage(img, 0, 0, width, height); let quality = 0.9; @@ -92,16 +93,24 @@ async function compressImage(file: File): Promise { const base64Length = result.length - "data:image/jpeg;base64,".length; const byteSize = Math.round((base64Length * 3) / 4); - if (byteSize <= TARGET_IMAGE_SIZE || quality <= 0.1) { + if (byteSize <= TARGET_IMAGE_SIZE) { resolve(result); - } else { + } else if (quality > 0.1) { quality -= 0.1; tryCompress(); + } else { + console.warn( + `Image still exceeds target size (${byteSize} bytes) even at minimum quality. Returning low-quality result.`, + ); + resolve(result); } }; tryCompress(); + img.src = ""; + }; + img.onerror = () => { + reject(new Error("Failed to load image. The file may be corrupt.")); }; - img.onerror = reject; img.src = dataUrl; }); }