V6 Goal: True PDF Export

Steve,

What are these “left”,“right” inputs for the filepdf.drawbitmap function? Looks like the docstring is missing.

Steve,

I think I’m getting closer. I’m able to create the bitmap as suggested. However, the placing of the bitmap on the pdf (pdf.DrawBitmap) is throwing this cryptic (to me at least) error.

VB Code block:

Dim settings As rhino.display.ViewCapturesettings = New rhino.display.ViewCapturesettings(RhinoDocument.Views.ActiveView, s, dpi)
Dim bitm As bitmap = rhino.display.ViewCapture.CaptureToBitmap(settings)
bitm.Save(“c:\projects\bm.jpg”)

Dim  pdf  As rhino.FileIO.FilePdf = rhino.FileIO.FilePdf.Create()
Dim pagenum As Integer = pdf.addpage(s.Width, s.Height, dpi)
pdf.DrawBitmap(pagenum, bitm, 0, 0, 300, 300, 0)

@stevebaer

I’m running into I think the same issue when trying to replicate the pseudo code you provided just above to place a captured bitmap onto a blank pdf page.

"Runtime error (MethodAccessException): Attempt by security transparent method ‘Xfinium.Pdf.Win.SelectionSerializer.DisableAssistant(System.Drawing.Bitmap)’ to access security critical method ‘System.Runtime.InteropServices.Marshal.Copy(IntPtr, Byte, Int32, Int32)’ failed.

Assembly ‘Xfinium.Pdf.Win, Version=8.0.0.11, Culture=neutral, PublicKeyToken=3a083ecebc95eb1c’ is marked with the AllowPartiallyTrustedCallersAttribute, and uses the level 2 security transparency model. Level 2 transparency causes all methods in AllowPartiallyTrustedCallers assemblies to become security transparent by default, which may be the cause of this exception."

Code below:

currentView = sc.doc.Views.ActiveView
dpi = 300
pdf = Rhino.FileIO.FilePdf.Create()
setting = Rhino.Display.ViewCaptureSettings(currentView, size, dpi)
capture = Rhino.Display.ViewCapture.CaptureToBitmap(setting)

pdf.AddPage(11*dpi,8.5*dpi,dpi)
pdf.DrawBitmap(1, capture, 0, 0, 11*dpi,8.5*dpi, 0)

filename = rs.SaveFileName()
pdf.Write(filename)

Is there a workaround yet? The documentation page is still missing lots of info in this area it seems like.

Thanks!

It is very impressive. May I ask how to avoid a dialog box when I use rs.SaveFileName? I don’t want to press Enter 50 times when I batch a drawing set. Thanks

1 Like

@stevebaer

I am also running into the same issue as timothytai right now adding a bitmap to a pdf with the exact same MethodAccessException Runtime error. Has anyone figured this out?

I was sort of able to work around the bitmap issue by using the iTextSharp library to insert the bitmap into the file after it had been written out by Rhino. Not the most convenient solution, but it worked.

I do have another request after some testing with the PDF export. Currently, the pdf export gives sharp edges and square line ends, which isn’t ideal when you have unjoined line segments that should at least appear continuous in the drawings. If would be incredibly helpful good to have the pdf export do rounded corners and ends, at least as an export option. See the images below.

I filed a feature request for this at https://mcneel.myjetbrains.com/youtrack/issue/RH-50899
Thanks for “pointing” it out :slight_smile:

4 Likes

I put my issue here as well since I should have start here.

So any update on how we can manage the point size when we use pdf file export?

Hi Steve,
I am trying to batch print a series of dwg to pdf with this and ecverything works but I do not understand how to implement this “settings.OutputColor” in the python script…
could you explain a bit more for a dummy like me?
Thanks!

Figured (duh!)
capture = Rhino.Display.ViewCaptureSettings(page,dpi)
capture.OutputColor=Rhino.Display.ViewCaptureSettings.ColorMode.DisplayColor

1 Like

Hello, I am trying to batch raster pdfs for drawing issue and have similar code to the above: AddPage, CaptureToBitmap, DrawBitmap, Write.

The Rhino.FileIO.FilePdf.DrawBitmap method is still resulting in the error 'Attempt by security transparent method ‘Xfinium.Pdf.Win.SelectionSerializer.DisableAssistant(System.Drawing.Bitmap)’

It would appear this is beacuse we don’t have the developer version of Xfinium PDF writer.
Is this on the horizon to be fixed?
I assume this is why the raster property in the ViewCaptureSettings class is not available or could this be added?

Alternatively if the pdf in RhinoPDF saved automatically as the layout or view name rather than the 3dm file name this would save alot of time.

This is something I am looking into, but currently have not fixed.

2 Likes

Hello, I have made some progress for a WIP alternative for a batch raster pdf maker…

First you need to get PdfSharp via nuget cli. Download to a folder and run

nuget.exe Install-Package PdfSharp

make sure all files are unblocked in their properties tab.

Then we need to add some modules as well as the usual suspects…

from System import Environment as env    
import clr
clr.AddReferenceToFileAndPath(r"c:\directory where you installed\lib\net20\PdfSharp.dll")
import PdfSharp as ipdf

I have modified the code to use pdfsharp…

def createSinglePDFRaster(view,wrkdir):
    # scale sizing based on scripts by Kelvin Chang & Lando Schumpich have added
    # layout sizes to accomodate pdfsharp
    if sc.doc.ActiveDoc.PageUnitSystem == sc.doc.PageUnitSystem.Millimeters:
        factor = 0.0393700787401575
        vWidth = ipdf.Drawing.XUnit.FromMillimeter(view.PageWidth)
        vHeight = ipdf.Drawing.XUnit.FromMillimeter(view.PageHeight)
    else:
        factor = 1.0
        vWidth = ipdf.Drawing.XUnit.FromInch(view.PageWidth)
        vHeight = ipdf.Drawing.XUnit.FromInch(view.PageHeight)
    dpi = 300

      # forces view to redraw, this doesn't appear to work so far...
    sc.doc.Views.ActiveView = view
    while view.Redraw() == False:
        Rhino.RhinoApp.Wait()

    # capture the layout image and send it to a memory stream, save as pdfsharp ximage
    size = System.Drawing.Size(view.PageWidth * factor * dpi, view.PageHeight * factor * dpi)
    settings = Rhino.Display.ViewCaptureSettings(view, size, dpi)
    bitmap = Rhino.Display.ViewCapture.CaptureToBitmap(settings)
    stream = System.IO.MemoryStream()
    bitmap.Save(stream,System.Drawing.Imaging.ImageFormat.Png)
    img = ipdf.Drawing.XBitmapImage.FromStream(stream)
    
    # create pdf document at a given location, add some pdf properties
    filename = os.path.join(wrkdir,view.PageName+'.pdf')
    pdf = ipdf.Pdf.PdfDocument()
    pdf.Info.Title = view.PageName
    pdf.Info.Author = env.UserName
    
    # add a single page to same dims as layout
    layout = pdf.AddPage()
    layout.Width = vWidth
    layout.Height = vHeight
    page = pdf.Pages[0]
    # create the background image and draw, save pdf
    gfx = ipdf.Drawing.XGraphics.FromPdfPage(page, ipdf.Drawing.XPageDirection.Downwards)
    gfx.DrawImage(ipdf.Drawing.XImage.FromStream(stream),0,0,page.Width,page.Height)
    pdf.Save(filename)

# pdf directory
pdfDirOut = r"c:\your\working\directory"
# create a list of layouts
viewList = [v for v in sc.doc.Views if v.GetType() == Rhino.Display.RhinoPageView]

# UI Progress bar
uiStr = '{} pdfs are being generated...  '.format(len(viewList))
Rhino.UI.StatusBar.ShowProgressMeter(0,len(viewList),uiStr,True,True)
progressBar = Rhino.UI.StatusBar.UpdateProgressMeter

# run for loop script
for i,view in enumerate(viewList):
    progressBar(i+1,True)
    createSinglePDFRaster(view,pdfDirOut)
    
Rhino.UI.StatusBar.HideProgressMeter()

The script pdf’s all the views correctly, only problem is I can’t seem to get the layout to redraw, if its active its ok, if not then it seems to revert to wireframe.

Anyone able to help with redraw events?

1 Like

Well redrawing is normally handled via the Redraw Method of a RhinoView.

view.Redraw()

I added the view.Redraw() method but it only returns None when printed.

On layouts that take a few seconds to render (with materials and shading etc) it requires a redraw.

I have looked in rhino common and can’t seem to find an event handler in rhino.display that confirms when the detail views have been redrawn either individually or by layout, maybe @stevebaer could help?

It maybe something simple or something a bit more complex going into the view pipeline.

If you click on the linked Rhinocommon page in my post, you can see the return type of RhinoView.Redraw() is void or None in python.

Is the redraw not working? What is your error?

Thanks for the reply @lando.schumpich ,

The script cycles through the layouts and saves as a bitmap regardless of whether the details views have completed rendering (materials, fills etc) so appear wireframe in the raster pdfs.

The problem is there seems to be no feedback on the view.Redraw() ensuring the display pipeline and rendering has completed.

while view.Redraw() != None:
    Rhino.RhinoApp.Wait()
    if view.Redraw() == None:
        break

Still results in wireframe pdfs.

while view.Redraw.Equals(None) is False:
    Rhino.RhinoApp.Wait()
    if view.Redraw.Equals(None) is True:
        break

Causes the loop to hang.

I am looking into the geometry pipeline but its getting quite deep into rhinocommon.

I have been looking into this further. I think view.Redraw() only updates things like viewport rectangles, cameras and curves etc rather than work with the viewport style and rendering the detail view. It seems that with any layout view, the rendering only happens on a mouse event, such as pan or zoom. It could be a driver issue (Quadro P4000).

I’m trying to use the Rhino.UI and Mouse methods to jog / pan the view with not much luck. Any help would be appreciated.

Detail view got me thinking here…

Maybe you need to set the details active one by one and redrawing for each one?

Have a look at the DetailView and PageView classes, especially the SetActiveDetail(Guid) and SetPageAsActive methods of PageView

Thanks for the reply, I initially thought this as well. I have tried the following but still the same problem with detailview’s not rendered correctly:

sc.doc.ActiveDoc.Views.ActiveView = view
details = view.GetDetailViews()
for d in details:
    d.GripsOn = True
    d.GripsOn = False
    vP = d.Viewport
    vP.DisplayMode = vP.DisplayMode
    d.CommitViewportChanges()

To get some sort of graphics redraw such as setting handles, changing display mode, committing changes etc.

It seems that the graphics pipeline starts after commiting changes and with some sort of interaction e.g. if I have an error in my script and the context of the python editor changes or I pan the PageView the DetailViews render correctly.