Skip to main content
Glama
ccw33
by ccw33

read_image

Extract dataURL and dimensions from local or URL-based images for processing in multimodal AI workflows.

Instructions

读取本地/URL图片并返回 dataURL 与尺寸信息

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
pathYes图片路径或URL
maxSideNo最大边长,用于缩放

Implementation Reference

  • Core handler function for reading images from local paths, URLs, or data URLs, compressing them using sharp, and returning a data URL with dimensions in ImageResult format.
    async function readImage(imagePath: string, maxSide?: number): Promise<ImageResult> {
      try {
        console.error(`[DEBUG] readImage called with path: ${imagePath.substring(0, 50)}...`);
        console.error(`[DEBUG] Path starts with data:? ${imagePath.startsWith("data:")}`);
        
        let buffer: Buffer;
    
        if (imagePath.startsWith("data:")) {
          // Data URL 格式
          console.error(`[DEBUG] Processing data URL in readImage`);
          const commaIndex = imagePath.indexOf(',');
          if (commaIndex === -1) {
            throw new Error("Invalid data URL format: no comma found");
          }
          const base64Data = imagePath.substring(commaIndex + 1);
          if (!base64Data) {
            throw new Error("Invalid data URL format: no base64 data");
          }
          console.error(`[DEBUG] Base64 data length: ${base64Data.length}`);
          buffer = Buffer.from(base64Data, 'base64');
        } else if (imagePath.startsWith("http://") || imagePath.startsWith("https://")) {
          // HTTP/HTTPS URL图片
          console.error(`[DEBUG] Fetching HTTP/HTTPS image`);
          const response = await fetch(imagePath);
          if (!response.ok) {
            throw new Error(`Failed to fetch image: ${response.statusText}`);
          }
          buffer = Buffer.from(await response.arrayBuffer());
        } else {
          // 本地文件
          console.error(`[DEBUG] Reading local file: ${imagePath}`);
          const resolvedPath = path.resolve(imagePath);
          buffer = await fs.readFile(resolvedPath);
        }
    
        console.error(`[DEBUG] Original buffer size: ${buffer.length}`);
        // 压缩图片
        const compressedBuffer = await compressImage(buffer, maxSide || 1024);
        console.error(`[DEBUG] Compressed buffer size: ${compressedBuffer.length}`);
        
        const mime = "image/jpeg"; // 压缩后统一为 JPEG 格式
        const dataUrl = `data:${mime};base64,${compressedBuffer.toString("base64")}`;
    
        return {
          ok: true,
          image: {
            source: imagePath,
            mime,
            dataUrl,
            width: (await sharp(compressedBuffer).metadata()).width,
            height: (await sharp(compressedBuffer).metadata()).height
          }
        };
      } catch (error) {
        return {
          ok: false,
          error: error instanceof Error ? error.message : "Unknown error"
        };
      }
    }
  • src/index.ts:51-78 (registration)
    Registers the 'read_image' tool with the MCP server, defining input schema and a wrapper handler that calls the core readImage function and formats the response.
    mcpServer.registerTool("read_image", {
      description: "读取本地/URL图片并返回 dataURL 与尺寸信息",
      inputSchema: {
        path: z.string().describe("图片路径或URL"),
        maxSide: z.number().optional().describe("最大边长,用于缩放"),
      },
    }, async ({ path: imagePath, maxSide }) => {
      try {
        const result = await readImage(imagePath, maxSide);
        return {
          content: [{
            type: "text" as const,
            text: JSON.stringify(result, null, 2)
          }]
        };
      } catch (error) {
        return {
          content: [{
            type: "text" as const,
            text: JSON.stringify({
              ok: false,
              error: error instanceof Error ? error.message : "Unknown error"
            }, null, 2)
          }],
          isError: true
        };
      }
    });
  • TypeScript interface defining the output structure of the read_image tool, including success flag, image details (dataUrl, dimensions), or error.
    interface ImageResult {
      ok: boolean;
      image?: {
        source: string;
        mime: string;
        dataUrl: string;
        width?: number;
        height?: number;
      };
      error?: string;
    }
  • Helper function to compress image buffers using Sharp library, resizing to maxSide while maintaining aspect ratio and converting to JPEG.
    async function compressImage(buffer: Buffer, maxSide: number = 1024, quality: number = 80): Promise<Buffer> {
      try {
        const image = sharp(buffer);
        const metadata = await image.metadata();
        
        let width = metadata.width || 1024;
        let height = metadata.height || 1024;
        
        // 计算缩放比例
        if (width > maxSide || height > maxSide) {
          const ratio = Math.min(maxSide / width, maxSide / height);
          width = Math.round(width * ratio);
          height = Math.round(height * ratio);
        }
        
        return await image
          .resize(width, height, { fit: 'inside' })
          .jpeg({ quality, progressive: true })
          .toBuffer();
      } catch (error) {
        console.error("Image compression failed:", error);
        return buffer; // 失败时返回原始buffer
      }
    }
Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ccw33/Multimodel-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server