Exporting 3D view to image file from stand-alone scripts

Here's the place for discussion related to coding in FreeCAD, C++ or Python. Design, interfaces and structures.
Post Reply
archxyne
Posts: 3
Joined: Wed Oct 26, 2011 2:32 pm

Exporting 3D view to image file from stand-alone scripts

Post by archxyne »

Hi,

As with most open-source projects I'm sure you come across a lot of people who take your work for granted and expect support etc, so I want to start by saying thank you for FreeCAD. It really is appreciated.



I'm new to FreeCAD (installed yesterday) and I'm currently exploring the Python API for creating stand-alone scripts for full automation. So far I've managed to create some basic shapes and export them in various formats (fcstd for loading in FreeCAD, Inventor for rendering with pivy, 2D projections in SVG).

What I would like to do now is export the 3D view to an image file from my script. I want to use the same methods that the GUI does via "Tools->Save picture...", which pops up a dialogue with multiple export formats.

Here's what I have so far (these are pieced-together hacks for testing):

This will create a simple shape and export the aforementioned files:

Code: Select all

#!/usr/bin/env python2

import sys

FREECADPATH = '/usr/lib/freecad/lib'
sys.path.append(FREECADPATH)
import FreeCAD, Part, Drawing

#dv = 0.000000000001

box = Part.makeBox(100,100,100)
box.translate(box.CenterOfMass.multiply(-1))

cylx = Part.makeCylinder(25, 100, FreeCAD.Base.Vector(0,1,0), FreeCAD.Base.Vector(0,90,0))
cylx.translate(cylx.CenterOfMass.multiply(-1))

cyly = Part.makeCylinder(25, 100, FreeCAD.Base.Vector(0,1,0), FreeCAD.Base.Vector(90,0,0))
cyly.translate(cyly.CenterOfMass.multiply(-1))

cylz = Part.makeCylinder(25, 100)
cylz.translate(cylz.CenterOfMass.multiply(-1))

hole = cylx.fuse(cyly).fuse(cylz)

test = box.cut(hole).common(Part.makeSphere(50))

with open('coin.iv', 'w') as f:
  f.write(test.writeInventor())

Part.show(test)

# FreeCAD.ActiveDocument.FileName = 'foo.fcstd'
# FreeCAD.ActiveDocument.save()

Shape = FreeCAD.ActiveDocument.Shape.Shape

visibleG0,visibleG1,hiddenG0,hiddenG1 = Drawing.project(Shape,FreeCAD.Base.Vector(1,1,1))
resultSVG = Drawing.projectToSVG(Shape,FreeCAD.Base.Vector(1,0.2,1))
# if 0 is used instead of dv, the image is rendered incorrectly
#resultSVG = Drawing.projectToSVG(Shape,FreeCAD.Base.Vector(0,dv,1))

with open('foo.svg', 'w') as f:
  f.write('<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-100 -100 200 200">')
  f.write(resultSVG)
  f.write('</svg>')
The previous script generates an inventor file named coin.iv that can be view interactively with

Code: Select all

from pivy.sogui import *
from pivy.coin import *
import sys

def main():
    myWindow = SoGui.init(sys.argv[0])
    if myWindow == None: sys.exit(1)

    input = SoInput()
    input.openFile("coin.iv")

    scene = SoDB.readAll(input)

    viewer = SoGuiExaminerViewer(myWindow)

    viewer.setSceneGraph(scene)
    viewer.setTitle("Scene Viewer")
    #viewer.setBackgroundColor()
    viewer.show()

    SoGui.show(myWindow) # Display main window
    SoGui.mainLoop()     # Main Coin event loop

if __name__ == "__main__":
    main()
Here's what I've tried:
* recording a macro and looking at the generated code (macro uses activeDocument().activeView().saveImage(), but script "gives AttributeError: 'App.Document' object has no attribute 'activeView'")
* pivy SoOffscreenRenderer, but only SGI RGB output is supported (not sure why, can't find any compile options for coin that would disable other formats), and the generated image is empty, probably because I haven't set the scene properly

Obviously I'm new to the API and I'm probably not looking in the right place for the documentation. So far I've just been piecing it together from docs, examples and the ipython shell. I think I can get an image if I keep digging through the SoOffscreenRenderer api, but it doesn't seem to be the same thing that the GUI is using.

All I want to do is be able to set the view and export the generated 3D image as it would be done when saving the image via the GUI (minus the dialogue), i.e. using the "built-in" renderer. I do not want to export to povray.


Additional information:
system: Arch Linux x86_64
freecad version: 0.11.4422-5
pivy-hg: 20100809-4
coin: 3.1.3-5
opencascade: 6.5.1-1



Thanks for any help, and sorry if this has already been covered or if this post is in the wrong place.
User avatar
jriegel
Site Admin
Posts: 3369
Joined: Sun Feb 15, 2009 5:29 pm
Location: Ulm, Germany
Contact:

Re: Exporting 3D view to image file from stand-alone scripts

Post by jriegel »

Image formats are plugins of Qt, so you have to check that you have installed/compiled the appropriated
Qt image plugins...
Stop whining - start coding!
wmayer
Site Admin
Posts: 17764
Joined: Thu Feb 19, 2009 10:32 am

Re: Exporting 3D view to image file from stand-alone scripts

Post by wmayer »

Coin only has built-in support for EPS and RGB format. Other formats like PNG, JPG, ... are provided by the simage plugin. In FreeCAD, however, we follow a different approach. We have a subclass of SoOffscreenRenderer called SoFCOffscreenRenderer. There we have a method to convert the buffer into a QImage. With this QImage we can write out to any format Qt offers.

From python you don't have to care about this. Here you can simply write:

Code: Select all

Gui.ActiveDocument.ActiveView.saveImage("filename")
The saveImage has one mandatory argument and four optional ones.
string : filename
int : width
int : height
string : background (can be 'Current' (default), 'Black', 'White', 'Transparent')
string : comment, will only be written to file types that supports this like JPG
archxyne
Posts: 3
Joined: Wed Oct 26, 2011 2:32 pm

Re: Exporting 3D view to image file from stand-alone scripts

Post by archxyne »

Thank you for the replies.

It took me a while to find "Gui" as I kept getting "name 'Gui' is not defined" errors and there is no module named "Gui" that I can import. The solution was to import "FreeCADGui" then run "FreeCADGui.showMainWindow()", after which 'Gui' is suddenly defined.*

Do I have to load and display the full GUI to export an image? Again, I'm doing this from a stand-alone script with no user interaction and I just want to be able to batch-generate files and images.

I'll install simage now and start exploring that end. Thanks again.


*Incidentally, in stand-alone scripts, it's not very clear that "App" is imported magically when you import "FreeCAD", or that "Gui" is imported when you run "FreeCADGui.showMainWindow()". Perhaps it would be worth mentioning this somewhere on the site.
wmayer
Site Admin
Posts: 17764
Joined: Thu Feb 19, 2009 10:32 am

Re: Exporting 3D view to image file from stand-alone scripts

Post by wmayer »

Gui is a shortcut for FreeCADGui which is defined while importing FreeCADGui. So, in scripts you can also write:

Code: Select all

import FreeCADGui as Gui
so that is more obvious where the definition comes from. It's the same with "App" and "FreeCAD".

To make screenshots without Gui check out the script here:
http://free-cad.svn.sourceforge.net/vie ... iew=markup
archxyne
Posts: 3
Joined: Wed Oct 26, 2011 2:32 pm

Re: Exporting 3D view to image file from stand-alone scripts

Post by archxyne »

wmayer wrote:To make screenshots without Gui check out the script here:
http://free-cad.svn.sourceforge.net/vie ... iew=markup
Perfect, thank you!


As for the imports, "Gui" isn't defined until "showMainWindow()" is run, which was what confused me. Here's an example script with output to show what I mean:

Code: Select all

#!/usr/bin/env python2

import sys
FREECADPATH = '/usr/lib/freecad/lib'
sys.path.append(FREECADPATH)

import FreeCADGui


try:
  print "Attemptint to print Gui"
  print Gui

except NameError as e:
  print e
  FreeCADGui.showMainWindow()
  print "Attempting to print Gui after showMainWindow()"
  print Gui
Output:

Code: Select all

FreeCAD 0.11, Libs: 0.11R4422
Attemptint to print Gui
name 'Gui' is not defined
Main window restored
Show main window
Toolbars restored
Attempting to print Gui after showMainWindow()
<module 'FreeCADGui' from '/usr/lib/freecad/lib/FreeCADGui.so'>
I only mention it in case it's unintentional.
Post Reply