Exporting bitmap from closed curves/hatches


(qythium) #1

Hi all,

The project I’m working on involves using Grasshopper to model vector graphics in pixel units, with the intention of exporting to a non-antialiased, “quantized” bitmap for further use in other software.

Here’s a screenshot of my sample input ( the closed circular curves) and desired output on the right.

My current rather convoluted workflow involves:

  1. Baking the curves
  2. Creating hatches from the curve boundaries
  3. Selecting only the hatches, and exporting as Illustrator .AI files at 1 mm = 1 point scale
  4. Opening the AI file in Illustrator, select all
  5. Using “Asset Export” Tool in Illustrator at 1x scale, 72 ppi, with no antialiasing
  6. Naming the file manually ( Illustrator defaults to calling it “Asset 1.png” no matter the original filename)

These steps have to be done dozens of times a day, in an iterative design process, so I’m wondering if there there any plugins or shortcuts out there to make this more efficient?

I’ve managed to automate steps 1-3 using a Python script (attached below) but it doesn’t always work, and sometimes freezes the GH canvas when run on another computer’s installation (Windows, RH 5).

Note, Rhino’s ViewCaptureToFile doesn’t work for my purposes, because it produces an anti-aliased bitmap scaled to the viewport dimensions instead of the model scale.
hatches_export_sample.gh (9.1 KB)


(Willem Derks) #2


I did a quick test and you might be able to use viewcapturetofile if you diable antialiasing :


results in this:

The code:

import rhinoscriptsyntax as rs

mywidth = 80
myheight = 50

filename = 'testcapture.png'

rs.Command('-ViewCaptureToFile Width={} Height={} TransparentBackground=Yes {}'.format(mywidth,myheight,filename))


(qythium) #3

Thanks for the reply :slight_smile:
There is still the issue that the exported bitmap is scaled to viewport size, not actual dimensions - i.e. I want 80 mm in the drawing to correspond exactly to 80 pixels in the output, and the boundaries to ideally correspond to the bounding box of the geometry, not the viewport window, eliminating the need for further cropping.

Perhaps there is a way of scaling the viewport’s zoom level and aspect ratio to achieve this outcome? I tried using _ViewportProperties, but that does not give direct control over the boundary coordinates.

(Willem Derks) #4


To get the properly scaled output try this, it’s rather hacky but will do the trick:

import rhinoscriptsyntax as rs

def capture_1to1(objs):
    #assuming topview capture
    bbox = rs.BoundingBox(objs)
    width = rs.Distance(bbox[0],bbox[1])
    height = rs.Distance(bbox[0],bbox[3])
    int_width = int(round(width))
    int_height =  int(round(height))
    #command to make sure the zoom extends will zoom without a border
    #running only once even outside the script would suffice but this will ensure the setting is correct
    rs.Command('_SetZoomExtendsBorder ParallelView=1 Enter')
    rs.Command('_NewFloatingViewport Projection Top Enter')
    rs.Command('_-ViewportProperties Size {} {} Enter'.format(int_width,int_height))
    rs.Command('ZoomSelected ')
    filename = 'testcapture.png'
    rs.Command('-ViewCaptureToFile TransparentBackground=Yes {}'.format(filename))
    rs.Command('CloseViewport ')

objs = rs.GetObjects('objects to capture',preselect=True)
if objs: capture_1to1(objs)


(qythium) #5

Aha, the SetZoomExtentsBorder command turned out to be the missing piece! I adapted your code to use RhinoCommon methods so it would be a little less hacky:

import Rhino
import System.Drawing

if button:
    bb = Rhino.Geometry.BoundingBox.Unset
    for crv in crvs:

    solid_hatch_index = 9
    hatches = Rhino.Geometry.Hatch.Create(crvs, solid_hatch_index, rotationRadians=0, scale=1.0)
    for h in hatches:
        Rhino.RhinoDoc.ActiveDoc.Objects.Add(h) # bake the hatches

    RhinoDocument = Rhino.RhinoDoc.ActiveDoc
    view = RhinoDocument.Views.Find("Top", False)
    vp = view.ActiveViewport
    width, height = bb.Diagonal.X, bb.Diagonal.Y
    size = System.Drawing.Size(width, height)

    Rhino.RhinoApp.RunScript("_SetZoomExtentsBorder _ParallelView=1 _Enter", True)

    capture = view.CaptureToBitmap(size)

Thanks for the help!

(Willem Derks) #6

Indeed it’s rather exotic command, great you got it working now!

(qythium) #7

Discovered what seems to be another bug on the Mac version of GH when trying to run the above script -

Using either of the overload methods for CaptureToBitmap that take in (bool, bool, bool) for hiding the grid and axes, results in a NoneType instead of Bitmap being returned. (No exception is thrown by the method itself.)

view = Rhino.RhinoDoc.ActiveDoc.Views.Find("Top", False)
bmp = view.CaptureToBitmap(System.Drawing.Size(480,640)) # works fine, returns Bitmap
bmp = view.CaptureToBitmap(False, True, True) # returns None
bmp.Save(...) # oops, AttributeError

I have to use Python for this, because C# on a Mac can’t work with System.Drawing.Bitmap as reported previously here:

Not sure if related or if it’s a problem with my installation…