Browser-based image compression for AI agents and workflows. Uses Canvas API with quality-aware encoding and no external dependencies.
Import directly into Dify, Coze, Cursor, or any tool-calling agent runtime.
{
"name": "image_compress",
"description": "Compress images in the browser with quality control and optional resizing.",
"parameters": {
"type": "object",
"properties": {
"input_base64": {
"type": "string",
"description": "Base64-encoded image data. Accepts either a data URI or raw base64."
},
"quality": {
"type": "number",
"description": "Compression quality from 0.1 to 1.0. Lower means smaller files.",
"minimum": 0.1,
"maximum": 1.0,
"default": 0.8
},
"max_width": {
"type": "integer",
"description": "Maximum output width in pixels. Use 0 to keep the original width."
},
"output_format": {
"type": "string",
"enum": ["image/jpeg", "image/png", "image/webp", "image/avif"],
"description": "Target MIME type for the compressed output.",
"default": "image/jpeg"
}
},
"required": ["input_base64"]
}
}Paste this into your system prompt to keep the generated tool implementation aligned with the contract.
# Task Constraints: Image Compression Module
When implementing browser-side image compression, you MUST follow this SOP.
## Core Prohibitions
- NEVER assume Node image libraries such as sharp or jimp are available.
- NEVER use third-party compression libraries unless they are explicitly imported.
- NEVER return raw pixel buffers in the AI response. Return base64 output instead.
## Standard Implementation
1. Normalize input_base64 by removing the data URI prefix when present.
2. Decode the bytes into a Blob and create an ImageBitmap.
3. If max_width is set and the image is wider than that value, scale proportionally.
4. Draw onto OffscreenCanvas or canvas.
5. Export with convertToBlob() or toBlob() using the requested quality and output_format.
6. Convert the Blob back to a data URI for the response.
## Guardrails
- JPEG and WebP should honor quality.
- PNG should ignore quality because it is lossless in this flow.
- AVIF may be unsupported in some browser sandboxes, so include a fallback path.
- Large images may exhaust memory. Fail fast with a clear error if decoding or rendering fails.Modern browser sandbox implementation based on ImageBitmap and OffscreenCanvas. Use it as a drop-in tool-call backend or adaptation template.
async function main(args) {
const {
input_base64,
quality = 0.8,
max_width = 0,
output_format = "image/jpeg",
} = args;
if (!input_base64) {
return { success: false, result: "", error: "input_base64 is required" };
}
try {
const base64Data = input_base64.replace(/^data:[^;]+;base64,/, "");
const binaryString = atob(base64Data);
const bytes = Uint8Array.from(binaryString, (char) => char.charCodeAt(0));
const blob = new Blob([bytes]);
const image = await createImageBitmap(blob);
let { width, height } = image;
if (max_width > 0 && width > max_width) {
const ratio = max_width / width;
width = max_width;
height = Math.round(height * ratio);
}
const canvas = new OffscreenCanvas(width, height);
const ctx = canvas.getContext("2d");
if (!ctx) {
throw new Error("Canvas context unavailable");
}
ctx.drawImage(image, 0, 0, width, height);
let targetFormat = output_format;
let outputBlob;
try {
outputBlob = await canvas.convertToBlob({
type: targetFormat,
quality: targetFormat === "image/png" ? undefined : quality,
});
} catch {
targetFormat = "image/webp";
outputBlob = await canvas.convertToBlob({ type: targetFormat, quality });
}
const buffer = await outputBlob.arrayBuffer();
const outputBase64 = btoa(
Array.from(new Uint8Array(buffer), (byte) => String.fromCharCode(byte)).join("")
);
return {
success: true,
result: "data:" + targetFormat + ";base64," + outputBase64,
mime_type: targetFormat,
original_size: bytes.length,
compressed_size: outputBlob.size,
width,
height,
};
} catch (error) {
return {
success: false,
result: "",
error: "Compression failed: " + (error instanceof Error ? error.message : String(error)),
};
}
}