Screenshot Manager
Relevant source files
Purpose and Scope
Section titled “Purpose and Scope”The Screenshot Manager provides high-quality image capture functionality for Upload Labs game boards. It handles capturing full desktop screenshots or selection-only screenshots using a tiled rendering approach that can handle arbitrarily large boards. This component manages quality settings, watermarking, folder configuration, and integrates with the Settings UI.
For information about other utility managers, see Other Utility Managers. For the main orchestrator that initializes this manager, see The Main Orchestrator.
System Overview
Section titled “System Overview”The Screenshot Manager is implemented as ScreenshotManager, a RefCounted utility class that operates independently of the scene tree. It captures images by temporarily manipulating the main camera and viewport, rendering the scene in tiles, and stitching them together into a final high-resolution image.
Key Capabilities:
- Full desktop capture: Captures all windows on the desktop with automatic bounds calculation
- Selection capture: Captures only currently selected nodes with padding
- Tiled rendering: Handles boards larger than viewport size by capturing in tiles
- Quality presets: Four quality levels balancing file size and image quality
- Watermarking: Optional branding overlay with automatic scaling and positioning
- Configurable output: User-selectable screenshot folder and filename generation
Sources: extensions/scripts/utilities/screenshot_manager.gd L1-L20
Class Architecture
Section titled “Class Architecture”classDiagram
class ScreenshotManager {
+int quality
+bool watermark_enabled
+String screenshot_folder
-SceneTree _tree
-SettingsUI _ui
-ConfigManager _config
-Callable _log_callback
+set_tree(tree)
+set_ui(ui_ref)
+set_config(config_manager)
+set_log_callback(callback)
+take_screenshot()
+take_screenshot_selection()
+add_screenshot_section(parent, ui_builder, config_manager)
+open_screenshot_folder()
-_compute_selection_bounds() : Rect2
-_show_folder_dialog(path_label, config_manager)
-_get_display_path() : String
-_log(message, force)
}
class ModMain {
+ScreenshotManager screenshot_manager
}
class ConfigManager {
+get_value(key, default)
+set_value(key, value)
}
class SettingsUI {
+is_visible() : bool
+set_visible(visible)
}
class Globals {
+Node desktop
+Array selections
}
class Signals {
+Signal notify
}
ModMain --> ScreenshotManager : initializes
ScreenshotManager --> ConfigManager : persists settings
ScreenshotManager --> SettingsUI : hides during capture
ScreenshotManager --> Globals : reads desktop and selections
ScreenshotManager --> Signals : emits notifications
Sources: extensions/scripts/utilities/screenshot_manager.gd L6-L54
Quality Settings and Capture Modes
Section titled “Quality Settings and Capture Modes”The Screenshot Manager supports four quality presets that determine the capture zoom level and output format. These settings balance image quality, file size, and capture time.
Quality Presets
Section titled “Quality Presets”| Quality Level | Zoom Factor | Format | Compression | Use Case |
|---|---|---|---|---|
| Low (0) | 0.5x | JPG | 80% | Quick sharing, small file size |
| Medium (1) | 0.6x | JPG | 90% | Balanced quality/size |
| High (2) | 0.8x | PNG | Lossless | High detail, reasonable size |
| Original (3) | 1.5x | PNG | Lossless | Maximum quality, large files |
The zoom factor determines how much detail is captured. A 1.5x zoom means the final image is 1.5 times larger than the world-space dimensions of the board.
Sources: extensions/scripts/utilities/screenshot_manager.gd L14-L16
extensions/scripts/utilities/screenshot_manager.gd L91-L94
Capture Modes
Section titled “Capture Modes”The system provides two capture modes:
- Full Desktop Capture (
take_screenshot()): Captures all windows on the desktop by calculating a bounding rectangle around all children ofGlobals.desktop.Windows. - Selection Capture (
take_screenshot_selection()): Captures only nodes inGlobals.selectionswith 64px world-space padding for better framing.
Both modes use the same tiled rendering pipeline but differ in bounds calculation.
Sources: extensions/scripts/utilities/screenshot_manager.gd L56-L89
extensions/scripts/utilities/screenshot_manager.gd L344-L362
Tiled Capture Workflow
Section titled “Tiled Capture Workflow”For large boards, a single viewport capture would be insufficient. The Screenshot Manager uses a tiled approach to capture arbitrarily large areas.
sequenceDiagram
participant User
participant ScreenshotManager
participant Viewport
participant Camera2D
participant RenderingServer
participant FileSystem
User->>ScreenshotManager: "take_screenshot()"
ScreenshotManager->>ScreenshotManager: "Calculate bounds from windows"
ScreenshotManager->>ScreenshotManager: "Determine tile count (tiles_x, tiles_y)"
ScreenshotManager->>Viewport: "set_disable_input(true)"
note over Viewport: Block all input during capture
ScreenshotManager->>Camera2D: "set_block_signals(true)"
ScreenshotManager->>Camera2D: "Disable all processing methods"
note over Camera2D: Prevent scroll wheel interference
ScreenshotManager->>ScreenshotManager: "Hide HUD and Settings UI"
ScreenshotManager->>ScreenshotManager: "Save camera position/zoom state"
ScreenshotManager->>ScreenshotManager: "Create empty Image(final_width, final_height)"
loop [For each tile (ty, tx)]
ScreenshotManager->>Camera2D: "position = tile_center"
ScreenshotManager->>Camera2D: "zoom = Vector2(capture_zoom, capture_zoom)"
ScreenshotManager->>ScreenshotManager: "await tree.process_frame × CAPTURE_DELAY"
note over ScreenshotManager: Wait 5+ frames for rendering
ScreenshotManager->>RenderingServer: "force_sync()"
ScreenshotManager->>ScreenshotManager: "await tree.process_frame"
ScreenshotManager->>Viewport: "get_texture().get_image()"
Viewport-->>ScreenshotManager: "tile_image"
ScreenshotManager->>ScreenshotManager: "final_image.blit_rect(tile_image, ...)"
end
ScreenshotManager->>ScreenshotManager: "Crop to actual bounds"
ScreenshotManager->>ScreenshotManager: "Apply watermark if enabled"
ScreenshotManager->>Camera2D: "Restore position/zoom/signals"
ScreenshotManager->>Viewport: "set_disable_input(false)"
ScreenshotManager->>ScreenshotManager: "Restore HUD visibility"
ScreenshotManager->>FileSystem: "save_png() or save_jpg()"
ScreenshotManager->>User: "Notify: Screenshot saved!"
Sources: extensions/scripts/utilities/screenshot_manager.gd L194-L236
Key Steps in Detail
Section titled “Key Steps in Detail”1. Input Blocking (Lines 96-150)
To prevent user input from interfering with capture, the system:
- Disables input at viewport level via
viewport.set_disable_input(true) - Blocks camera signals with
main_camera.set_block_signals(true) - Disables all camera processing methods (process, physics_process, input, etc.)
- Sets the dragger’s mouse filter to
MOUSE_FILTER_IGNORE - Disables camera zooming animation state
Sources: extensions/scripts/utilities/screenshot_manager.gd L96-L150
2. Tile Calculation (Lines 161-188)
tile_world_size = viewport_size / capture_zoomtiles_x = ceil(bounds.size.x / tile_world_size.x)tiles_y = ceil(bounds.size.y / tile_world_size.y)final_width = tiles_x × viewport_size.xfinal_height = tiles_y × viewport_size.yThe system adds 15% padding to bounds to ensure edges are captured. If the final image would exceed 16384 pixels in either dimension, the capture zoom is automatically reduced.
Sources: extensions/scripts/utilities/screenshot_manager.gd L161-L188
3. Per-Tile Capture (Lines 194-236)
For each tile:
- Calculate tile center position in world coordinates
- Move camera to tile center and set zoom
- Wait
CAPTURE_DELAY(5) frames, plus 5 extra frames for the first tile (visibility culling initialization) - Force rendering sync with
RenderingServer.force_sync() - Wait one more frame
- Capture viewport image with
viewport.get_texture().get_image() - Blit tile into final image at calculated position
The camera position is locked multiple times during the wait to prevent any drift.
Sources: extensions/scripts/utilities/screenshot_manager.gd L194-L236
4. State Restoration (Lines 289-322)
All modified state is restored:
- Viewport input re-enabled
- Camera signals unblocked
- Camera processing methods re-enabled
- Camera position/zoom restored
- HUD and Settings UI visibility restored
- Background grid visibility restored
Sources: extensions/scripts/utilities/screenshot_manager.gd L289-L322
Watermarking System
Section titled “Watermarking System”When watermark_enabled is true, the system applies a branded watermark to the bottom-right corner of captured images.
flowchart TD A["Load TajsModHeader.png"] B["Convert to RGBA8"] C["Calculate target width<br>(15% of image width)"] D["Scale with INTERPOLATE_LANCZOS"] E["Apply 50% opacity<br>to all pixels"] F["Calculate position<br>(bottom-right + 2% padding)"] G["Blend onto final_image<br>(respects alpha)"] A --> B B --> C C --> D D --> E E --> F F --> G
The watermark automatically scales based on output image size, with a minimum size of 100px to ensure visibility. The 50% opacity allows the watermark to be visible without obscuring important content.
Implementation:
- Watermark source:
res://mods-unpacked/TajemnikTV-TajsModded/TajsModHeader.png - Scaling: 15% of final image width
- Minimum size: 100px wide
- Opacity: 50% (alpha multiplied by 0.5)
- Position: Bottom-right corner with 2% padding
- Blend mode: Alpha blending via
final_image.blend_rect()
Sources: extensions/scripts/utilities/screenshot_manager.gd L251-L288
Configuration and Persistence
Section titled “Configuration and Persistence”The Screenshot Manager integrates with the configuration system to persist user preferences across sessions.
Configuration Keys
Section titled “Configuration Keys”| Key | Type | Default | Description |
|---|---|---|---|
screenshot_quality | int | 2 (High) | Quality preset index (0-3) |
screenshot_watermark | bool | true | Enable watermark overlay |
screenshot_folder | String | "user://screenshots" | Output directory path |
Sources: extensions/scripts/utilities/screenshot_manager.gd L14-L20
Initialization Flow
Section titled “Initialization Flow”flowchart TD
A["mod_main._ready()"]
B["screenshot_manager = ScreenshotManager.new()"]
C["screenshot_manager.set_tree(get_tree())"]
D["screenshot_manager.set_config(config_manager)"]
E["Load quality from config:<br>config.get_value('screenshot_quality', 2)"]
F["Load watermark from config:<br>config.get_value('screenshot_watermark', true)"]
G["Load folder from config:<br>config.get_value('screenshot_folder', 'user://screenshots')"]
A --> B
B --> C
C --> D
D --> E
E --> F
F --> G
Sources: Referenced from mod_main initialization pattern
Settings UI Integration
Section titled “Settings UI Integration”The add_screenshot_section() method builds a UI control panel that includes:
- Quality Selector: Four toggle buttons for quality presets (Low/Medium/High/Original)
- Watermark Toggle: CheckButton to enable/disable watermarking
- Take Screenshot Button: Triggers
take_screenshot()on press - Folder Management: * Display of current folder path (globalized from
user://if applicable) * “Open Folder” button: Launches system file explorer * “Change Folder” button: ShowsFileDialogfor path selection
Each UI element connects to the configuration system, calling config_manager.set_value() when changed to immediately persist the setting.
Sources: extensions/scripts/utilities/screenshot_manager.gd L592-L705
Output and File Management
Section titled “Output and File Management”Filename Generation
Section titled “Filename Generation”Screenshot filenames follow a structured format to ensure uniqueness and include relevant metadata:
Full Desktop Screenshots:
fullboard_{quality}_{timestamp}.{extension}Example: fullboard_high_2024-12-15 14-30-45.pngSelection Screenshots:
selection_{node_count}nodes_{quality}_{timestamp}.{extension}Example: selection_12nodes_med_2024-12-15 14-31-22.jpgTimestamps are generated using Time.get_datetime_string_from_system() with colons replaced by hyphens for filesystem compatibility.
Sources: extensions/scripts/utilities/screenshot_manager.gd L325-L328
extensions/scripts/utilities/screenshot_manager.gd L560-L564
Folder Management
Section titled “Folder Management”The default screenshot folder is user://screenshots, which resolves to the Godot user data directory. Users can change this to any filesystem location.
Folder Operations:
- Open Folder (
open_screenshot_folder()): * Creates directory if it doesn’t exist * Globalizesuser://paths usingProjectSettings.globalize_path()* Opens in system file explorer viaOS.shell_open() - Change Folder (
_show_folder_dialog()): * Creates aFileDialogwithFILE_MODE_OPEN_DIR* Sets access mode toACCESS_FILESYSTEMfor full filesystem access * Updates configuration on folder selection * Updates UI path display
Sources: extensions/scripts/utilities/screenshot_manager.gd L714-L760
Integration with Core Systems
Section titled “Integration with Core Systems”flowchart TD MM["mod_main.gd"] SM["ScreenshotManager"] G1["Globals.desktop"] G2["Globals.selections"] S1["Signals.notify"] CM["ConfigManager"] CF["user://tajs_mod_config.json"] SU["SettingsUI"] HUD["Main/HUD"] CAM["Main/Main2D/Camera2D"] VP["Viewport"] RS["RenderingServer"] FS["Screenshot Folder"] User["User"] CMD["take-screenshot command"] MM --> SM SM --> G1 SM --> G2 SM --> S1 SM --> CM CM --> CF SM --> SU SM --> HUD SM --> CAM SM --> VP SM --> RS SM --> FS User --> MM User --> SM User --> CMD CMD --> MM MM --> SM
Integration Points:
- Initialization:
mod_main.gdcreates the ScreenshotManager instance during_ready()and passes references to SceneTree, ConfigManager, and SettingsUI. - Invocation: Screenshots can be triggered through: * Keyboard shortcut (Ctrl+P) handled in mod_main input processing * Settings UI “Take Screenshot” button * Command Palette
take-screenshotortake-screenshot-selectioncommands - State Management: The manager reads from
Globals.desktopfor window enumeration andGlobals.selectionsfor selection-based captures. - User Feedback: All operations emit notifications via
Signals.notifywith appropriate icons (“check” for success, “exclamation” for errors). - Configuration: Settings are immediately persisted through ConfigManager, which writes to
user://tajs_mod_config.json.
Sources: Integration pattern inferred from component architecture
Error Handling and Edge Cases
Section titled “Error Handling and Edge Cases”The Screenshot Manager includes defensive checks for various failure scenarios:
Error Conditions
Section titled “Error Conditions”| Condition | Check | User Feedback |
|---|---|---|
| Desktop not found | Globals.desktop validity | ”Could not capture - desktop not found” |
| No windows | Windows container empty | ”Could not capture - no windows” |
| No selection | Globals.selections.is_empty() | ”No nodes selected” |
| Camera not found | Camera2D node lookup | ”Camera not found” |
| Watermark load failure | Texture load result | ”WARNING: Could not load watermark image” |
| Folder open failure | OS.shell_open() return code | ”Could not open folder” |
Sources: extensions/scripts/utilities/screenshot_manager.gd L60-L89
extensions/scripts/utilities/screenshot_manager.gd L347-L356
Size Limiting
Section titled “Size Limiting”To prevent excessive memory usage or crashes, images exceeding 16384 pixels in either dimension have their zoom automatically reduced:
if final_width > max_dimension or final_height > max_dimension: var scale_down = min(float(max_dimension) / final_width, float(max_dimension) / final_height) capture_zoom = capture_zoom * scale_downThis ensures even extremely large boards can be captured, albeit at reduced zoom.
Sources: extensions/scripts/utilities/screenshot_manager.gd L176-L188
Performance Characteristics
Section titled “Performance Characteristics”Capture Timing
Section titled “Capture Timing”The tiled capture process is synchronous (blocks the game loop) to maintain state consistency. Approximate timing:
- Per-tile overhead: 5-10 frames (CAPTURE_DELAY + sync)
- First tile: Additional 5 frames for visibility culling initialization
- Example: 3×2 tile grid = 6 tiles × 8 frames avg = ~48 frames = ~0.8 seconds at 60 FPS
Memory Usage
Section titled “Memory Usage”Each tile consumes viewport size × 4 bytes (RGBA8). For a 1920×1080 viewport:
- Per-tile memory: ~8.3 MB
- Maximum allocation: One tile + final image in memory simultaneously
- Final image size varies by quality and board size
File Size Examples
Section titled “File Size Examples”Approximate sizes for a 10,000×10,000 pixel board area:
| Quality | Resolution | Format | Approx. Size |
|---|---|---|---|
| Low | 5,000×5,000 | JPG 80% | 2-4 MB |
| Medium | 6,000×6,000 | JPG 90% | 4-7 MB |
| High | 8,000×8,000 | PNG | 15-25 MB |
| Original | 15,000×15,000 | PNG | 80-120 MB |
Actual sizes depend on board complexity (wire density, colors, etc.).
Sources: Performance characteristics derived from implementation analysis