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.
- through Rhino.Display.ViewCapture() which turned out to be too slow (commented out)
- 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
