Recording Snapshot animation through Gh (well, tried to...)

I tried to animate snapshots from within Gh, but apparently Grasshopper solver is suspended during the snapshot animation.

Proved here:


This file contains two snapshots.
Screencapture.3dm (328.8 KB)

This script contains a python component that contains 2 methods for screen recording.

  1. through Rhino.Display.ViewCapture() which turned out to be too slow (commented out)
  2. through System.Drawing

But apparently my struggles are in vain… As no computation happen during the animation sequence.

File:
Screencapture.gh (8.4 KB)

code:

################################################################################
# SampleViewCaptureToFile.py
# Copyright (c) 2018 Robert McNeel & Associates.

#2023-11-22 Gh version by Toni Österlund, inspired by Ryan Hughes
#using simple counter by AndersDeleuran
################################################################################
"""Provides a scripting component.
    Inputs:
        Path: Folder path for saving the image sequence
        Filename: File prefix. 'Frame' if left empty
        Transparent: Boolean to define if the backgroud is transparent
        Scale: Define the resolution as multiplication of the viewport resolution size
        Capture: Boolean to start the script
    Output:
        Log: Log of the image saving process"""
        
import System
import Rhino
import Grasshopper as gh
import scriptcontext as sc
import time
import System.Windows.Forms.Screen 
import System.Drawing.Bitmap
import System.Drawing.Graphics

# Capture a view to a bitmap
def ViewCaptureToFile(_path, _frame, _filename, _transparentBG, _scale):
    view = sc.doc.Views.ActiveView
    if _filename==None:_filename='Frame'
    if _transparentBG==None:_transparentBG=False
    if _scale==None:_scale=1.0
            
    if view:
        view_capture = Rhino.Display.ViewCapture()
        view_capture.Width = view.ActiveViewport.Size.Width*_scale
        view_capture.Height = view.ActiveViewport.Size.Height*_scale
        view_capture.ScaleScreenItems = False
        view_capture.DrawAxes = False
        view_capture.DrawGrid = False
        view_capture.DrawGridAxes = False
        view_capture.TransparentBackground = _transparentBG
        bitmap = view_capture.CaptureToBitmap(view)
        if bitmap:
            filename = System.IO.Path.Combine(_path, _filename +'_' + _frame + '.png')
            bitmap.Save(filename, System.Drawing.Imaging.ImageFormat.Png)
            
def ViewScreenCapToFile(_path, _frame, _filename):
    if _filename==None:_filename='Frame'
    view = sc.doc.Views.ActiveView #Active view
    rect = view.ClientRectangle #Viewport rectangle
    
    #Viewport left top corner point
    pt = Rhino.Geometry.Point2d(rect.Left, rect.Top)
    pt = view.ActiveViewport.ClientToScreen(pt)
    
    bitmap = System.Drawing.Bitmap(rect.Width, rect.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
    #Create a graphics object from the bitmap
    gfxScreenshot = System.Drawing.Graphics.FromImage(bitmap);
    
    #Take the screenshot from the upper left corner to the right bottom corner
    gfxScreenshot.CopyFromScreen(pt.X, pt.Y, 0, 0, rect.Size, System.Drawing.CopyPixelOperation.SourceCopy)
    if bitmap:
            filename = System.IO.Path.Combine(_path, _filename +'_' + _frame + '.png')
            bitmap.Save(filename, System.Drawing.Imaging.ImageFormat.Png)

#Updates this component, similar to using a grasshopper timer
def updateComponent(_ms):
    # Define callback action
    def callBack(e):
        ghenv.Component.ExpireSolution(False)
    # Get grasshopper document
    ghDoc = ghenv.Component.OnPingDocument()
    # Schedule this component to expire
    ghDoc.ScheduleSolution(_ms,gh.Kernel.GH_Document.GH_ScheduleDelegate(callBack))
Log = []
fps = 30 #frames per second for animation

# Instantiate/reset persisent starting counter variable
if "my_counter" not in globals() or Capture == False:
    my_counter = 0
    del Log[:]
    ghenv.Component.Message = None

if Capture:
    ts = time.time()
    my_counter += 1
    #ViewCaptureToFile(Path, str(my_counter).zfill(5), Filename, Transparent, Scale)
    ViewScreenCapToFile(Path, str(my_counter).zfill(5), Filename)
    te = time.time()
    real_fps = round(1/(te-ts),1)
    if real_fps>fps: real_fps=fps
    Log.append("Image Saved, attempt fps({0}) \nFrame Count = {1}".format(fps,my_counter ))
    ghenv.Component.Message = "fps " + str(real_fps)
    updateComponent(1000/fps) #update in milliseconds
2 Likes

Maybe a scripted timer like this one can help: How to run a GHPython infinite while loop with Timer - Scripting - McNeel Forum

Have you tried using the Animate feature on a slider? Will that work for what you want to do?
image

@AndyPayne @Cumberland
I attempted to record Snapshot animation internally from Gh. Because now it is only possible via screen recording software.

My original post was about the fact that Gh computation seems to be halted during the time of the animation.