@@ -1506,6 +1506,40 @@ function registerFileHandlers(): void {
15061506 } ) ;
15071507
15081508 // Load thumbnails for file paths on disk (used to restore previews in history)
1509+ // Save an image to a user-chosen location (base64 data URI or existing file path)
1510+ ipcMain . handle ( 'media:saveImage' , async ( _ , params : {
1511+ base64 ?: string ;
1512+ mimeType ?: string ;
1513+ filePath ?: string ;
1514+ defaultFileName : string ;
1515+ } ) => {
1516+ try {
1517+ const ext = params . defaultFileName . includes ( '.' )
1518+ ? params . defaultFileName . split ( '.' ) . pop ( ) !
1519+ : ( params . mimeType ?. split ( '/' ) [ 1 ] || 'png' ) ;
1520+ const result = await dialog . showSaveDialog ( {
1521+ defaultPath : join ( homedir ( ) , 'Downloads' , params . defaultFileName ) ,
1522+ filters : [
1523+ { name : 'Images' , extensions : [ ext , 'png' , 'jpg' , 'jpeg' , 'webp' , 'gif' ] } ,
1524+ { name : 'All Files' , extensions : [ '*' ] } ,
1525+ ] ,
1526+ } ) ;
1527+ if ( result . canceled || ! result . filePath ) return { success : false } ;
1528+
1529+ if ( params . filePath && existsSync ( params . filePath ) ) {
1530+ copyFileSync ( params . filePath , result . filePath ) ;
1531+ } else if ( params . base64 ) {
1532+ const buffer = Buffer . from ( params . base64 , 'base64' ) ;
1533+ writeFileSync ( result . filePath , buffer ) ;
1534+ } else {
1535+ return { success : false , error : 'No image data provided' } ;
1536+ }
1537+ return { success : true , savedPath : result . filePath } ;
1538+ } catch ( err ) {
1539+ return { success : false , error : String ( err ) } ;
1540+ }
1541+ } ) ;
1542+
15091543 ipcMain . handle ( 'media:getThumbnails' , async ( _ , paths : Array < { filePath : string ; mimeType : string } > ) => {
15101544 const results : Record < string , { preview : string | null ; fileSize : number } > = { } ;
15111545 for ( const { filePath, mimeType } of paths ) {
0 commit comments