mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-05 08:10:14 +00:00
Adds a new image downscaling feature that resizes images before sending them to the LLM, reducing token usage for high-resolution screenshots. Changes: - Add sharp dependency for image processing - New settings: maxImageDimension (0=disabled) and imageDownscaleQuality (1-100) - New resize-image.ts utility using sharp for proportional downscaling - Integrate resizing into all image entry points: selectImages, readImageAsDataUrlWithBuffer, processImageFile, resolveImageMentions - Add settings UI controls in Context Management settings tab - Add English translation strings for the new settings - Downscaling disabled by default (opt-in) Closes #11912
65 lines
1.7 KiB
TypeScript
65 lines
1.7 KiB
TypeScript
import * as vscode from "vscode"
|
|
import fs from "fs/promises"
|
|
import * as path from "path"
|
|
import { maybeResizeImage, DEFAULT_IMAGE_DOWNSCALE_QUALITY } from "./resize-image"
|
|
|
|
export interface SelectImagesOptions {
|
|
/** Maximum dimension (width or height) in pixels for downscaling. 0 = disabled. */
|
|
maxDimension?: number
|
|
/** JPEG/WebP quality (1-100) for re-encoding resized images. */
|
|
quality?: number
|
|
}
|
|
|
|
export async function selectImages(options?: SelectImagesOptions): Promise<string[]> {
|
|
const dialogOptions: vscode.OpenDialogOptions = {
|
|
canSelectMany: true,
|
|
openLabel: "Select",
|
|
filters: {
|
|
Images: ["png", "jpg", "jpeg", "webp"], // supported by anthropic and openrouter
|
|
},
|
|
}
|
|
|
|
const fileUris = await vscode.window.showOpenDialog(dialogOptions)
|
|
|
|
if (!fileUris || fileUris.length === 0) {
|
|
return []
|
|
}
|
|
|
|
return await Promise.all(
|
|
fileUris.map(async (uri) => {
|
|
const imagePath = uri.fsPath
|
|
let buffer = await fs.readFile(imagePath)
|
|
const mimeType = getMimeType(imagePath)
|
|
|
|
// Downscale if configured
|
|
if (options?.maxDimension && options.maxDimension > 0) {
|
|
const resizeResult = await maybeResizeImage({
|
|
buffer,
|
|
mimeType,
|
|
maxDimension: options.maxDimension,
|
|
quality: options.quality ?? DEFAULT_IMAGE_DOWNSCALE_QUALITY,
|
|
})
|
|
buffer = resizeResult.buffer
|
|
}
|
|
|
|
const base64 = buffer.toString("base64")
|
|
const dataUrl = `data:${mimeType};base64,${base64}`
|
|
return dataUrl
|
|
}),
|
|
)
|
|
}
|
|
|
|
function getMimeType(filePath: string): string {
|
|
const ext = path.extname(filePath).toLowerCase()
|
|
switch (ext) {
|
|
case ".png":
|
|
return "image/png"
|
|
case ".jpeg":
|
|
case ".jpg":
|
|
return "image/jpeg"
|
|
case ".webp":
|
|
return "image/webp"
|
|
default:
|
|
throw new Error(`Unsupported file type: ${ext}`)
|
|
}
|
|
}
|