markitup_extend
Extend image canvas to target aspect ratio and dimensions using AI outpainting. Provide source via URL or base64, specify aspect ratio and pixel size.
Instructions
AI-outpaint an image to a larger canvas. Useful for converting a square asset to 16:9 or 9:16, or extending a tight crop. Costs 1 credit. Provide the source image as URL or base64, plus the target aspect ratio and pixel dimensions.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| image_url | No | Public HTTPS URL of the source image. | |
| image_base64 | No | Base64-encoded source image (no data: prefix). Mutually exclusive with image_url. | |
| image_mime_type | No | image/png | |
| aspect_ratio | Yes | Target aspect ratio. One of: 1:1, 3:2, 2:3, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9. | |
| target_width | Yes | Target output width in pixels. | |
| target_height | Yes | Target output height in pixels. | |
| image_size | No |
Implementation Reference
- src/tools/extend.ts:1-26 (schema)Definition of the extendTool object with name 'markitup_extend' and its inputSchema (image_url, image_base64, aspect_ratio, target_width, target_height, image_size).
import { MarkItUpApiClient } from "../api/client.js"; export const extendTool = { name: "markitup_extend", description: "AI-outpaint an image to a larger canvas. Useful for converting a square asset to 16:9 or 9:16, or extending a tight crop. " + "Costs 1 credit. " + "Provide the source image as URL or base64, plus the target aspect ratio and pixel dimensions.", inputSchema: { type: "object", properties: { image_url: { type: "string", description: "Public HTTPS URL of the source image." }, image_base64: { type: "string", description: "Base64-encoded source image (no data: prefix). Mutually exclusive with image_url." }, image_mime_type: { type: "string", default: "image/png" }, aspect_ratio: { type: "string", description: "Target aspect ratio. One of: 1:1, 3:2, 2:3, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9.", }, target_width: { type: "number", description: "Target output width in pixels." }, target_height: { type: "number", description: "Target output height in pixels." }, image_size: { type: "string", enum: ["1K", "2K", "4K"] }, }, required: ["aspect_ratio", "target_width", "target_height"], additionalProperties: false, }, } as const; - src/tools/extend.ts:37-82 (handler)The runExtend handler function that validates inputs, converts the source image to a data URL, POSTs to /extend, and returns the result as text + image content.
export async function runExtend( api: MarkItUpApiClient, args: Record<string, unknown> ): Promise<{ content: Array<TextContent | ImageContent>; structuredContent: ExtendBackendResponse; }> { const imageUrl = typeof args.image_url === "string" ? args.image_url : undefined; const imageBase64 = typeof args.image_base64 === "string" ? args.image_base64 : undefined; const mimeType = typeof args.image_mime_type === "string" ? args.image_mime_type : "image/png"; const aspectRatio = typeof args.aspect_ratio === "string" ? args.aspect_ratio : ""; const targetWidth = typeof args.target_width === "number" ? args.target_width : 0; const targetHeight = typeof args.target_height === "number" ? args.target_height : 0; const imageSize = typeof args.image_size === "string" ? args.image_size : undefined; if (!aspectRatio || !targetWidth || !targetHeight) { throw new Error("aspect_ratio, target_width, and target_height are required"); } if (!!imageUrl === !!imageBase64) { throw new Error("Provide exactly one of image_url or image_base64"); } const imageDataUrl = imageUrl ? await fetchAsDataUrl(imageUrl) : `data:${mimeType};base64,${imageBase64}`; const body: Record<string, unknown> = { imageDataUrl, aspectRatio, targetWidth, targetHeight, }; if (imageSize) body.imageSize = imageSize; const data = await api.post<ExtendBackendResponse>("/extend", body); const content: Array<TextContent | ImageContent> = [ { type: "text", text: `Extended to ${data.width ?? targetWidth}x${data.height ?? targetHeight} (${aspectRatio}).` }, ]; const parsed = parseDataUrl(data.imageDataUrl); if (parsed) { content.push({ type: "image", data: parsed.data, mimeType: parsed.mimeType }); } return { content, structuredContent: data }; } - src/tools/extend.ts:84-96 (helper)Helper functions fetchAsDataUrl (fetches a URL and returns a data URL) and parseDataUrl (parses a data URL into mimeType and base64 data).
async function fetchAsDataUrl(url: string): Promise<string> { const res = await fetch(url); if (!res.ok) throw new Error(`Failed to fetch image_url (${res.status}): ${url}`); const buf = Buffer.from(await res.arrayBuffer()); const contentType = res.headers.get("content-type") ?? "image/png"; return `data:${contentType};base64,${buf.toString("base64")}`; } function parseDataUrl(dataUrl: string): { mimeType: string; data: string } | null { const match = dataUrl.match(/^data:([^;]+);base64,(.+)$/); if (!match) return null; return { mimeType: match[1], data: match[2] }; } - src/index.ts:41-47 (registration)The extendTool is registered in the tools array alongside balance, generate, regen, and bgremove tools.
const tools: Tool[] = [ balanceTool as unknown as Tool, generateTool as unknown as Tool, regenTool as unknown as Tool, extendTool as unknown as Tool, bgremoveTool as unknown as Tool, ]; - src/index.ts:61-62 (handler)Registration of runExtend as the handler for extendTool.name ('markitup_extend') in the CallToolRequestSchema switch statement.
case extendTool.name: return await runExtend(api, args ?? {});