Converting VSD Drawings to PNGs – VBScript

This VBScript contains the logic to convert each drawing (page) of a specific Microsoft Visio file to a png named after its source page name and saves it to a target directory.

Option Explicit

' constants required for opening files in Visio
Const visOpenRO = 2
Const visOpenMinimized = 16
Const visOpenHidden = 64
Const visOpenMacrosDisabled = 128
Const visOpenNoWorkspace = 256

' constants required for setting ExportSize in Visio
Const visRasterFitToCustomSize = 3
Const visRasterPixel = 0

Sub export(filePath, exportDirectory, widthInPixels, heightInPixels)

    ' open file
    Dim visioApplication : Set visioApplication = CreateObject("Visio.Application")

    ' set export size
    visioApplication.Settings.SetRasterExportSize visRasterFitToCustomSize, widthInPixels, heightInPixels, visRasterPixel

    ' open document in Visio without showing it to the user
    visioApplication.Documents.OpenEx filePath, visOpenRO + visOpenMinimized + visOpenHidden + visOpenMacrosDisabled + visOpenNoWorkspace

    ' iterate over all pages and export each one
    Dim currentItemIndex
    For currentItemIndex = 1 To visioApplication.ActiveDocument.Pages.Count

        Dim currentItem : Set currentItem = visioApplication.ActiveDocument.Pages.Item(currentItemIndex)

        ' use the lowercase name for the file
        Dim exportPath : exportPath = exportDirectory & "\" & LCase(currentItem.Name) & ".png"

        ' export happens here!
    	currentItem.Export exportPath

    ' Quit Visio
End Sub

' current directory
Dim currentDirectory : currentDirectory = CreateObject("Scripting.FileSystemObject").GetAbsolutePathName(".")

' file to open
Dim filePath : filePath = currentDirectory & "\AI - stundenplan.vsd"

' set export directory
Dim exportDirectory : exportDirectory = currentDirectory

export filePath, exportDirectory, 3557, 4114

Annotations about VBScript in general to better understand what is going on in this script.

  • The colon (:) is the statement separator. This can be used to declare and assign a variable in one line.
  • Use Dim NAME : NAME = VALUE for variables referencing not objects
  • Use Set NAME = OBJECT for variables referencing objects
  • Line Comments are started with '
  • No parantheses are allowed for calling Subs (procedures) or Functions
  • Stating Option Explicit at the first line requires each variable to be declared before it can be used
  • To determine what parameters to set, you can use the record macro function in Visio. This button is not directly available in Visio 2010, refer to this guide on how to make it visible.
  • The object explorer of Visio 2010 is very helpful to find the correct functions or procedures.
  • Use the ampersand (&) to concatenate strings

Find the most used first word (and every word) in your git commit messages

Via Twitter, I found this interesting gist ( which contains a one-line bash command for “Find[ing] the most used verbs in your git commit messages” in a git repo.

$ git log --pretty=format:'%s' | cut -d " " -f 1 | sort | uniq -c | sort -nr
      2 Added
      1 Improved

In the following, I have extracted the neccessary information from the help/man pages to understand, how this is achieved. I also preserved the intermediate states which are printed after a command is explained.

git log # "Show commit logs"(git log --help)
git log --pretty=format:'%s' # print each commit log as a line containing solely its subject

$ git log --pretty=format:'%s'
Improved README

cut # "print selected parts of lines from each FILE to standard output."(cut --help)
cut -d, --delimiter=DELIM # "use DELIM instead of TAB for field delimiter"(cut --help)
cut -f, --fields=LIST # "output only these fields"(cut --help)
cut -d " " -f 1 # split line by " " and output only the first field

$ git log --pretty=format:'%s' | cut -d " " -f 1

sort # "Write sorted concatenation of all FILE(s) to standard output."(sort --help)

$ git log --pretty=format:'%s' | cut -d " " -f 1 | sort

uniq # "Discard all but one of successive identical lines from INPUT (or standard input), wirting to OUTPUT (or standard output)"(uniq --help)
uniq -c, --count # "prefix lines by the number of occurrences"(uniq --help)

$ git log --pretty=format:'%s' | cut -d " " -f 1 | sort | uniq -c
      2 Added
      1 Improved

sort # "Write sorted concatenation of all FILE(s) to standard output."(sort --help)
sort -r # "reverse the result of comparisons"(sort --help)
sort -n # "compare according to string numerical value, imply -b"(sort --help)
sort -b # "ignore leading blanks in sort fields or keys"(sort --help)

$ git log --pretty=format:'%s' | cut -d " " -f 1 | sort | uniq -c | sort -nr
      2 Added
      1 Improved

If you want all the words (and not only the first words of each commit), the cut command does not suffice. In that case, sed, a “stream editor for filtering and transforming text”(sed man page) can be leveraged. It is shown in the following.

$ git log --pretty=format:'%s'
Improved README

sed # "stream editor for filtering and transforming text"(sed man page)
sed s/regexp/replacement/ # "Attempt to match regexp against the pattern space. If successful, replace that portion matched with replacement."(sed --help)
\s # whitespace character
\n # new line
sed 's/\s/\n/g' # replace all whitespace characters by new lines

$ git log --pretty=format:'%s' | sed 's/\s/\n/g'

$ git log --pretty=format:'%s' | sed 's/\s/\n/g' | sort

$ git log --pretty=format:'%s' | sed 's/\s/\n/g' | sort | uniq -c
      2 Added
      1 Improved
      2 README

$ git log --pretty=format:'%s' | sed 's/\s/\n/g' | sort | uniq -c | sort -nr
      2 README
      2 Added
      1 Improved

But beware, as this can be too much for your command line buffer to handle. This can be solved by piping the result to less.

$ git log --pretty=format:'%s' | sed 's/\s/\n/g' | sort | uniq -c | sort -nr | less
      2 README
      2 Added
      1 Improved

It can still be improved, e.g., to convert all upper case letters to lower case ones. This is possible using tr '[:upper:]' '[:lower:]' which uses the tr tool that is able to “translate, squeeze, and/or delete characters from standard input, writing to standard output”(tr --help). In that case it translates every upper case letter to a lower case one while copying the other characters.

Counting html files with ruby and bash

At work, I had the task to count how many html files where located within a specific folder and its subfolders.

I did it first in Ruby, then in bash. I will show the source code and explain the solution afterwards.

First, the Ruby solution:

puts Dir.glob('**/*.html').count

I invoke the glob method of the Dir class and send it a glob pattern. This pattern refers to all html files within the current directory and within all sub directories. The method returns an array of all found files. This array has a count method which returns the number of entries. The number is printed to the console using the puts command. Read it like this: The program puts the number to the console.

You can invoke this directly from the command line using ruby -e as shown below:

ruby-e "puts Dir.glob('**/*.html').count"

Note, that you have to be careful how to use the or signs. For more information on the Dir class and its methods, please refer to the ruby api on the Dir class.

In bash, the solution is as follows:

find -name "*.html" | wc -l

It consists of two parts: First, all files which ends with .html are found within the current directory and its subfolders using the find command. Each found file will be send to the STDOUT. Normally, this would print this to the console. However, using |  (the pipe character) we redirect the found files to the wc command which stands for word count. This command can count the characters, words or lines of a file/input. In our case, we want it to count the lines by passing it the -l flag. For more information on pipes on unix, read this.

Both solutions work! 🙂

Command Line Tips – pwd

Using the unix command line, the most commonly used tool is pwd. It prints the working directory, meaning the directory the console is currently targeted at. This is done by simply writing the current value of the global variable $PWD to the screen. You can do this by hand using echo $PWD. If you change the directory with cd, you change the variable $PWD and, therefore, the output of the command pwd. For convinience, the system stores the previous value of $PWD in the variable $OLDPWD. This $OLDPWD variable can be printed to the screen using echo $OLDPWD.

Tip: Using cd –, you can change the working directory to the previous working directory.


user@host /test $ pwd

user@host /test $ echo $PWD

user@host /test $ cd sub

user@host /test/sub $ pwd

user@host /test/sub $ echo $OLDPWD

user@host /test/sub $ cd -

user@host /test $ cd -

user@host /test/sub $

Note: global variables should be written in capital letters, as shown above. Use lower case letters for your own local variables!

PS: Note the all new, well designed favicon!

Starting Sublime Text 2 from the Command Line

My all-new-favorite text editor is Sublime Text 2. This editor is blazingly fast, has a project view for simple navigation, supports syntax highlighting for allmost all formats out of the box and can be extended. I often have to work in the command line, however, I do not want to use vim. Thus, I have to start and navigate to my project in the command line as well as in my editor. Additionally, opening files in my editor instead of vim has to be done using my windows explorer.

Scripting to the rescue!

I wrote a small bash script, which can be used in cygwin/git bash environments for starting sublime:

/c/Program\ Files/Sublime\ Text\ 2/sublime_text.exe $1 &

A few comments to this script:

  • The first line indicates that this is a script which is executed using /bin/sh (the standard shell)
  • The second line executes the sublime_text.exe. Note, that spaces in the folders had to be escaped using the backslash character (\).
  • $1 refers to the first parameter passed to this script. This can be a file or a folder which is passed on to Sublime Text 2 which in turn automatically opens the file or in case of a folder adds it to the current project.
  • The & sign at the end moves this process into the background. This allows to use the current command line further while Sublime Text 2 is running (as it is NOT running in the foreground of the command line. )

Of course, you have to chmod +x this file to make it executable and place it into a folder which is within the PATH. Perhaps renaming the script to sl would be nice in order to reduce typing.

But then, you can use the script as follows to open the current directory:

$> sublime .

Or open the test.txt file:

$> sublime test.txt

TextMate (solely available on the Mac) already has such a feature named mate.