Skip to main content
Glama
duke0317

Image Processing MCP Server

by duke0317

create_gif

Create animated GIFs from multiple image sources by specifying frame duration and loop settings for visual storytelling or demonstration purposes.

Instructions

创建GIF动画

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
image_sourcesYes图片源列表,每个元素可以是文件路径或base64编码的图片数据
durationNo每帧持续时间(毫秒)
loopNo循环次数,0表示无限循环

Implementation Reference

  • main.py:772-792 (registration)
    MCP tool registration for 'create_gif' using @mcp.tool() decorator. This wrapper function collects arguments and calls the advanced handler.
    @mcp.tool()
    def create_gif(
        image_sources: Annotated[list, Field(description="图片源列表,每个元素可以是文件路径或base64编码的图片数据")],
        duration: Annotated[int, Field(description="每帧持续时间(毫秒)", ge=50, default=500)],
        loop: Annotated[int, Field(description="循环次数,0表示无限循环", ge=0, default=0)]
    ) -> str:
        """创建GIF动画"""
        try:
            arguments = {
                "image_sources": image_sources,
                "duration": duration,
                "loop": loop
            }
            result = safe_run_async(advanced_create_gif(arguments))
            return result[0].text
        except Exception as e:
            return json.dumps({
                "success": False,
                "error": f"创建GIF失败: {str(e)}"
            }, ensure_ascii=False, indent=2)
  • Core implementation of the create_gif tool. Loads multiple images, converts to RGB, resizes frames to match, saves as animated GIF to TEMP_DIR using PIL, returns file reference.
    async def create_gif(arguments: Dict[str, Any]) -> List[TextContent]:
        """
        从多张图片创建GIF动画
        
        Args:
            arguments: 包含图片源列表和GIF参数的字典
            
        Returns:
            List[TextContent]: 处理结果
        """
        try:
            # 参数验证
            image_sources = arguments.get("image_sources", [])
            if len(image_sources) < 2:
                raise ValidationError("至少需要2张图片")
            
            duration = arguments.get("duration", 500)
            loop = arguments.get("loop", 0)  # 默认0表示无限循环
            optimize = arguments.get("optimize", True)
            resize_to = arguments.get("resize_to")
            
            # 验证参数
            validate_numeric_range(duration, 100, 5000, "duration")
            
            processor = ImageProcessor()
            frames = []
            
            # 加载所有图片
            for source in image_sources:
                ensure_valid_image_source(source)
                image = processor.load_image(source)
                
                # 转换为RGB模式(GIF不支持RGBA)
                if image.mode != "RGB":
                    if image.mode == "RGBA":
                        # 创建白色背景
                        background = Image.new("RGB", image.size, (255, 255, 255))
                        background.paste(image, mask=image.split()[-1])
                        image = background
                    else:
                        image = image.convert("RGB")
                
                frames.append(image)
            
            # 调整所有帧到相同尺寸
            if resize_to:
                target_width = resize_to.get("width")
                target_height = resize_to.get("height")
                if target_width and target_height:
                    frames = [frame.resize((target_width, target_height), Image.Resampling.LANCZOS) 
                             for frame in frames]
            else:
                # 使用第一帧的尺寸
                target_size = frames[0].size
                frames = [frame.resize(target_size, Image.Resampling.LANCZOS) for frame in frames]
            
            # 生成唯一文件名并保存到temp目录
            import uuid
            import os
            from config import TEMP_DIR
            
            unique_id = str(uuid.uuid4())[:8]
            gif_filename = f"gif_{unique_id}.gif"
            gif_path = os.path.join(TEMP_DIR, gif_filename)
            
            # 确保temp目录存在
            os.makedirs(TEMP_DIR, exist_ok=True)
            
            # 创建并保存GIF
            frames[0].save(
                gif_path,
                format="GIF",
                save_all=True,
                append_images=frames[1:],
                duration=duration,
                loop=loop,  # 直接使用传入的整数值:0=无限循环,1=播放一次,n=循环n次
                optimize=optimize
            )
            
            # 获取文件大小
            file_size = os.path.getsize(gif_path)
            
            return [TextContent(
                type="text",
                text=json.dumps({
                    "success": True,
                    "message": f"成功创建包含{len(frames)}帧的GIF动画",
                    "data": {
                        "output_type": "file_reference",
                        "file_path": gif_path,
                        "format": "GIF",
                        "file_size": file_size,
                        "operation": "create_gif",
                        "frame_count": len(frames),
                        "size": [frames[0].width, frames[0].height],
                        "duration": duration,
                        "loop": loop,
                        "optimize": optimize
                    }
                }, ensure_ascii=False)
            )]
            
        except ValidationError as e:
            return [TextContent(
                type="text",
                text=json.dumps({
                    "success": False,
                    "error": f"参数验证失败: {str(e)}"
                }, ensure_ascii=False)
            )]
        except Exception as e:
            return [TextContent(
                type="text",
                text=json.dumps({
                    "success": False,
                    "error": f"创建GIF失败: {str(e)}"
                }, ensure_ascii=False)
            )]
  • JSON schema definition for create_gif tool inputs in get_advanced_tools() (note: actual registration uses pydantic in main.py)
    Tool(
        name="create_gif",
        description="从多张图片创建GIF动画",
        inputSchema={
            "type": "object",
            "properties": {
                "image_sources": {
                    "type": "array",
                    "description": "图片源列表(文件路径或base64编码)",
                    "items": {"type": "string"},
                    "minItems": 2,
                    "maxItems": 20
                },
                "duration": {
                    "type": "integer",
                    "description": "每帧持续时间(毫秒)",
                    "minimum": 100,
                    "maximum": 5000,
                    "default": 500
                },
                "loop": {
                    "type": "boolean",
                    "description": "是否循环播放",
                    "default": True
                },
                "optimize": {
                    "type": "boolean",
                    "description": "是否优化文件大小",
                    "default": True
                },
                "resize_to": {
                    "type": "object",
                    "description": "调整所有帧到指定尺寸",
                    "properties": {
                        "width": {"type": "integer", "minimum": 50, "maximum": 800},
                        "height": {"type": "integer", "minimum": 50, "maximum": 800}
                    }
                }
            },
            "required": ["image_sources"]
        }
    )

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/duke0317/ps-mcp'

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