Wednesday
Sep032008

Notes on Using Client Applications to Generate Server-Side Graphics

Occasionally I am contacted by someone who wants to generate some graphics content on a web server and they want to use a client application like Visio or PowerPoint or Photoshop as as an engine to generate those images dynamically on a web server. They are often looking for some guidance on whether this is a better approach than, for example, manually creating the images using custom code.

The fundamental issue is that client applications are (usually) never designed to be run in this scenario.

Typical issues one will encounter

  • Simultaneous requests – A single instance of a client applications will often be unable to handle multiple client requests at the same time. You may have to spawn multiple instances or queue the requests. (I’ll leave identifying any threading issues as an exercise to the reader)
  • Security – You’ve got to be careful to examine the potential risk of running a client application in a server context. For example, can a client use malformed input to cause the application to do something that would put the server at risk? You need to think about the threat model for this scenario.
  • Interactivity – Client apps tend to assume that there is a human sitting in front of a monitor using the app and so will show UI (modal dialogs, etc.). When there is an interactive user, this is no problem, the user handles or dismisses the UI and continues. On the server side, you may find that the client app will try to launch some interactive UI and will either outright fail or simply block waiting on user input. A typical example are the “File already exists. Do you want to overwrite?” dialogs. You’ll have to code around these issues if you can.
  • Licensing – The license under which one uses the software may explicitly or implicitly restrict or forbid its use as a server-side application.
  • API support – Some client apps allow a user to interactively create content but does not provide an API to do so programmatically. Sometimes if the API is exposed, you may find that the API is quite limited compared to what an interactive user can create.
  • Performance and Memory Usage – you may find that even low numbers of requests per unit time that the client application consumes too much memory or CPU cycles.

My Recommendations

  • (a) Roll-your own.  XML-based vector formats like SVG or Silverlight might be good candidates here because it is simple to create the content.
  • (b) Re-use an existing library that is built for generating server side graphics (example: libgd)

Even with this recommendation one will have to consider most the issues I’ve identified earlier, but at least one will have more control over those issues.

Update [2008-08-09]: Additional links

Monday
Apr142008

Speeding up Visio automation by batching via SetFormulas(), GetFormulas() and VisDOM

If you've read this post by Bill Morein and this one by Mai-lan, you know that using page.SetFormulas() and page.GetFormulas() can really speed things up when drawing via Automation.

In this post I'm going to show a range of techniques to use SetFormulas() and GetFormulas() to achieve this performance win. The code here is on the latest release (3.0.2) of AutoVisioExt on CodePlex.

First, let's use the VisioAutoExt library and some basic code that draws a 15x15 grid of squares and sets them to have a circular fill gradient with different starting and ending transparencies (something that can't be done in the Vision 2007) UI.

The output should look like this:

image

The first attempt without any batching

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IVisio = Microsoft.Office.Interop.Visio;
using VisioAutomation;

namespace VisioAutomationSamples
{

    public partial class Demo
    {

        public static void sample3_a()
        {
            IVisio.Application visapp = new Microsoft.Office.Interop.Visio.ApplicationClass();
            IVisio.Document doc = visapp.Documents.Add(new Isotope.Drawing.Size(10, 10));

            IVisio.Page page = doc.Pages[1];

            int num_rows = 15;
            int num_cols = 15;
            Isotope.Drawing.LayoutGrid grid = new Isotope.Drawing.LayoutGrid( page.GetRect(), num_rows,num_cols,false);

            var cells = grid.EnumCells(num_rows, num_cols);
            var shapes = cells.Select(c => page.DrawRectangle(c.rect)).ToList();

            format_shapes_no_batching(page, shapes);
        }

        public static void format_shapes_no_batching( IVisio.Page page, IEnumerable<IVisio.Shape> shapes)
        {
            // no batching
            foreach (IVisio.Shape shape in shapes)
            {
                shape.SetFillPattern(FillPatternType.RadialCenter);
                shape.SetFillForegroundColor(System.Drawing.Color.Red);
                shape.SetFillForegroundTransparency(0);
                shape.SetFillBackgroundColor(System.Drawing.Color.Black);
                shape.SetFillBackgroundTransparency(50);
            }
        }

    }

}

This example uses the VisioAutoExt library so the code is in general a bit simpler than "pure" Visio automation code. If you run the code, you'll notice the delay as each shape is drawn and then an even greater delay as the fill properties are set on each shape.

The second attempt using SetFormulas() and GetFormulas()

Now let's take the performance advice and use SetFormulas() and GetFormulas(). We'll replace format_shapes_no_batching() with this function format_shapes_batching_1()

public static void format_shapes_batching_1(IVisio.Page page, List<IVisio.Shape> shapes)
{

    List<short> shapesheet_info = new List<short>();

    foreach (IVisio.Shape shape in shapes)
    {
        shapesheet_info.Add((short)shape.ID);
        shapesheet_info.Add((short)IVisio.VisSectionIndices.visSectionObject);
        shapesheet_info.Add((short)IVisio.VisRowIndices.visRowFill);
        shapesheet_info.Add((short)IVisio.VisCellIndices.visFillPattern);
        shapesheet_info.Add((short)shape.ID);
        shapesheet_info.Add((short)IVisio.VisSectionIndices.visSectionObject);
        shapesheet_info.Add((short)IVisio.VisRowIndices.visRowFill);
        shapesheet_info.Add((short)IVisio.VisCellIndices.visFillForegnd);
        shapesheet_info.Add((short)shape.ID);
        shapesheet_info.Add((short)IVisio.VisSectionIndices.visSectionObject);
        shapesheet_info.Add((short)IVisio.VisRowIndices.visRowFill);
        shapesheet_info.Add((short)IVisio.VisCellIndices.visFillForegndTrans);
        shapesheet_info.Add((short)shape.ID);
        shapesheet_info.Add((short)IVisio.VisSectionIndices.visSectionObject);
        shapesheet_info.Add((short)IVisio.VisRowIndices.visRowFill);
        shapesheet_info.Add((short)IVisio.VisCellIndices.visFillBkgnd);
        shapesheet_info.Add((short)shape.ID);
        shapesheet_info.Add((short)IVisio.VisSectionIndices.visSectionObject);
        shapesheet_info.Add((short)IVisio.VisRowIndices.visRowFill);
        shapesheet_info.Add((short)IVisio.VisCellIndices.visFillBkgndTrans);
    }

    System.Array shapesheet_info_array = (System.Array)shapesheet_info.ToArray();

    System.Array formula_array;
    page.GetFormulas(ref shapesheet_info_array, out formula_array);

    int i=0;
    foreach (var shape in shapes)
    {
        formula_array.SetValue("40", i++);
        formula_array.SetValue("rgb(255,0,0)", i++);
        formula_array.SetValue( "0%", i++);
        formula_array.SetValue("rgb(0,0,0)", i++);
        formula_array.SetValue("50%", i++);
    }
    short flags = 0;
    page.SetFormulas(ref shapesheet_info_array, ref formula_array, flags);

}

How wonderfully painful. At least it's really fast compared to the first example.

The third example: Using VisBatchFormulaApplier

We can get much simpler code and all the performance benefits if we use the VisBatchFormulaApplier class found in the VisioAutoExt library.

public static void format_shapes_batching_2(IVisio.Page page, IEnumerable<IVisio.Shape> shapes)
{
    VisioAutomation.VisBatchFormulaApplier batch = new VisBatchFormulaApplier();
    foreach (IVisio.Shape shape in shapes)
    {
        batch.SetFormula( shape, VisProps.FillPattern, (int) FillPatternType.RadialCenter );
        batch.SetFormula( shape, VisProps.FillForegroundColor , System.Drawing.Color.Red );
        batch.SetFormula( shape, VisProps.FillForegroundTransparency, 0, VisUnit.Percent);
        batch.SetFormula( shape, VisProps.FillBackgroundColor, System.Drawing.Color.Black);
        batch.SetFormula( shape, VisProps.FillBackgroundTransparency, 50, VisUnit.Percent);

    }
    batch.ApplyFormulas(page);
}

It isn't quite as readable as the first example, but it's much better then the second example, but it is very fast.

VisBatchFormulaApplier will generally make things much simpler.

Some issues:

  • it will only with shapes on the same page
  • you have to write your automation code to create all the objects first and then work use the applier.
  • you have to remember that some properties require you to specify the unit to work (for example VisUnit.Percent for transparencies)

The fourth example: using VisDOM

And now, we use the new experimental VisDOM support. VisDOM is essentially a small set of classes that will automatically draw shapes and apply them in batch. As an extra benefit, things are much more readable and strongly typed than any of the examples above. Here's the full example:

public static void sample3_b()
{

    VisDOM.Document doc = new VisDOM.Document();
    VisDOM.Page page1 = new VisDOM.Page(10, 10);
    doc.Pages.Add(page1);

    int num_rows = 15;
    int num_cols = 15;
    Isotope.Drawing.LayoutGrid grid = new Isotope.Drawing.LayoutGrid(page1.Rect, num_rows, num_cols, false);

    var cells = grid.EnumCells(num_rows, num_cols);
    var shapes = cells.Select(c => page1.DrawRectangle(c.rect)).ToList();

    foreach (VisDOM.Shape shape in shapes)
    {
        shape.FillPattern.Value = FillPatternType.RadialCenter;
        shape.FillForegroundColor.Value = System.Drawing.Color.Red;
        shape.FillBackgroundColor.Value = System.Drawing.Color.Black;
        shape.FillForegroundTransparency.Value = 0;
        shape.FillBackgroundTransparency.Value = 50;

    }

    IVisio.Application visapp = new Microsoft.Office.Interop.Visio.ApplicationClass();
    VisDOM.VisDOMRenderer.RenderToVisio(doc, visapp,false,false);

}

VisDOM constructs a document in memory and then the VisDOMRenderer.RenderToVisio() method does all the Visio magic for batching.

Notice how the properties like FillForegroundTransparency are strongly typed, will work with Intellisense, and don't require knowledge of the VisUnit codes.

Friday
Feb152008

Visio Trick: One-Color and Two-Color Glows

In which shapes will receive a spotlight

Let's suppose you have the network diagram below.

image

And what you'd like to to provide a little extra attention on server A. For example to emphasize it's importance or status. Perhaps we wish to indicate it's in a "warning" state.

You could try setting the fill color ...

image

And that would work. But given the nice 3-point gradient used in the diagram, we want to go the extra mile and make highlight A in a more subtle manner. What we want is this:

image

And now we'll learn how to make a "glow" shape that you can use to highlight other shapes.

First, draw a rectangle, and right-click and select Format / Fill

image

The Fill dialog launches

image

for Pattern select 40 ( a radial fill(

image

Then for Color select Orange

image

Then for Fill Pattern select Orange

image

Then click OK.

image

Enable the shapesheet by going to Tools/Options/Advanced and selecting run in developer mode

image

Right click on Show Shapesheet and in the Fill Format section, change the FillBkgndTrans to 100%.

image

The shape will now look like this:

image

Get rid of the line ...

image

And now the shape will look like this:

image

Now place it above the background but underneath the server A shape and you get:

image

At this point, you've got a nice highlight effect. But we can do better. Leveraging the technique for the 3-point gradients, we are going to make a two color glow.

To help visualize the differences:

image

In the 2-color glow, we have the same orange color, but toward the center it gets progressively brighter to white.

NOTE: the 2-color glow is still 1 shape.

How to achieve this?

First, draw a 1-color glow using the color white.

image

Select that shape and choose Format / Shadow

image

In the Shadow dialog

  • Set Style to 13: Offset, custom
  • Set Color to orange (or whatever you want)
  • Set Pattern to 40
  • Set Pattern Color to orange (or whatever you selected for Color)
  • Set the X Offset & Y Offset to 0 and 0
  • Set Magnification to 170%

And close the Shadow dialog

You should see this:

image

Right click on the shape and select Show Shapesheet

And in the Fill Format section set ShdwBkgndTrans to 100%

image

And you will now have this

image

Which you can then use as a more intense highlight for Server A

image

Notice boundary of the shape.

Keep in mind that the orange glow is beyond the shape's selection area and is thus not selectable. You'll have to click on the "inner" glow. The picture below should make it clear.

image

Also, you can have fun with the glows to make some nice backgrounds.

image

A visio file with all the shapes is attached to this post.

Thursday
Feb072008

Visio 2007 Trick: 3-Point Gradient Fills with Transparency

A Question

How many shapes are required to draw the image below in Visio?

image

The Answer

5 shapes.

No groups, no wierd geometries. Just 5 shapes.

What I want

I want rich, smooth, multi-color gradient fills with independent transparencies for each color.

I could get what I want by drawing multiple shapes. That can work. But, sometimes it's irritating. The shapes have to be perfectly aligned, you'll have some selection wierdness, etc. Simpler to have 1 shape.

What is a  3-Point Gradient Fill with Transparency?

Before I show the steps. Let me give you a clearer understanding of what I mean.

First, here is a conceptual drawing the 3-point I really want to draw:

image

Now, without getting into the explanation, the gradient we'll be able to draw will be more like this:

image

So visualize it forming like this:

image

Implementing 3-Point Gradient Fill with Transparency

We are going to use a combination of the normal shape fills and the SHADOW feature to draw a 3-point gradient.

It's not perfect, it doesn't do everything you'd expect in an application like Illustrator, but I'm sure it's more than what you've seen with Visio so far.

Just so that the goal is clear: here is what we will end-up with:

image

  • ORANGE in the upper left
  • LIGHT BLUE in the upper-right
  • DARK BLUE in along the bottom

Steps

  • Launch Visio
  • Create a new document
  • Draw a rectangle

image

  • Select the rectangle, right-click, and choose Format / Fill...

image

  • The Fill dialog will appear

image

  • Set the colors appropriately (pay attention)
  • Set the Fill / Pattern to 36

image

  • Set Fill / Color and FIll / Pattern Color to the color you want for the upper left (ORANGE)

image

  • Don't touch the transparency for now
  • Set the Shadow / Pattern to 28

image

  • Set Shadow / Color to the color you want along the bottom of the shape (DARK BLUE)
  • Set Shadow / Pattern Color to the color you want at the upper right of the shape (LIGHT BLUE)
  • Click OK
  • Here is what you have now

image

  • Turn on the shape sheet via Tools / Options / Advanced / Run in developer mode and click OK to close the Tools / Options dialog

image

  • Select the shape, right click, and select Show ShapeSheet
  • Find the FIllBkgndTrans cell and change the value from 0% to 100%

image

  • You'll notice the change in the shape once you finish making this change

image

  • close the shapesheet window

image

  • A closer look

image

  • Select the shape
  • Form the menu, select Format / Shadow ...

image

  • The Shadow dialog launches

image

  • Under the Size & Position section, click the black dot in the middle of all the arrows

image

  • A close-up of the black dot to click

image

  • Once you click the dot, the Shadow dialog will look like this

image

  • NOTE: when you click on the black dot, the Shadow / Style changed to "13: Offset, custom" (this is expected)
  • Click OK to close the Shadow dialog
  • What we have created is a single shape with a three-point gradient.

image

  • If you edit the fill and shadow transparencies, you can vary the transparencies as needed

That was hard, how can I create another one?

  • Just duplicate the object and edit the colors in the Fill dialog to get what you want.

What about an existing shape? How can I copy the effect?

  • Use the format painter button

image

How do I create the picture are the beginning of the post?

image

  • Duplicate this shape 4 times for a total of five shapes.
  • Resize and stack three on top of each other and modify the colors via the FIll dialog.
  • Make the other two into vertical columns, set the colors and the transparencies
  • Play with the patterns and transparencies. You'll get some nice combinations!

Summary

  • A single shape that avoids selection weirdness and keep the file size manageable
  • An easy way to change the colors
  • Trivial to generate a different gradients, you only need to use the shapesheet the first time: Create this shape once, save it as a file, if you ever want another gradient just reload, duplicate, change colors via the UI as desired.
Wednesday
Feb062008

Visio 2007 Trick: Transparent Gradients

In which a Visio shape will be harmed ...

The Microsoft Visio Conference 2008 concluded this afternoon. The Visio team presented some exciting things for the next version. One thing I observed is that people have yet to exploit the full power of Vision 2007 with regard to create compelling visuals.

I'm going to spend some time trying to change that.

Today's topic: Transparent Gradients

Before I explain how, here's an example of the desired output: a shape with a gradient fill where the transparency changes from the start of the gradient to the end of the gradient.

What we want will look like this:

image

The shape in the middle is opaque on the left and transparent on the right.

I drew this shape using Xara. By the time, I'm finished here, you'll know how to do it in Visio 2007.

No Cheating

People sometimes employ a technique where a series of tiny shapes each with an gradually increasing amount of transparency are used to create a transparent gradient. That technique may be appropriate in some cases. It's completely unnecessary here and doesn't yield great visual results. I will not be using this technique. Instead, I'll do it "the right way".

The Instructions

  • Launch Visio 2007
  • Create a new drawing via File / New / New Drawing
  • Insert a picture using Insert / Picture / From File ... . The only reason a picture is being inserted is to make it obvious that the gradient changes transparency from the beginning to the end.
  • Resize the picture to fit within the Page

image

  • Draw a rectangle over the picture.

image

  • Create a new drawing via File / New / New Drawing
  • On the rectangle, right-click and select Format / Fill ...
  • The Fill Dialog will launch

image

  • Set the Pattern to 25
  • Set Color to blue
  • Set Pattern Color to red

image

  • Click OK
  • The Fill dialog closes
  • The fill of the rectangle will now have changed

image

  • Select Tools / Options

image

  • The Options dialog will launch

image

  • Navigate to the Advanced tab
  • Check Run in developer mode
  • Click OK
  • The Options dialog will close
  • Right click on the rectangle and select Show ShapeSheet
  • The ShapeSheet will open
  • Navigate to the Fill Format section
  • NOTE: FillBkgndTrans maps to the transparency of the "Pattern Color" in the Fill dialog
  • Set the FillBkgndTrans to 100%.

image

  • At this point it should be clear that the gradient has a beginning and end transparency.
  • NOTE: Do not close the ShapeSheet (nothing bad will happen if you do, it will just make the next step more obvious)
  • Let's look at more closely...

image

  • Withthe ShapeSheet still up, right-lick onthe shape and select Format / Fill...
  • The Fill dialog will launch

image

  • Set both Color and Pattern Color to the white
  • Do NOT change the Transparency value. It will lose the gradient transparency if you do so.

image

  • Click OK
  • The Fill dialog closes

image

  • Close the shapesheet

image

  • Remove the edge for the rectangle

image

image

  • Look what we have created

image

Homework

  • In the Fill dialog, change the fill pattern to achieve these effects

image

Tomorrow

Stay tuned. It gets better.