Visio Guy

Visio Discussions => Programming & Code => Topic started by: PinPinPoola on March 21, 2024, 03:58:05 PM

Title: Create a new stencil and populate master shapes from image files via PowerShell?
Post by: PinPinPoola on March 21, 2024, 03:58:05 PM
Has anyone any example PowerShell code to create a new stencil and populate it's master shapes from external image files (.png | .svg)?

I have tried recording a VBA macro and then 'converting' it to Powershell, but I am getting nowhere fast. Even ChatGPT eventually gave up giving suggestions.

I will appreciate any help/suggestions.

Thx
Pin
Title: Re: Create a new stencil and populate master shapes from image files via PowerShell?
Post by: Surrogate on March 21, 2024, 04:24:59 PM
Hi, Pin!
Quote from: PinPinPoola on March 21, 2024, 03:58:05 PM
I have tried recording a VBA macro and then 'converting' it to Powershell, but I am getting nowhere fast.
Not all actions can be write via macro-recorder!  :(
Right now I have not time for PowerShell coding, but I prepare this VBA-code for 5 minutes...
Sub PicturesImportToDocStencil()
    Dim strPath As String
    Dim strFile As String, fullname As String
    Dim cnt As Integer
    Dim mst As Visio.Master
    Dim wn As Window
    cnt = 0
    strPath = "C:\Users\surrogate-tm\Pictures\VisioObjectModel\"
    strFile = Dir(strPath & "*.*") ' Searches for all files
    Do While strFile <> ""
        cnt = cnt + 1
        Debug.Print cnt, strFile
        Set mst = ActiveDocument.Masters.Add
        mst.Name = cnt
        mst.Prompt = ""
        mst.IconSize = visNormal
        mst.AlignName = visCenter
        mst.MatchByName = False
        mst.IconUpdate = visAutomatic
        Set wn = mst.Open.OpenDrawWindow
        wn.Activate
        fullname = strPath & strFile
        wn.Master.Import fullname
        wn.Master.Close
        strFile = Dir()
    Loop
End Sub


Title: Re: Create a new stencil and populate master shapes from image files via PowerShell?
Post by: PinPinPoola on March 21, 2024, 05:09:21 PM
Thank you Surrogate.

I am still struggling with VBA, but getting much better with PowerShell these days; as my job uses it more & more.

As always, I really appreciate your help.

Take care,
Pin
Title: Re: Create a new stencil and populate master shapes from image files via PowerShell?
Post by: Yacine on March 22, 2024, 04:32:03 AM
Saveenr has done some powershell / visio stuff.
https://stackoverflow.com/users/468604/saveenr
Title: Re: Create a new stencil and populate master shapes from image files via PowerShell?
Post by: Surrogate on March 22, 2024, 04:51:12 AM
Quote from: Yacine on March 22, 2024, 04:32:03 AM
Saveenr has done some powershell
Yes, we can find his site (https://saveenr.gitbook.io/visio) and repository (https://github.com/saveenr)
Title: Re: Create a new stencil and populate master shapes from image files via PowerShell?
Post by: PinPinPoola on March 22, 2024, 01:50:46 PM
Thank you both for Saveenr's details. I will take a look.

In the mean time @Surrogate I have had time to try your suggested code and nothing happens when I run it.

I have updated the strPath to my own path and strFile to (*.svg)

When I run the code, the Visio session 'flashes' or refreshes for each file, but no new shapes appear.

I have tried opening the new stencil file for edits.

Am I doing something wrong?

Cheers
Pin
Title: Re: Create a new stencil and populate master shapes from image files via PowerShell?
Post by: Surrogate on March 22, 2024, 04:05:10 PM
Quote from: PinPinPoola on March 22, 2024, 01:50:46 PMAm I doing something wrong?
My simple code add new master-shapes to local document stencil, it not create new external stencil!!!
(https://i.imgur.com/hSYSza2.png)
Please check Show Document Stencil option...
Title: Re: Create a new stencil and populate master shapes from image files via PowerShell?
Post by: Surrogate on March 22, 2024, 11:25:57 PM
Quote from: PinPinPoola on March 21, 2024, 05:09:21 PMbut getting much better with PowerShell these days; as my job uses it more & more.
Sorry, I am not PowerShell exert :-\

$visio = [Runtime.Interopservices.Marshal]::
GetActiveObject('Visio.Application')   # Get Visio.App session   
# Get Visio ActiveDocument
$Doc = $visio.ActiveDocument     
# Set Masters counter 
$n = 0   
# Set folder path   
    $Path= 'C:\Users\surrogate-tm\Pictures\VisioObjectModel' 
    Get-ChildItem -Path $Path | ForEach-Object {
# Iterate SVG files
        If ($_.Name -like "*.svg") {
# Increment counter
            $n = $n+1
# Get current SVG fullname
            $fn = $_.FullName
# Create new master
            $mst = $doc.Masters.Add()
# Rename new master
            $mst.Name = $n
# Set normal iconsize (visNormal = 1)
            $mst.IconSize = 1
# Set align name (visCenter)
            $mst.AlignName = 2
# No MatchByName option
            $mst.MatchByName = $False 
# Set IconUpdate mode (visAutomatic = 1)
            $mst.IconUpdate = 1
# My code cant open master window
            $wn = $mst.Open.OpenDrawWindow
# I want Activate window,  but I cant do this
            $wn.Activate
# Import SVG picture
            $wn.Master.Import, $fn
# Close master's window
            $wn.Master.Close
# Debug output
            Write-Host -Object "Added master: $fn"
        } ElseIf ($_.PSIsContainer) {
# ???
        } # End If-ElseIf.

I cant translate VBA code row
Set wn = mst.Open.OpenDrawWindow
Title: Re: Create a new stencil and populate master shapes from image files via PowerShell?
Post by: Nikolay on March 23, 2024, 09:07:34 PM
Visio Super Utilities can do that:
https://unmanagedvisio.com/products/vsu/

Use Stencil -> Create Stencil From Images
(https://i.imgur.com/lf8maY4.png)

You will be prompted for the stencil name, and to pick the images to create the stencil from.
Title: Re: Create a new stencil and populate master shapes from image files via PowerShell?
Post by: Surrogate on March 23, 2024, 11:27:52 PM
Quote from: Nikolay on March 23, 2024, 09:07:34 PM
Visio Super Utilities can do that
Sorry, I forgot!
My code is just for memory!
I had a problem with importing a picture. I couldn't do it without drawing a rectangle before importing the picture. (http://visio.getbb.ru/images/ranks/visio_getbb_ru/huh.gif)$visio = [Runtime.Interopservices.Marshal]:: GetActiveObject('Visio.Application') # Get active Visio session
$visio.AlertResponse = $true # AlertResponse change to
$target = 'C:\Forum_BU\gifs\test1.vss' # Path for new stencil
$st = $visio.Documents.Addex('', 0, 516) # Create new stenctl
$n = 0
$Path= 'C:\surrogate-tm\Pictures\VisioObjectModel'

    Get-ChildItem -Path $Path | ForEach-Object {
        If ($_.Name -like "*.*") { #
            $n = $n+1
            $fn = $_.FullName
            $mst = $st.Masters.Add()
            $mst.Name = $n
            $mst.Prompt = ""
            $mst.IconSize = 1 #visNormal
            $mst.AlignName = 2 #visCenter
            $mst.MatchByName = $False
            $mst.IconUpdate = 1 #visAutomatic
            $wn = $mst.OpenDrawWindow()
            $wn.Activate()
            $sh1 = $wn.Master.DrawRectangle(0,0,0,0) # Draw rectangle
            $sh2 = $wn.Master.Import($fn) # Import picture
            $sh2.Cells("LocPinX").Formula = 'Width*0'
            $sh2.Cells("PinX").Formula = '0 mm'
            $sh2.Cells("LocPinY").Formula = 'Height*0'
            $sh2.Cells("PinY").Formula = '0 mm'
            $wn.Master.Close() # Close master

        } ElseIf ($_.PSIsContainer) {

        } # End If-ElseIf.
    } # End ForEach-Object.
    $visio.AlertResponse = $false #
    $st.SaveAs($target) # Save stencil
    $st.close() # Close stencil
    $visio.Documents.OpenEx($target, 6) # Open stencil for RO
Title: Re: Create a new stencil and populate master shapes from image files via PowerShell?
Post by: wapperdude on March 25, 2024, 05:55:21 AM
PowerShell...
Title: Re: Create a new stencil and populate master shapes from image files via PowerShell?
Post by: Yacine on March 25, 2024, 08:11:06 AM
That's not fair. PS got a super hero as mascot, we've haven't got more than a funny nerd head.
Title: Re: Create a new stencil and populate master shapes from image files via PowerShell?
Post by: wapperdude on March 25, 2024, 05:53:11 PM
Well, desperate does as desperate needs.  Obviously PowerShell feels creative need to expand user base. 

I was perusing PowerShell to see if there's any utility gained for Visio users.  I have mixed feelings.  I'm am most doubt.  Visio is so inherently powerful, I see little point, if any, to use Visio PowerShell.  The idea of Visio was to be visual object oriented, and, for the most part, avoid doing design/entry via a textual input.  PowerShell seems like a step backwards...use a textual input to drive a graphics tool?  Yes, there are unforeseen missing tools, but these can be provided from within Visio.  This topic, case in point.  Nikolay has tool that does what was requested of PowerShell. 

I even tried using binges to do this.  It failed.  It created a solution, code failed, pointed out error, fix failed.  Yada. Yada.  So, then I tried...and failed.    There are a couple sites, and YouTube vids, but this is too much of a niche topic to motivate investment time to learn something I'll not use again. 

Perhaps some of the other power users will pick up on this.
Title: Re: Create a new stencil and populate master shapes from image files via PowerShell?
Post by: wapperdude on March 27, 2024, 12:37:21 AM
OK.  So I am officially off my rocker!  Why? Well, 1) Nikolay has a working solution from inside Visio, 2) I know nothing about PowerShell, com stuff, etc., and 3) I hate programming.

Well, with the help of BingAI, below is working PowerShell code (script, I guess).

Some things to note:
1) translating image files into Visio shapes requires, uh, Visio.  That then begs the question, why not use Nikolay's solution.
2) the code works, mostly.  Issue with quitting VisiThe use and the pop-up dialog asking yes, no, cancel. 
3) this is proof of concept, so, code only grabs a single image.  Some sort of loop would be needed to grab more than 1
4) User must use appropriate file locations and names.
5) this code is a collaborative effort between me and BingAI

# Define the path to the image file you want to add
$imagePath = "C:\VisioPix\MyImage1.jpg"

# Define the name for the new master
$masterName = "MyImage1"

# Create a new Visio application object
$visioApp = New-Object -ComObject Visio.Application

# Make Visio invisible to the user (no UI)
$visioApp.Visible = $false

# Create a new document for importing the image
$doc = $visioApp.Documents.Add("")

# Import the image to the new document
$importedShape = $doc.Pages.Item(1).Import($imagePath)

# Define the path to the Visio stencil file
$stencilPath = "C:\VisioPix\Pix.vssx"

# Open the stencil file
$stencil = $visioApp.Documents.OpenEx($stencilPath, 64)

# Create a master of the imported image in the stencil
$master = $stencil.Drop($importedShape, 0, 0)

# Set the name for the new master
$master.Name = $masterName

# Save the modified stencil
$stencil.SaveAS($stencilPath)

# Close the stencil and the new document
$stencil.Close()
$doc.Close()

# Quit Visio
$visioApp.Quit()

# Release the COM objects
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($importedShape)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($master)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($stencil)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($doc)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($visioApp)

# Print a success message
Write-Host "Task execution done."
Title: Re: Create a new stencil and populate master shapes from image files via PowerShell?
Post by: PinPinPoola on March 28, 2024, 03:39:19 PM
Apologies that I have not replied sooner, but I had to go away with work for a few days.

Thank you all so much for your help; especially to Surrogate, as your second PowerShell script worked perfectly for me.

Pin.
Title: Re: Create a new stencil and populate master shapes from image files via PowerShell?
Post by: wapperdude on March 30, 2024, 10:08:39 PM
Not taking anything away from Surrogate's response, but since I had syarted this learning experience, I decided to complete the task by including a For loop to iterate through a directory for image files.  Along the way, I discovered that copy/pasting the cmdlets seems to always run, but, thru not so when trying to execute the code same via a script file... until I found this syntax that seems to work  PowerShell and PowerShell ISE:  & 'C:\PowerShellProject\NewTry R6.ps1'  The scriptfile is NewTry R6.ps1, located in directory C:\PowerShellProject.

I'm reasonably confident in the following code.  Use notepad to copy/paste & save as .ps1, not txt, or  may also be copy/pasted into PowerShell directly. 

Some features:
1) the target vssx file must be pre-existing.  Initially, a blank (empty) vssx is fine.
2) the directories and file names are hard coded, so some editing is necessary
3) Visio must be called, even Surrogate's code does this, but Visio is hidden.
4) the code executes without creating any preceding shapes to contain the image file import.
5) it displays the filenames that were processed.
$visApp = New-Object -ComObject Visio.Application
$visApp.Visible = 0
$visApp.AlertResponse = 5
$visDoc = $visApp.Documents.Add("")
   
$stnPath = "C:\PowerShellProject\Pix.vssx"
$stnFile = $visApp.Documents.add($stnPath)
$stnFile.Protection = 2

Get-ChildItem -path "C:\VisioPix" | ForEach-Object {
    $imgFile = $_.Fullname
    $masterName = $_.Basename
    start-sleep -m 500
    $importedShape = $visDoc.Pages.Item(1).Import($imgFile)
    $master = $stnFile.Drop($importedShape, 0, 0)
    $master.name = $masterName
    write-host "Image File: " $masterName
    $importedShape.Delete()
}

$stnFile.SaveAS($stnPath)
$stnFile.Close()

$visApp.Quit()   

# Print a success message
Write-Host "Task execution done."

Title: Re: Create a new stencil and populate master shapes from image files via PowerShell?
Post by: wapperdude on April 01, 2024, 12:38:59 AM
Here's an alternative version of the script.  This version leverages the VisioPS module and its accompanying commands.  It allows more of a Visio feel to the coding. BTW, the start-sleep line in the previous version is not needed, and not included below.  Also, if spaces are removed from the file name, then the "&" and single quotes noted above are unnecessary.

Ed.: Curious note.  Invoking New-VisioDocument actually starts a new Visio session.  The Get-VisioApplication grabs that running session.  Whereas, had New-VisioApplication been executed first, that would also start a new Visio instance without a document reference.  As this is temporary, A New-VisioDocument would still be needed, only now two Visio instances would exist.  Most undesirable.  Hence the code order below is necessary, sufficient, and intentional wrt starting up Visio. 

The rest of the code was generated by 10,000 monkeys working with AI.

Import-Module Visio
$visDoc = New-VisioDocument
$visPg = Get-VisioPage -ActivePage
$visApp = Get-VisioApplication
$visApp.Visible = 0
$visApp.AlertResponse = 5
   
$stnPath = "C:\PowerShellProject\Pix.vssx"
$stnFile = $visApp.Documents.add($stnPath)
$stnFile.Protection = 2

Get-ChildItem -path "C:\VisioPix" | ForEach-Object {
    $imgFile = $_.Fullname
    $masterName = $_.Basename
    $importedShape = $visPg.Import($imgFile)
    $master = $stnFile.Drop($importedShape, 0, 0)
    $master.name = $masterName
    write-host "Image File: " $masterName
    $importedShape.Delete()
}

$stnFile.SaveAS($stnPath)
$stnFile.Close()

Close-VisioApplication

# Print a success message
Write-Host "Task execution done."