Tag-Archive for ◊ PowerPoint ◊

Author:
Tuesday, February 02nd, 2010

Anyone who has tried their hand at OpenXml programming would concur that its a bit daunting at start with. Anyone tried their hands at making charts in OpenXml would agree even more. There are, of course, several code snippets on the internet to help you out. However, I didn’t find any that would help me with simple charts in PowerPoint. And the one I found for Excel, for instance, was too complicated to be used and involved creating a chart from the scratch.

All I wanted was a simple way to put my data into in existing bar chart in a powerpoint slide. That way I can give the user the freedom to have any formatting options that he wishes for the chart and only the data will be filled in by my program.

You’ll see the code snippet below. Basically I delete the existing “BarChartSeries” and insert my own with my data. I don’t touch any other part of the Chart leaving the formatting intact.

It may not work for all your scenarios but its a simple thing to start with. Note that I’m using Microsoft’s OpenXml SDK.

private void button1_Click(object sender, EventArgs e)
{
Dictionary<string, int> values = new Dictionary<string, int>();
values.Add("hello", 20);
values.Add("world", 30);
values.Add("test", 40);
values.Add("data", 50);

PresentationDocument presentationDoc = PresentationDocument.Open("c:\\p2.pptx", true);
SlidePart slidePart = presentationDoc.PresentationPart.SlideParts.First();
ChartPart chartPart = slidePart.ChartParts.First();

ReplaceValuesInChartInSlide(chartPart, values, "my category");
presentationDoc.PresentationPart.Presentation.Save();
presentationDoc.Close();
}

public static void ReplaceValuesInChartInSlide(ChartPart chartPart, Dictionary<string, int> data, string categoryTitle)
{
ChartSpace chartSpace = chartPart.ChartSpace;
List<int> indexOfUsedItems = new List<int>();

BarChart barChart = chartSpace.Descendants<BarChart>().FirstOrDefault();

barChart.RemoveAllChildren<BarChartSeries>();
uint i = 0;
foreach (string key in data.Keys)
{
BarChartSeries barChartSeries = barChart.AppendChild<BarChartSeries>(new BarChartSeries(new Index() { Val = new UInt32Value(i) },
new Order() { Val = new UInt32Value(i) },
new SeriesText(new NumericValue() { Text = key })));

StringLiteral strLit = barChartSeries.AppendChild<CategoryAxisData>(new CategoryAxisData()).AppendChild<StringLiteral>(new StringLiteral());
strLit.Append(new PointCount() { Val = new UInt32Value(1U) });
strLit.AppendChild<StringPoint>(new StringPoint() { Index = new UInt32Value(0U) }).Append(new NumericValue(categoryTitle));

NumberLiteral numLit = barChartSeries.AppendChild<DocumentFormat.OpenXml.Drawing.Charts.Values>(
new DocumentFormat.OpenXml.Drawing.Charts.Values()).AppendChild<NumberLiteral>(new NumberLiteral());
numLit.Append(new FormatCode("General"));
numLit.Append(new PointCount() { Val = new UInt32Value(1U) });
numLit.AppendChild<NumericPoint>(new NumericPoint() { Index = new UInt32Value(0u) }).Append(new NumericValue(data[key].ToString()));

i++;
}

chartSpace.Save();
}

The p2.pptx in the code simply contained a slide with a barchart.

Note that a chart in powerpoint has its associated data in an embedded excel file. In this sample we haven’t touched that excel file and hence haven’t changed that data. Hence, although your chart will render new data correctly, it may not show the new data in that excel (it appears when click “Edit Data” for the chart in PowerPoint). Anyways, this simple code worked for us cos our primary aim was to render the graph.

Author:
Thursday, October 01st, 2009

With Office 2007, Microsoft introduced a new document format called OpenXml. Its an xml based format for storing Mirosoft office documents. Technically, an Office 2007 file (pptx, docx etc) is simply a zip file containing a set of xml files and related content. You can actually, rename it to .zip and extract its contents! Although the idea is novel, the xml format itself is a little complex to work with. Microsoft does provide a OpenXML SDK to make life a little easier for programmers.

However, you’ll still need to learn a lot of tricks to get things done in OpenXml. I’ll demonstrate one such common task here. If you’re working with an OpenXml PowerPoint (pptx) file, one of the first things you may want to learn is how to clone a slide. i.e. make a copy of a slide along with all its contents. There are several sites that’ll give you code to Clone a slide. Here’s a good one which I’m using as a reference for my code: http://blogs.msdn.com/brian_jones/archive/2009/08/13/adding-repeating-data-to-powerpoint.aspx

However, I didn’t find any site that has a code which works with charts. When you clone a slide, all its parts should also be cloned for it to work properly. For eg. images are stored in a property called ImagePart. If you want images from source slide to appear in the cloned slide, you should copy the ImagePart too.

Similary charts are stored in a ChartPart. However, charts are more tricky as they refer to an embedded excel sheet that contains chart data. You’ll need to copy this excel sheet too. The following function has the sample code for charts and the embedded excel. It also has code to clone images to help you compare the differences:

public static SlidePart CloneSlidePartWithImagesAndCharts(PresentationPart presentationPart, SlidePart slideTemplate)
{
int i = presentationPart.SlideParts.Count();
//Create a new slide part in the presentation.
SlidePart newSlidePart = presentationPart.AddNewPart<SlidePart>(“newSlide” + i);
i++;
//Add the source slide content into the new slide.
newSlidePart.FeedData(slideTemplate.GetStream(FileMode.Open));
//Make sure the new slide references the proper slide layout.
newSlidePart.AddPart(slideTemplate.SlideLayoutPart, slideTemplate.GetIdOfPart(slideTemplate.SlideLayoutPart));

// copy the image parts
foreach (ImagePart ipart in slideTemplate.ImageParts)
{
ImagePart newipart = newSlidePart.AddImagePart(ipart.ContentType, slideTemplate.GetIdOfPart(ipart));
newipart.FeedData(ipart.GetStream());
}

// copy the chart parts
foreach (ChartPart cpart in slideTemplate.ChartParts)
{
ChartPart newcpart = newSlidePart.AddNewPart<ChartPart>(slideTemplate.GetIdOfPart(cpart));
newcpart.FeedData(cpart.GetStream());
// copy the embedded excel file
EmbeddedPackagePart epart = newcpart.AddEmbeddedPackagePart(cpart.EmbeddedPackagePart.ContentType);
epart.FeedData(cpart.EmbeddedPackagePart.GetStream());
// link the excel to the chart
(((newcpart.ChartSpace)).ExternalData).Id = newcpart.GetIdOfPart(epart);
newcpart.ChartSpace.Save();
}

//Get the list of slide ids.
SlideIdList slideIdList = presentationPart.Presentation.SlideIdList;

//Deternmine where to add the next slide (find max number of slides).
uint maxSlideId = 1;
SlideId prevSlideId = null;
foreach (SlideId slideId in slideIdList.ChildElements)
{
if (slideId.Id > maxSlideId)
{
maxSlideId = slideId.Id;
prevSlideId = slideId;
}
}
maxSlideId++;
//Add the new slide at the end of the deck.
SlideId newSlideId = slideIdList.InsertAfter(new SlideId(), prevSlideId);
//Make sure the id and relid are set appropriately.
newSlideId.Id = maxSlideId;
newSlideId.RelationshipId = presentationPart.GetIdOfPart(newSlidePart);
newSlidePart.Slide.Save();
return newSlidePart;
}

Category: .Net | Tags: , , , , , ,  | 7 Comments