Merge branch 'screenshot-feature'

This commit is contained in:
ahujasid 2025-06-08 19:34:31 +05:30
commit 6a5959f737
2 changed files with 100 additions and 0 deletions

View File

@ -198,6 +198,7 @@ class BlenderMCPServer:
handlers = { handlers = {
"get_scene_info": self.get_scene_info, "get_scene_info": self.get_scene_info,
"get_object_info": self.get_object_info, "get_object_info": self.get_object_info,
"get_viewport_screenshot": self.get_viewport_screenshot,
"execute_code": self.execute_code, "execute_code": self.execute_code,
"get_polyhaven_status": self.get_polyhaven_status, "get_polyhaven_status": self.get_polyhaven_status,
"get_hyper3d_status": self.get_hyper3d_status, "get_hyper3d_status": self.get_hyper3d_status,
@ -340,6 +341,63 @@ class BlenderMCPServer:
return obj_info return obj_info
def get_viewport_screenshot(self, max_size=800, filepath=None, format="png"):
"""
Capture a screenshot of the current 3D viewport and save it to the specified path.
Parameters:
- max_size: Maximum size in pixels for the largest dimension of the image
- filepath: Path where to save the screenshot file
- format: Image format (png, jpg, etc.)
Returns success/error status
"""
try:
if not filepath:
return {"error": "No filepath provided"}
# Find the active 3D viewport
area = None
for a in bpy.context.screen.areas:
if a.type == 'VIEW_3D':
area = a
break
if not area:
return {"error": "No 3D viewport found"}
# Take screenshot with proper context override
with bpy.context.temp_override(area=area):
bpy.ops.screen.screenshot_area(filepath=filepath)
# Load and resize if needed
img = bpy.data.images.load(filepath)
width, height = img.size
if max(width, height) > max_size:
scale = max_size / max(width, height)
new_width = int(width * scale)
new_height = int(height * scale)
img.scale(new_width, new_height)
# Set format and save
img.file_format = format.upper()
img.save()
width, height = new_width, new_height
# Cleanup Blender image data
bpy.data.images.remove(img)
return {
"success": True,
"width": width,
"height": height,
"filepath": filepath
}
except Exception as e:
return {"error": str(e)}
def execute_code(self, code): def execute_code(self, code):
"""Execute arbitrary Blender Python code""" """Execute arbitrary Blender Python code"""
# This is powerful but potentially dangerous - use with caution # This is powerful but potentially dangerous - use with caution

View File

@ -4,6 +4,7 @@ import socket
import json import json
import asyncio import asyncio
import logging import logging
import tempfile
from dataclasses import dataclass from dataclasses import dataclass
from contextlib import asynccontextmanager from contextlib import asynccontextmanager
from typing import AsyncIterator, Dict, Any, List from typing import AsyncIterator, Dict, Any, List
@ -266,6 +267,47 @@ def get_object_info(ctx: Context, object_name: str) -> str:
logger.error(f"Error getting object info from Blender: {str(e)}") logger.error(f"Error getting object info from Blender: {str(e)}")
return f"Error getting object info: {str(e)}" return f"Error getting object info: {str(e)}"
@mcp.tool()
def get_viewport_screenshot(ctx: Context, max_size: int = 800) -> Image:
"""
Capture a screenshot of the current Blender 3D viewport.
Parameters:
- max_size: Maximum size in pixels for the largest dimension (default: 800)
Returns the screenshot as an Image.
"""
try:
blender = get_blender_connection()
# Create temp file path
temp_dir = tempfile.gettempdir()
temp_path = os.path.join(temp_dir, f"blender_screenshot_{os.getpid()}.png")
result = blender.send_command("get_viewport_screenshot", {
"max_size": max_size,
"filepath": temp_path,
"format": "png"
})
if "error" in result:
raise Exception(result["error"])
if not os.path.exists(temp_path):
raise Exception("Screenshot file was not created")
# Read the file
with open(temp_path, 'rb') as f:
image_bytes = f.read()
# Delete the temp file
os.remove(temp_path)
return Image(data=image_bytes, format="png")
except Exception as e:
logger.error(f"Error capturing screenshot: {str(e)}")
raise Exception(f"Screenshot failed: {str(e)}")
@mcp.tool() @mcp.tool()