Created
July 16, 2020 11:21
-
-
Save yorikvanhavre/85bbfec3bcf47fba10e81724aadaeb58 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
""" | |
This script renders different kinds of CAD files as PNG files using | |
FreeCAD. If the given PNG image path already exists, and was created | |
from the same file (same MD5 hash), no new rendering is performed. | |
Usage: cad2png.py [OPTIONS] path/to/someFile.FCStd path/to/somefile.png | |
Options: | |
-w, --width : the width of the png image, default 800 | |
-h, --height : the height of the png image, default 600 | |
-b, --background : the background color in hex format, default #FFFFFF | |
-n, --nocache : discard caching and force-recompute image | |
Example: | |
cad2png.py -w 800 -h 600 /path/to/file.FCStd /path/to/image.png | |
Supported file types: | |
- FreeCAD files (*.FCStd) | |
- STEP files (*.stp, *.step) | |
- IGES files (*.igs, *.iges) | |
- OpenCasCade's BREP files (*.brp, *.brep) | |
- Any other filetype supported by FreeCAD (obj, stl, ifc, etc...) is | |
supported as well, but they are mesh formats, and there might be much | |
faster viewers for them | |
Instructions: | |
- make sure you have the latest version of FreeCAD installed | |
- make sure you have the pivy (python bindongs for coin3D) package | |
installed | |
- make sure FreeCAD is importable from python (use the commented line | |
below if needed). Another way, more system-independent, is to symlink | |
your FreeCAD.so file to .local/lib/Python3.7/site-packages (user-wide) | |
or /usr/lib/python3.7/dis-packages (system-wide) (using your version | |
of python3 instead of 3.7 in the links above if applicable) | |
- on linux, the X server must have indirect rendering enabled in order | |
to be able to do offline PNG rendering. Unfortunatley, this is turned | |
off by default on most recent distros. The easiest way I found is to | |
edit (or create if inexistant) /etc/X11/xorg.conf and add this: | |
Section "ServerFlags" | |
Option "AllowIndirectGLX" "on" | |
Option "IndirectGLX" "on" | |
EndSection | |
(if your xorg.conf already has a "ServerFlags" section, just add the | |
two options in it). There might be other ways for other distros | |
though, google for "enable indirect glx" with your distro name and | |
version | |
""" | |
# builtin Python modules | |
import os # builtin python lib | |
import sys # builtin python lib | |
import getopt # command-line options parser | |
import hashlib # builtin python lib | |
from PIL.PngImagePlugin import PngImageFile, PngInfo # PNG metadata io | |
# FreeCAD modules | |
# uncomment and adapt next line if needed - path to your FreeCAD.so (or FreeCAD.pyd on windows) | |
# sys.path.append("/path/to/FreeCAD.so") | |
import FreeCAD # main freecad lib, to be imported before any other FreeCAD component | |
import OfflineRenderingUtils # the offline rendering utilities module | |
def convert(freecadfile,outputpath,width=800,height=600,background="#FFFFFF",usecache=True): | |
# first check if the image already exists and was made with the exact same file | |
with open(freecadfile, "rb") as f: | |
file_hash = hashlib.md5() | |
while chunk := f.read(8192): | |
file_hash.update(chunk) | |
filehash = str(file_hash.hexdigest()) | |
if usecache and os.path.exists(outputpath): | |
target = PngImageFile(outputpath) | |
if hasattr(target,"text") and ("fchash" in target.text): | |
if target.text["fchash"] == filehash: | |
print(outputpath,"is up to date") | |
return | |
# convert background string to tuple | |
background = tuple(int(background[i:i + 2], 16) / 255. for i in (1, 3, 5)) | |
# open FreeCAD file (this works with any filetype supported by FreeCAD | |
FreeCAD.loadFile(freecadfile) | |
doc = FreeCAD.ActiveDocument | |
if freecadfile.lower().endswith(".fcstd"): | |
# build color dict | |
colors = OfflineRenderingUtils.getColors(freecadfile) | |
# get the camera data from the file (used in some functions below) | |
camera = OfflineRenderingUtils.getCamera(freecadfile) | |
else: | |
colors = {} | |
camera = None | |
# build coin scene | |
scene = OfflineRenderingUtils.buildScene(doc.Objects,colors) | |
# export to PNG | |
OfflineRenderingUtils.render(outputpath, | |
scene, | |
camera, | |
width=width, | |
height=height, | |
background=background) | |
# write hash info as metadata | |
target = PngImageFile(outputpath) | |
metadata = PngInfo() | |
metadata.add_text("fchash",filehash) | |
target.save(outputpath, pnginfo=metadata) | |
if __name__ == "__main__": | |
opts, args = getopt.getopt(sys.argv[1:], "h:w:b:n", ["height=", "width=","background=","nocache"]) | |
if len(args) == 2: | |
infile = args[0] | |
outfile = args[1] | |
width = 800 | |
height = 600 | |
background = "#FFFFFF" | |
usecache = True | |
for opt in opts: | |
if opt[0] in ("-h","--height"): | |
height = int(opt[1]) | |
elif opt[0] in ("-w","--width"): | |
width = int(opt[1]) | |
elif opt[0] in ("-b","--background"): | |
background = opt[1] | |
elif opt[0] in ("-n","--nocache"): | |
usecache = False | |
convert(infile, outfile, width, height, background, usecache) | |
else: | |
print(__doc__) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment