Automate FreeCAD Rendering Using Headless Python

Automating FreeCAD rendering tasks using a headless Python script enables developers to generate 3D model previews, technical drawings, and ray-traced images without opening the graphical user interface. This article explains how to configure a headless environment using a virtual framebuffer, access the FreeCAD Python API, and execute batch rendering tasks directly from the command line for automated workflows and continuous integration pipelines.

Prerequisites and Environment Setup

Rendering in FreeCAD typically relies on Coin3D or specialized rendering backends (such as POV-Ray or LuxCoreRender via the Render Workbench) which require an active graphics display context. When running on a server or container without a physical monitor, you must provide a virtual display using Xvfb (X Virtual Framebuffer).

On a Debian/Ubuntu-based system, install FreeCAD and Xvfb:

sudo apt-get update
sudo apt-get install -y freecad xvfb

Ensure your Python path includes FreeCAD's library modules if running from a system Python interpreter rather than the built-in FreeCADCmd interpreter:

import sys
sys.path.append("/usr/lib/freecad/lib")

Creating the Headless Rendering Script

FreeCAD provides FreeCADGui and the Coin3D library for off-screen rendering. The following script loads a CAD file, configures the camera view, and renders the scene to an image file using SoOffscreenRenderer.

Save this script as headless_render.py:

import sys
import FreeCAD
import FreeCADGui
from pivy import coin

def render_model(fcstd_path, output_image_path, width=1920, height=1080):
    # Initialize the GUI framework in headless mode
    FreeCADGui.showMainWindow()

    # Open the target FreeCAD document
    doc = FreeCAD.open(fcstd_path)
    gui_doc = FreeCADGui.getDocument(doc.Name)

    # Access the active 3D view
    view = gui_doc.ActiveView
    view.viewIsometric()
    view.fitAll()

    # Retrieve the Coin3D scene graph from the view
    sg = view.getSceneGraph()

    # Configure the off-screen renderer
    renderer = coin.SoOffscreenRenderer(coin.SbViewportRegion(width, height))
    renderer.setBackgroundColor(coin.SbColor(1.0, 1.0, 1.0)) # White background

    # Render the scene graph
    if renderer.render(sg):
        renderer.writeToRGBFile(output_image_path)
        print(f"Render successfully saved to {output_image_path}")
    else:
        print("Rendering failed", file=sys.stderr)

    # Cleanup
    FreeCAD.closeDocument(doc.Name)

if __name__ == "__main__":
    if len(sys.argv) < 3:
        print("Usage: FreeCADCmd headless_render.py <input.FCStd> <output.png>")
        sys.exit(1)

    input_file = sys.argv[1]
    output_file = sys.argv[2]
    render_model(input_file, output_file)

Alternative: Native View Image Export

If you prefer using FreeCAD's built-in view export methods instead of low-level Coin3D bindings, you can replace the off-screen renderer calls with the saveImage method:

# Set background color to white
view.setBackgroundColor(1.0, 1.0, 1.0)

# Save the current view directly
view.saveImage(output_image_path, width, height, "White")

Executing the Script Headlessly

To execute the rendering pipeline without a physical X-server, wrap the command with xvfb-run:

xvfb-run -a FreeCADCmd headless_render.py input_model.FCStd output_render.png

Key arguments explained:

  • xvfb-run -a: Automatically finds a free server number for the virtual display.
  • FreeCADCmd: Launches FreeCAD's command-line interpreter with all internal modules pre-linked.

Automating Batch Rendering

To process multiple files programmatically, accept a directory path in your Python script and iterate over all CAD files:

import glob
import os

def batch_render(input_dir, output_dir):
    files = glob.glob(os.path.join(input_dir, "*.FCStd"))
    for file_path in files:
        base_name = os.path.basename(file_path).replace(".FCStd", ".png")
        out_path = os.path.join(output_dir, base_name)
        render_model(file_path, out_path)

This workflow enables automated thumbnail generation, automated visual regression testing, and scheduled export routines in continuous delivery environments.