A needed to generate a series of consistent gradients in Visio this week for some diagrams. It's tedious to do this manually so I automated the task with IronPython 1.1.

Running this command line:

image

 

Produces launches Visio to 2007 produce this output.

 

image

 

The attached package with source is here: msdn_saveenr-2007-07-07-Automating Visio with IronPython.zip

It includes three files:

  • AutoVisio.Dll - where I wrote a lot of code to simplify the use of Visio from other managed code languages
  • Isotope.Color.Dll - some simple colorspace utilities (RGB, HSB, HSL)
  • gradient_explorer.py - the code that generates the gradients

gradient_explorer uses a seed color to generate a sequence of gradients automatically. Using different seed colors results in different colors. Examples are below:

image

Below is the gradient explorer source

 

 

 

"""

gradient_explorer

USAGE
-----
Run script. It will start visio and draw a series of gradients based on the seed_color.

HOW TO GET DIFFERENT GRADIENTS
------------------------------
-alter the seed_color
-play with the modify_color_x functions

HISTORY
-------

2007-07-06
Updated to produce multiple rows

2007-07-05
Initial Version

"""
import sys
import clr

import System

clr.AddReference("System.Drawing")
import System.Drawing

clr.AddReference("Microsoft.Office.Interop.Visio")
from Microsoft.Office.Interop import Visio


clr.AddReferenceToFileAndPath("AutoVisio.dll")
import AutoVisio

clr.AddReferenceToFileAndPath("Isotope.Color.dll")
import Isotope.Color


def modify_color_1( input_hsl ) :
    return input_hsl.Add( 1.1, -input_hsl.Saturation , -0.05 )

def modify_color_2( input_hsl ) :
    return input_hsl.Add( 0.0, 0.0 , -0.1 )

def modify_color_3( input_hsl ) :
    return input_hsl.Add( 0.0, 0.0 , -0.2 )

def modify_color_4( input_hsl ) :
    return input_hsl.Add( 0.0, 0.0 , -0.3 )

def modify_color_5( input_hsl ) :
    return input_hsl.Add( 0.02, 0.1 , -0.2 )

def modify_color_6( input_hsl ) :
    print input_hsl
    return input_hsl.Add( -0.02, 0.1 , -0.2 )


text_color_black = Isotope.Color.HSLColor.FromWebColorString("#000000") 
text_color_white = Isotope.Color.HSLColor.FromWebColorString("#ffffff") 

def calc_text_color( start_color, end_color ) :
    mid_lum = ((start_color.Luminance+ end_color.Luminance) /2.0)

    if ( mid_lum>0.6) :
        text_color = text_color_black
    else :
        text_color = text_color_white

    return text_color


def explore_gradients():

    seed_color = Isotope.Color.HSLColor.FromWebColorString( "#ff0000" )
    #seed_color = Isotope.Color.HSLColor.FromRGBBytes( 193,202,221)
    #seed_color = Isotope.Color.HSLColor.FromRGBBytes( 249,185,81)
    #seed_color = Isotope.Color.HSLColor.FromRGBBytes( 171,205,137)
    
    # number of blocks in each row
    steps = 20

    # 36 is a gradial gradient that begins in the upper left        
    grad_pattern_id = 36

    # One row will be drawn for each color function in this list
    color_funcs = [ modify_color_1, modify_color_2, modify_color_3 , modify_color_4 , modify_color_5, modify_color_6 ]


    grad_rows = []

    # caclculate an evenly spaced set of luminances starting from 0.0 to 1.0
    luminances = [ v*(1.0/(steps-1)) for v in xrange(steps) ]

    # using the seed color generate the starting color used for each row
    row_start_colors= [ Isotope.Color.HSLColor( seed_color.Hue, seed_color.Saturation, lum ) for lum in luminances ]


    # generate the colors for each row
    # each row will contain a tuple of (start,end) colors
    for color_func in color_funcs :
        row_end_colors = [ color_func(start_color) for start_color in row_start_colors ]
        grad_rows.append( zip( row_start_colors, row_end_colors) )


    # for debugging, print out all the color strings before drawing begins
    for grad_colors in grad_rows :
        for i,grad_color in enumerate(grad_colors):
            print i+1, grad_color[0].ToWebColorString(), "->", grad_color[1].ToWebColorString()
        print
    
    num_cols = steps
    num_rows = len( grad_rows )

    # each cell is one inch in width and height
    # the page has a 1 inch border on each of the four sides
    page_width = 2 + num_cols
    page_height = 2 + num_rows
    page_size = AutoVisio.Size( page_width ,page_height)

    # Launch Visio to do the drawing
    app = AutoVisio.VisioLib.StartVisio()

    # Create a document with an initial empty page    
    doc = AutoVisio.VisioLib.CreateDocument( app,  page_size )

    # Locate that first page
    page = doc.Pages[1]

    # for each row draw the gradients
    for grad_row_index, grad_colors in enumerate(grad_rows) :

        for n,grad_color in enumerate(grad_colors) :

            rect = AutoVisio.Rect( 1+n,1+grad_row_index,1+n+1,1+grad_row_index+1)
            start_color,end_color = grad_color

            # find the right text color that is visible on the gradient
            text_color = calc_text_color( start_color, end_color ) 
            
            # Draw the shape        
            shape= AutoVisio.VisioLib.DrawRectangle( page, rect )

            # Set the shape attributes
            AutoVisio.VisioLib.SetFillGradient( shape ,
                                                grad_pattern_id,
                                                start_color.ToSystemDrawingColor(),
                                                end_color.ToSystemDrawingColor() )
            AutoVisio.VisioLib.SetLinePattern( shape, 0 )

            # for debugging, can set the text content of the shape
            # shape.Text = str( grad_pattern_id )
            # AutoVisio.VisioLib.SetTextColor( shape, text_color.ToSystemDrawingColor()  )
    
if ( __name__ == '__main__' ) :
    explore_gradients()