Capturing detail viewport on a layout page

Hi Python Gurus,

I’m writing a python script for capturing an image of a detail view on the layout page. So far this proves to be a challenge to identify the viewport and its correct location on the layout page to do the print-screen. I have gotten the method to work for specifying that I click the top left and bottom right corner of the detail view to determine the location and size of the capturing. However, this method can be quite tedious, and I want to simplify it even more where I can just select a detail view and capture it with its correct viewport size (ratio).

Also, the resolution of the image is limited by the DPI of the screen for doing a print-screen like capture. Would it be possible for Rhino to do a viewport print-screen with a specify resolution ignoring the DPI of the screen?

I’m writing a Python script to capture an image of a detail view on a layout page in Rhino. I currently have a method that works by manually clicking the top-left and bottom-right corners of the detail view to determine the capture area. However this process is quite tedious, so I want to simplify it by clicking to select a detail view and capturing it at its correct viewport size (aspect ratio).

Also, the resolution of the captured image is currently limited by the screen’s DPI (72) since it’s doing a print-screen capture. Is there a way in Rhino to capture a viewport image at a specified resolution (ignoring the screen DPI)?

Please see my sample script. Any advice? Thanks in Advance.

import Rhino
import scriptcontext as sc
import rhinoscriptsyntax as rs
import System.Drawing as sd

def capture_selected_detail():
    # Select a detail view object
    detail_id = rs.GetObject("Select a detail viewport", rs.filter.detail)
    if not detail_id:
        print("No detail selected.")
        return

    selected_obj = sc.doc.Objects.Find(detail_id)
    if not isinstance(selected_obj, Rhino.DocObjects.DetailViewObject):
        print("Not a valid detail view.")
        return

    # Find the layout view that owns this detail
    layout_view = None
    matched_detail = None
    for view in sc.doc.Views:
        if isinstance(view, Rhino.Display.RhinoPageView):
            for detail in view.GetDetailViews():
                if detail.Id == selected_obj.Id:
                    layout_view = view
                    matched_detail = detail
                    break
        if layout_view:
            break

    if not layout_view or not matched_detail:
        print("Could not find parent layout for detail.")
        return

    # Use the detail geometry's bounding box
    bbox = matched_detail.Geometry.GetBoundingBox(True)
    if not bbox.IsValid:
        print("Invalid bounding box.")
        return

    # Transform bounding box to page coordinates
    xform = matched_detail.WorldToPageTransform
    pt1 = xform * bbox.Min
    pt2 = xform * bbox.Max

    # Debug: Print transformed points
    print("Transformed points: pt1 = " + str(pt1) + ", pt2 = " + str(pt2))

    # Create crop rectangle
    x = int(min(pt1.X, pt2.X))
    y = int(min(pt1.Y, pt2.Y))
    width = int(abs(pt2.X - pt1.X))
    height = int(abs(pt2.Y - pt1.Y))
    crop_rect = sd.Rectangle(x, y, width, height)

    # Debug: Print crop rectangle
    print("Crop rectangle: " + str(crop_rect))

    # A3 size at 300 DPI
    dpi = 300
    media_width = int(420.0 * dpi / 25.4)
    media_height = int(297.0 * dpi / 25.4)

    # Simplified capture settings for the layout
    settings = Rhino.Display.ViewCaptureSettings(layout_view, dpi)
    settings.SetLayout(sd.Size(media_width, media_height), crop_rect)

    # Save the image
    filename = rs.SaveFileName("Save captured detail", "PNG Files (*.png)|*.png||")
    if not filename:
        print("No file selected.")
        return

    print("Attempting to capture the image...")
    
    try:
        # Perform the capture
        bitmap = Rhino.Display.ViewCapture.CaptureToBitmap(settings)
        
        if bitmap:
            print("Capture successful!")
            # Save the captured bitmap
            bitmap.Save(filename, sd.Imaging.ImageFormat.Png)
            print("Saved image to: " + filename)
        else:
            print("Failed to capture image - bitmap is None.")
    except Exception as e:
        print("Error during image capture: " + str(e))

# Run the script
capture_selected_detail()