Set the resolution of view capture

Hi!
I am using the code from here to capture the view:

However, the output pictures are very blurry. If I increase the “view_capture.Width” and “view_capture.Height” the image gets more pixels, but also becomes more zoomed out.
Setting “view_capture.ScaleScreenItems = True” does not seem to help.

I believe the “Resolution” property in the “ViewCaptureSettings()” can fix this, but my limited experience with these things stop me from properly implement it. Any pointers on how this is done would be greatly appreciated!

Does it look sharper if you use .CaptureToSvg instead? It’s a long shot but there’s a size attribute on view

Hi @isak.wadso, you’ll need to multiply Width and Height with a value to maintain the aspect ratio of the view. eg. below will capture 4 times the original size:

import System
import Rhino
import scriptcontext as sc

def SampleViewCaptureToFile(multiplier=1):
    if not multiplier: return
    view = sc.doc.Views.ActiveView
    if view:
        view_capture = Rhino.Display.ViewCapture()
        view_capture.Width = view.ActiveViewport.Size.Width * multiplier
        view_capture.Height = view.ActiveViewport.Size.Height * multiplier
        view_capture.ScaleScreenItems = False
        view_capture.DrawAxes = False
        view_capture.DrawGrid = False
        view_capture.DrawGridAxes = False
        bitmap = view_capture.CaptureToBitmap(view)
        if bitmap:
            folder = System.Environment.SpecialFolder.Desktop
            path = System.Environment.GetFolderPath(folder)
            filename = System.IO.Path.Combine(path, "SampleViewCaptureToFile.png")
            bitmap.Save(filename, System.Drawing.Imaging.ImageFormat.Png)

SampleViewCaptureToFile(multiplier=4)

Note that this does not change the view or camera postition.

ScaleScreenItems servers a different purpose. If you have eg. 2d screen items like TextDots, it will Scale them if you size up or down the image. If ScaleScreenItems is False, TextDots remain at their original size.

_
c.

1 Like

Thanks for the replies!

James: For my geometry, with shadows and gradients, I think I will need a pixel-based format. But it would have been a good alternative if it was more distinct lines and such suitable for vector graphic.

Clement: I am not sure if I get how you mean. I added a multiplier, but If I zoom in on the outputs they are just as blurry. The scale value just makes the picture with larger white margins around the object. Maybe there is some other setting that will fit my object to the view?


Also great info about the ScaleScreenItems.

I found here that CaptureToBitmap can take two different inputs: RhinoView or ViewCaptureSettings:
https://developer.rhino3d.com/api/RhinoCommon/html/Overload_Rhino_Display_ViewCapture_CaptureToBitmap.htm
I created a ViewCaptureSettings with the active view, size and resolution, but it seems like CaptureToBitmap prefers a RhinoView:
“Error: Runtime error (ArgumentTypeException): expected RhinoView, got ViewCaptureSettings”
Maybe this one is not implemented with python?

That is very odd, here is what i get using multipliers from 1 to 3 with above script:

SampleViewCaptureToFile(multiplier=1)

SampleViewCaptureToFile(multiplier=2)

SampleViewCaptureToFile(multiplier=3)

It does not change the view here, just creates a higher resolution image. What Version of Rhino are you running ? (I am testing with Rhino 7 SR28)

You can zoom to the Extents by using this:

scriptcontext.doc.Views.ActiveView.ActiveViewport.ZoomExtents()

but this should not be required. The multiplier in above script seems to work though since your captured images get larger in size.

For using the ViewCaptureSettings there is a different way to call the Capture. Below demonstrates it:

import Rhino
import scriptcontext
import System

def CustomViewCapture(multiplier=1.0):
    view = scriptcontext.doc.Views.ActiveView
    width  = int(view.Size.Width * multiplier)
    height = int(view.Size.Height * multiplier)
    size = System.Drawing.Size(width, height)
    settings = Rhino.Display.ViewCaptureSettings(view, size, 72)
    settings.Document = scriptcontext.doc.ActiveDoc
    settings.DrawAxis = False
    settings.DrawGrid = False
    settings.RasterMode = True
    
    bitmap = Rhino.Display.ViewCapture.CaptureToBitmap(settings)
    if bitmap:
        folder = System.Environment.SpecialFolder.Desktop
        path = System.Environment.GetFolderPath(folder)
        filename = System.IO.Path.Combine(path, "CustomViewCapture.png")
        bitmap.Save(filename, System.Drawing.Imaging.ImageFormat.Png)

CustomViewCapture(multiplier=1)

Does this also change your view if you run it with different multipliers ?

_
c.

Hm, both works now if I run them isolated, so there might be something else I am doing with the camera positions, view and such that messes it up.

The second version, with “ViewCaptureSettings” works with the rest of my script though! Thank you :slight_smile:

Hello again!
I have now realized that my scaling problem happens when I set a different aspect ratio than the view. For example if I try to make the output picture half as wide as it is tall, it zooms out like mentioned before:

size = System.Drawing.Size(height/2, height)
settings = rh.Display.ViewCaptureSettings(view, size, 72)

It seems that it includes the whole viewport, and then extend the frame from there to achieve the specified ratio.
Do you know Clement if there is a way to crop the output picture so that the dimensions follow the size of the objects in view? Like a “bounding rectangle”.

Hi @isak.wadso, maybe you could just make a new floating viewport with the desired dimensions, zoom extents the target object(s) and then perform the capture (maintaining the aspect ratio of the floating viewport).

Once captured, you could just close the floating viewport.

_
c.

That was smart!
Now I have managed to create a new floating view, set its proportions, take the pictures and then remove it. One last question (I think): Do you know of a way to find the bounds in X and Y of the objects in view? Having that I could scale the floating view so that it has the same proportions as the objects in view, like a bounding rectangle. Can the Frustum properties be used for this, or something else in ViewportInfo?
Thanks a lot for helping out as I learn my ways around these things!

You can get the bounding box of the object to capture in screen coordinates and then use them to compute the width and height. I’ve tried something:

NewFloatingViewSizedFromObject.py (2.5 KB)

Try it with a Perspective viewport with parallel projection first and make sure the object to capture is fully enclosed in the view. The size of the new floating viewport depends also on the size of the object on screen. If the projection is not parallel, of course the bounding box will cause deviation as the viewport aspect ratio changes from the initial view to the floating one.

I don’t think so, it depends on the initial viewport width and height. What really bothered me is that there is no method for getting the screen based bbox yet for a bunch of objects. It could be generated in parallel and perspective projection using a screen based bbox from a MeshOutline.

_
c.

Thanks for taking the time to put this code together :slight_smile:
As you say it is a bit tricky in the perspective view, but still the proportions become about right.
I have never used screen coordinates, interesting thing to work with.