Features PPPcreator
- Purpose: Automation of PowerPoint.
- This C# (Visual Studio 2003) project creates PowerPoint presentations based on XML templates which are filled with dynamic data.
- The documents are created from scratch. You can also add new slides into an existing presentation.
- You can use this project to create Reports on a weekly or monthly basis which display content from a database in a PowerPoint presentation.
- You can insert dynamic text, tables and pictures,... into the PPP document.
- The created documents can be played on PowerPoint 2002 up to 2007. They also play on PowerPoint 97 with restrictions.
Features PPPanalyzer
The Analyzer allows to write all properties of all Shapes in an existing PowerPoint Presentation into XML files.
PowerPoint 2003 is Full of Bugs
My first experiments using PowerPoint 2003 failed because PP 2003 is !FULL! of ugly bugs.
Example
You set the width of a border of a table cell. No problem. Afterwards you try to set the color of the same border: result = Exception 0x800A01A8
Then you try to do it in the reverse order: First set the color. No problem. Then set the width: result = Exception 0x800A01A8. This exception has no documentation in MSDN and in the internet you find hundreds of people with the same problem but no solution.
There were a lot of other things which did not work in PP 2003 and all had one thing in common: they were extremely strange and did not make any sense.
I wasted two entire days searching for a workaround: without success. Finally I found the solution: Using PowerPoint 2007 which does not have these bugs anymore.
When I started the project, I didn't want to use PowerPoint 2007 because I wanted to create PPP documents which can also be played on PP 2003. But then I found that my documents created on PP 2007 will also play on PP 2002 and PP 2003 without problems.
IMPORTANT: Read in the last chapter what you have to install additionally to PP 2007!
The PowerPointCreator Project
This project demonstrates the creation of a Sales Report of a fictitious company "Ipsum Colors Inc." which sells paints.
The following animation shows a PowerPoint Presentation consisting of 5 slides which have been created from scratch with PowerPointCreator:
Using the Class PPPcreator
Let's have a look at how to create the first page (the start slide):
string s_TemplatePath = Directory.GetCurrentDirectory() + "\\Templates";
PPPcreator i_PppCreator = new PPPcreator(s_TemplatePath, true);
Hashtable i_Replacements = new Hashtable();
i_Replacements["CurrentDate"] = DateTime.Today.ToString("dd. MMMM yyyy");
i_PppCreator.InsertTemplateSlide(-1, null, "Template_StartSlide.xml", i_Replacements);
It's really that simple! These 5 lines of code create an entire PowerPoint slide! You specify an XML template "Template_StartSlide.xml" and a hashtable with replacements for all dynamic data which is to be inserted into the template (here the current date).
The second parameter of the PPPcreator
constructor (true) specifies the creation mode.
true -> PowerPoint opens and you see the creation process "live" on the screen as if you would add all the elements manually.
false -> PowerPoint runs minimized in the taskbar without a visible window. This mode is faster.
You can also insert new slides into an already existing presentation:
i_PppCreator.LoadPresentation (@"C:\My Documents\....\SalesReport.ppt");
i_PppCreator.InsertTemplateSlide(5, "Template_Background.pot", "Template_XYZ.xml",
i_Replacements);
The first parameter of InsertTemplateSlide()
specifies the zero based insert position of the new slide.
- 5 -> insert before the 5th slide
- -1 -> append behind the last slide
The second parameter of InsertTemplateSlide()
specifies an optional PowerPoint Template. (*.pot)
From this SlideMaster template only the basic layout (like header and footer) will be loaded, not the content!
The XML Templates
The structure of the XML templates is very similar to HTML files. The templates completely define how the resulting Presentation will look. They contain two main tags:
- Styles
- Shapes
The Shapes tag contains all PowerPoint Shapes you want to insert into the document like TextBoxes, Tables, Pictures or Lines.
The Styles tag contains definitions of how these elements will look like, for example their color and font size.
ATTENTION:
- All Tags and Attributes in the XML file are CASE SENSITIVE!
- All Values in the XML file MUST be enclosed in quotation marks!
The XML - Shapes Section
<Shapes>
<Textbox Top="60" Left="120" Width="580" Style="TitleBox" Name="Title">
Sales Report</Textbox>
<Picture Top="155" Left="120" Width="250" Height="195">Company_Logo.gif</Picture>
<Table Top="75" Left="45" ColumnWidths="100,120,100,150" MaxHeight="405">
<Row Height="20">
<Cell Style="CellCommon,CellDark">First Cell</Cell>
<Cell Style="CellCommon,CellBright">Second Cell</Cell>
<Cell Style="CellCommon,CellBright" ColSpan="2">Third and Fourth Cell</Cell>
</Row>
</Table>
<Line BeginX="120" BeginY="465" EndX="120" EndY="494" Style="GreenLine" />
</Shapes>
All Shapes use absolute positioning, so the attributes Top
and Left
are mandatory. The Shapes are drawn in the order in which they appear in the XML file. So if you want to put text on top of a picture you have to define the picture first.
Every Shape can have an optional Name
attribute. This name is similar to an ID or Name tag in HTML. It is stored invisible in the PPP document and may be useful to locate a Shape if you want to modify the document later.
Textboxes
You don't need to specify the Height
attribute for a Textbox
as the height depends on the text which you put into the box. The height is only required if the textbox
has a visible border or a background color and is bigger than the text.
Pictures
All Pictures are loaded from the Template folder which you have specified in the constructor of PPPcreator
.
Tables
The Table in the above example has 4 columns whose widths (100,120,100,150) you specify in the attribute ColumnWidths
.
The Height
attribute for table rows is optional. If it is missing, the row's content will define its height. Cells can be combined with their right neighbour using the ColSpan
attribute.
As the cells in the above example show, you can specify multiple styles
separated by a comma.
In the Styles section of the XML file (see below):
CellCommon
contains definitions for all cells. CellBright
contains only the color definitions for the white cells. CellDark
contains only the color definitions for the blue cells.
The MaxHeight
attribute for the table defines when its content will be broken onto the next slide. PowerPoint does not do that automatically (like Word does). If the table becomes too high, PowerPointCreator removes as many words from the last table cell as is required to make the text fit on that slide. After that a new slide is appended which receives the rest of the table. To optically show the continuation of a table, it's border becomes dashed:
The XML - Styles Section
<Styles>
<TitleBox Shape.TextFrame.MarginLeft="10"
Shape.TextFrame.TextRange.Font.Name="Arial"
Shape.TextFrame.TextRange.Font.Size="22"
Shape.TextFrame.TextRange.Font.Bold="true"
Shape.TextFrame.TextRange.Font.Color.RGB="#373C71"
Shape.TextFrame.TextRange.ParagraphFormat.Alignment="ppAlignCenter"
/>
<CellCommon Borders.ppBorderTop.Weight="1"
Borders.ppBorderBottom.Weight="1"
Borders.ppBorderLeft.Weight="1"
Borders.ppBorderRight.Weight="1"
Borders.ppBorderLeft.ForeColor.RGB="#373C71"
Borders.ppBorderRight.ForeColor.RGB="#373C71"
Borders.ppBorderBottom.ForeColor.RGB="#373C71"
Shape.TextFrame.TextRange.Font.Name="Arial"
Shape.TextFrame.TextRange.Font.Size="10"
Shape.Fill.Solid="true"
/>
<CellDark Borders.ppBorderTop.ForeColor.RGB="#FFFFFF"
Shape.TextFrame.TextRange.Font.Bold="true"
Shape.TextFrame.TextRange.Font.Color.RGB="#FFFFFF"
Shape.Fill.ForeColor.RGB="#373C71"
/>
etc....
</Shape>
All entries have exactly the same name as the corresponding objects in the namespace PowerPoint
.
Don't try to abbreviate these attributes!!
For example: A cell may specify border settings (LineFormat
), also a row and a Line use the same properties. There are multiple objects which allow you to specify a ForeColor
or BackColor
. You will run into a big confusion if you try to simplify these long properties!
If you need additional properties which are not yet supported by the PPPcreator
class, you have to add them on your own. I would have liked to use Reflection to set the properties but this is not possible as Microsoft.Office.Interop.PowerPoint
is a COM object which does not support Reflection. So each and every property must be set separately in a long switch()
statement.
Table Cell Borders
When you define the cell borders, you have to be careful. For each cell you can specify width, color, etc.. for it's top border, bottom border, left border and right border separately. But each cell shares its borders with its neighbours...
...and as a table is painted from top to bottom, the settings of the bottom border of a cell will be overwritten with the settings of the top border of the following row.
To obtain a table as you see in this image the cell C must define a top border which is white, but Cell B must define a top border which is blue, while the bottom border of all Cells A-C may be defined as ANYthing which will be ignored as the next row overwrites it with its own settings!
The bottom border will ONLY be of importance in the very last row.
The right border will ONLY be of importance in the very last column.
For all other cells only the top and the left border have importance.
If you study the file "Template_Table.xml" thoroughly, you will understand how it works:
- The style
CellDark
defines a white top border. - The style
CellTopDark
defines a blue top border. - In the attribute
Style="CellDark,CellTopDark"
the order of the styles matters!
That means that the TopBorder
color in CellTopDark
will overwrite the definition in CellDark
!
Cell B:
<Cell Style="CellCommon,CellDark,CellTopDark">Priority</Cell>
Cell C:
<Cell Style="CellCommon,CellDark">Finished</Cell>
The Replacements
The Replacements make the templates really dynamic. To insert a dynamic title into a PP slide write in the XML file:
<Shapes>
<Textbox Top="60" Left="120" Width="580" Style="TitleBox">%Title%</Textbox>
</Shapes>
The data to be inserted may come from a database, you can read it from an XML file, or get it from wherever you like. You have to store it into a hashtable and pass it to PPPcreator
.
Hashtable i_Replacements = new Hashtable();
i_Replacements["Title"] = "Sales Report";
i_PppCreator.InsertTemplateSlide(-1, null, "Template_Table.xml", i_Replacements);
You can do the same with text in table cells or picture files.
Also, the values of Attributes can be defined dynamically. For example, if your template defines different title styles, you can decide at runtime which style to use for the title:
<Shapes>
<Textbox Top="60" Left="120" Width="580" Style="%TitleStyle%">Sales Report</Textbox>
</Shapes>
Formatted Text
Another feature is the ability to write formatted text into a PowerPoint TextBox
or TableCell
.
Option 1
The Replacements may contain HTML code if it is enclosed between <HTML>
and </HTML>
:
i_Replacements["Summary"] = "<Html><b><big>Lorem ipsum</big></b></Html>";
Option 2
You put the HTML code directly into the XML file:
<Textbox Top="60" Left="90" Width="580" Style="TitleBox" Name="Title">
<Html>
Sales Report <BR />
<Font Color="#000088">Business Statistic</Font>
<small>half-way 2008</small>
</Html>
</Textbox>
IMPORTANT
- XML is much stricter than HTML: EVERY Tag must be closed. (also
<BR>
, <LI>
, etc.) - XML is case sensitive: you cannot close a
<DIV>
with a </div>
- Obviously not all HTML tags are supported. Study the class
TextRangeFormat
for allowed tags.
Dynamic Lists
And what if I want to create a list with a variable count of rows (for example from a database)? No problem!
Write in the XML file:
<Shapes>
<Table Top="100" Left="65" ColumnWidths="360,77,77,77" MaxHeight="405">
<Row Height="15" DataSource="SalesData">
<Cell Style="xyz">%SalesData#Product%</Cell>
<Cell Style="xyz">%SalesData#Sold%</Cell>
<Cell Style="xyz">%SalesData#Profit%</Cell>
<Cell Style="xyz">%SalesData#Percent%</Cell>
</Row>
</Table>
</Shapes>
The row will be repeated as often as your DataSource
has row entries. The replacements must be of the form %DataSourceName#ColumnName%
. In the C# code, write:
DataSource i_SalesData = new DataSource(new string[]{ "Product", "Sold", "Profit",
"Percent" });
i_SalesData.AddRow(new string[]{"LA553 - Gallon Ultra Premium Flat Wall Paint",
"353.912", "$3.267.000", "25,7%"});
i_SalesData.AddRow(new string[]{"IN965 - Interior Wall Paint 10 litre Acryl",
"270.733", "$2.332.000", "22,4%"});
etc...
Hashtable i_Replacements = new Hashtable();
i_Replacements["SalesData"] = i_SalesData;
i_PppCreator.InsertTemplateSlide(-1, "Template_Background.pot",
"Template_DynamicList.xml", i_Replacements);
The DataSource
class is a special class designed to hold table data for dynamic list creation. The names of the columns are defined in the DataSource
constructor and must obviously have the same names as the XML entries.
Above you will find an example of everything I've explained in the PowerPointCreator project.
The Analyzer
The second part of the application is the PowerPoint Analyzer.
You specify any existing PPP or PPS file and the Analyzer creates an XML file for each Slide it finds in it.
There are hundreds of properties which a Shape can have.
To avoid an endless XML file the analyzer has built in intelligence:
- It does not write values if they are the default properties.
For example after adding a new TextBox
, it has several default properties like Shape.Fill.RotateWithObject="msoFalse"
.
These defaults are not written into the generated XML file.
PowerPointCreator uses the file DefaultShapes.xml to check if a property has its default value.
The file DefaultShapes.xml must be created once from a real PowerPoint file which contains the default Shapes: the file DefaultShapes.ppt. You don't have to care about this as this is done. - In a second analysis, the analyzer checks all
TextBox
es, all TableCell
s, etc... for their common properties and generates an XML node under <styles>
which it stores the common properties. So they are not written 50 times for 50 table cells. - If a property cannot be read or written (
PropertyInfo.CanWrite=false
), it is skipped. There are several Shape properties which are read-only. It does not make sense to store them in the XML file as they later cannot be assigned in PPPcreator. - There is a lot of ambiguous stuff in a Shape like
Shape.TextFrame
and Shape.TextFrame2
which is also eliminated.
The result is a handy XML file which can be used as input for the Creator.
ATTENTION
Due to the incredible complexity of the PowerPoint API, you must be aware that the generated XML file will probably require manual editing.
Restrictions
Analyzer: It analyzes ANY PowerPoint presentation using its tricky Pseudo-Refection.
Creator: In the current version 5.0 ready to generate Tables, Lines, TextBoxes and Pictures.
But AutoShapes and Groups are premature / not implemented.
PowerPoint is very slow. When you create a presentation "live", you will see how it draws every single table cell and prints the text.
PowerPoint is quite primitive (like the entire Office package). For example, it does not allow you to put a picture into a table cell. This is not possible. Also you cannot append a table row to the end of a table. If the previous row has merged cells (uses ColSpan
) the new row would merge the same cells although you never did program that. For all these things PPPcreator
has workarounds built in.
A documentation for the PowerPoint API does not exist. What you find in the MSDN is ridiculous. You have to find out everything by trial and error.
Some functions which exist in the PowerPoint API are not implemented. (for example, Slide.Shapes.AddDiagram(...)
).
The Helper Grid
All PowerPoint presentations use the odd coordinate system of 720 x 540 pixels. To ease the definition of coordinates when creating the XML file, PowerPointCreator draws a helper grid when compiled in Debug mode. Every 20 pixels, a dashed line is drawn and every 100 units a solid line:
Source Code
You will find a very clean and well structured C# source code with plenty of comments, written by a very experienced programmer. The code is reusable, so you can easily put it into your own projects:
- The class
PPPcreator
encapsulates all the PowerPoint creation stuff - The class
DataSource
stores Dynamic List data - The class
XML
eases XML file management - The class
Functions
contains a bunch of helper functions
Requirements
To compile or run this project:
Obviously you must have PowerPoint 2007 installed.
- IMPORTANT: in the Office 2007 Installer under "Shared Office Components", you MUST install "Visual Basic for Applications". If this is not installed, you have a severe problem: When creating a presentation, you will get an exception with the most stupid error message Microsoft ever has created: "Unspecified Error". You will search hours and hours to find out why the program runs on one PC but not on the other PC!!
VB is required although this is a C# project!!
The ".NET Programmability Support" which you find in the Office 2007 installer under "PowerPoint" installs the files Office.dll and Microsoft.Office.Interop.PowerPoint.dll into the Global Assembly Cache.
But you don't need to install this because I have put these tiny DLLs into the same folder as the EXE and compiled the EXE to run with these 'local' DLLs if they are not found in the GAC. So the program will also run on a computer where only PowerPoint 2007 is installed without these DLLs in the GAC. This avoids crashes, unnecessary problems, frustrated users and a lot of work for the support.
Future Versions
The current version 2.0 contains a lot of useful functionality. Probably future versions, which will be published on CodeProject, will contain more functionality like dynamic generation of diagrams, etc..
History
- 28th August, 2008: Initial post
- 18th December, 2008: Article updated
- 19th January, 2009: Source updated