@@ -7,6 +7,54 @@ import React from "react";
77import * as ServerTypes from "@/sdk/types/IServer" ;
88import { cn } from "@/lib/utils" ;
99
10+ const readBlobAsDataUrl = ( blob : Blob ) => new Promise < string > ( ( resolve , reject ) => {
11+ const reader = new FileReader ( ) ;
12+ reader . onload = ( ) => resolve ( reader . result as string ) ;
13+ reader . onerror = ( ) => reject ( reader . error ) ;
14+ reader . readAsDataURL ( blob ) ;
15+ } ) ;
16+
17+ const reencodeImageToJpeg = ( file : File ) => new Promise < string > ( ( resolve , reject ) => {
18+ const objectUrl = URL . createObjectURL ( file ) ;
19+ const img = new Image ( ) ;
20+ img . onload = ( ) => {
21+ try {
22+ const canvas = document . createElement ( "canvas" ) ;
23+ canvas . width = img . naturalWidth || img . width ;
24+ canvas . height = img . naturalHeight || img . height ;
25+ const ctx = canvas . getContext ( "2d" ) ;
26+ if ( ! ctx ) {
27+ reject ( new Error ( "Canvas context unavailable" ) ) ;
28+ return ;
29+ }
30+ ctx . drawImage ( img , 0 , 0 ) ;
31+ canvas . toBlob ( ( blob ) => {
32+ URL . revokeObjectURL ( objectUrl ) ;
33+ if ( ! blob ) {
34+ reject ( new Error ( "Failed to encode JPEG" ) ) ;
35+ return ;
36+ }
37+ readBlobAsDataUrl ( blob ) . then ( resolve ) . catch ( reject ) ;
38+ } , "image/jpeg" , 0.92 ) ;
39+ } catch ( err ) {
40+ URL . revokeObjectURL ( objectUrl ) ;
41+ reject ( err ) ;
42+ }
43+ } ;
44+ img . onerror = ( ) => {
45+ URL . revokeObjectURL ( objectUrl ) ;
46+ reject ( new Error ( "Failed to load pasted image" ) ) ;
47+ } ;
48+ img . src = objectUrl ;
49+ } ) ;
50+
51+ const ensureJpegDataUrl = ( file : File ) => {
52+ if ( file . type === "image/jpeg" ) {
53+ return readBlobAsDataUrl ( file ) ;
54+ }
55+ return reencodeImageToJpeg ( file ) . catch ( ( ) => readBlobAsDataUrl ( file ) ) ;
56+ } ;
57+
1058interface UserInputProps {
1159 onUserMessage : ( message : ServerTypes . Message ) => void ;
1260 /** This controls the send button. Not the editor. */
@@ -167,12 +215,7 @@ export function UserInput({ onUserMessage, inputEnabled, initialMessage, editorH
167215 if ( item . kind === "file" && item . type . startsWith ( "image/" ) ) {
168216 const file = item . getAsFile ( ) ;
169217 if ( ! file ) continue ;
170- filePromises . push ( new Promise ( ( resolve , reject ) => {
171- const reader = new FileReader ( ) ;
172- reader . onload = ( ) => resolve ( reader . result as string ) ;
173- reader . onerror = ( ) => reject ( reader . error ) ;
174- reader . readAsDataURL ( file ) ;
175- } ) ) ;
218+ filePromises . push ( ensureJpegDataUrl ( file ) ) ;
176219 }
177220 }
178221 if ( filePromises . length > 0 ) {
0 commit comments