Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Create PowerPoint slides from Silverlight by taking snaps of pages

0.00/5 (No votes)
7 Jul 2011 1  
This article explains how to take a snapshot of a Silverlight page and convert it into a PowerPoint slide.

Introduction

In this article, I will explain how a Silverlight application can be used to create slides in a Microsoft PowerPoint file by taking various snaps of the Silverlight page. I was motivated to write this because I did not see a solution for this in the internet when I wanted to create PowerPoint slides from a Silverlight project, but did find many results on using Silverlight in PowerPoint.

How it works

The solution has three projects:

  1. PowerpointService (a WCF Service project)
  2. SilverlightToPowerpoint (a Silverlight project)
  3. SilverlightToPowerpoint.Web (a web application hosting the Silverlight project)

The Silverlight project makes a call to the WCF Service by sending snaps of pages (byte array as image) with a title. In return, WCF creates PowerPoint slides and sends them back as a byte array. The Silverlight app prompts the Save dialog box to the user to decide where to save the file and saves the byte array as a Microsoft PowerPoint file.

The WCF Service becomes necessary because we want to manipulate a file which is not supported in Silverlight as it runs in the client's browser and accessing a file is denied. (I hear some of you say "Hey! there is Isolated Storage", but for this to work, that is not an ideal solution.)

Third party libraries

Third party libraries are used to take a snap of Silverlight and create slides in Microsoft PowerPoint.

For taking a snap of Silverlight, the following libraries are used in the Silverlight project:

  1. ImageTools.dll
  2. ImageTools.IO.Png.dll
  3. ICSharpCode.SharpZipLib.Silverlight.dll

These are free libraries and can be downloaded from CodePlex.

For creating slides, DocumentFormat.OpenXml.dll is used in the WCF Service project. This library can be downloaded from OpenXmlDeveloper.

Note: You really do not need to download these libraries as they are part of the solution attached here. The links are for your further reference only.

Screenshots

In the Silverlight project, I have used three images of three cars, but these images are stored in the web project under the ClientBin->Images folder to reduce the size of the Silverlight project.

The first page when you run the Silverlight app is:

web_1.PNG

After selecting a car:

web_2.PNG

After adding to the slide collection (by default, the car name is shown as the title, but this can be changed):

web_3.PNG

Taking multiple cars (in the code, I've set the maximum as 20, but you can change this):

web_4.PNG

Save the slides into a PowerPoint file:

web_5.PNG

Here is the confirmation:

web_6.PNG

...And the PowerPoint file:

ppt.PNG

Code walkthrough

Silverlight project

The Silverlight project has a user control file MainPage.xaml where all the UI design is written. Though the .xaml is self-explanatory and easy to understand for any Silverlight developer, the below markup code requires special explanation:

<stackpanel name="spSlide" grid.row="1">
   <img name="imgCar" stretch="UniformToFill" />
</stackpanel>

This StackPanel is very important as, in the code, I convert the StackPanel and its child controls to an image and passes it to the WCF Service. Here I have just used an image, but if you want to add more controls, you must add them under the StackPanel. Of course, in the code I have used a StackPanel, but you can use any other container control for that matter.

This is the code that gets executed when you click Add to Slide.

if (cbCars.SelectedValue == null) return; //No item is chosen

// comment this line if you want allow unlimited
// number of slides. or update the number
if (_slides.Count > 20)
    throw new Exception("Maximum slides (20) added already!");

//convert the stackpanel and its controls as image and store it in memory
WriteableBitmap image = new WriteableBitmap(spSlide, new ScaleTransform());
try
{
    PptSlide slide = new PptSlide();
    byte[] binaryData = GetImageBufferAsPng(image);
    BitmapImage bmpImage = new BitmapImage();
    Stream stream = new MemoryStream(binaryData, 0, binaryData.Length);
    bmpImage.SetSource(stream);
    slide.Image = bmpImage;
    slide.ImageBinary = binaryData;
    slide.ImageTitle = string.Format("{0}_{1}", 
      ((ComboBoxItem)cbCars.SelectedItem).Content, _slides.Count + 1);
    _slides.Add(slide);
    tabSlides.Header = string.Format("Slides ({0})", _slides.Count);
}
catch (Exception ex)
{
    ShowErrorAlert(string.Format(
      "Error while adding to slide collection:\n{0}", ex.Message));
}

This code uses the Image libraries to convert the StackPanel and its controls to a PNG image and adds it to the internal observable collection which is the source of the DataGrid.

The code gets executed when you click Save as PowerPoint:

if (_slides.Count == 0) return;
try
{
    var service = new PowerpointClient();
    var slides = new List<powerpointimage>();
    foreach (var item in _slides)
    {
        var slide = new PowerpointImage();
        slide.ByteArray = item.ImageBinary;
        slide.Title = item.ImageTitle;
        slides.Add(slide);
    }

    SaveFileDialog = new SaveFileDialog();
    SaveFileDialog.DefaultExt = "Powerpoint 2007 (*.pptx)|*.pptx";
    SaveFileDialog.Filter = "Powerpoint 2007 (*.pptx)|*.pptx";
    SaveFileDialog.FilterIndex = 1;
    if (SaveFileDialog.ShowDialog() == true)
    {
        service.PowerpointAsByteCompleted += 
                service_PowerpointAsByteCompleted;
        service.PowerpointAsByteAsync(slides);
        tbStatus.Text = "Saving file...";
    }

}
catch (Exception ex)
{
    ShowErrorAlert(string.Format(
      "Error while getting powerpoint file:\n{0}", ex.Message));
}

...on completion of the WCF service call:

void service_PowerpointAsByteCompleted(object sender, 
             PowerpointAsByteCompletedEventArgs e)
{
    if (e.Error != null)
    {
        ShowErrorAlert(string.Format(
          "Error while getting powerpoint file:\n{0}", 
          e.Error.Message));
        return;
    }
    if (!string.IsNullOrWhiteSpace(e.Result.ErrorMessage))
    {
        ShowErrorAlert(e.Result.ErrorMessage);
        return;
    }

    byte[] pptByte = e.Result.PptByte;

    if (pptByte == null)
    {
        ShowErrorAlert("Empty powerpoint file is returned from server.");
        return;
    }

    using (System.IO.Stream stream = SaveFileDialog.OpenFile())
    {
        stream.Write(pptByte, 0, pptByte.Length);
        tbStatus.Text = "File saved: " + SaveFileDialog.SafeFileName;
    }
}

WCF project

This project offers only one method PowerpointAsByte. And the service interface IPowerpoint:

[ServiceContract]
public interface IPowerpoint
{
    /// <summary>
    /// Converts the images from images collection to powerpoint
    /// slides and return the powerpoint file as byte array
    /// </summary>
    /// <param name="slides" />
    /// <returns />
    [OperationContract]
    PowerpointAsByteResult PowerpointAsByte(IList<powerpointimage> images);
}

The service class Powerpoint:

public class Powerpoint : IPowerpoint
{

    /// <summary>
    /// Method accepts collection of images and convert them as powerpoint slides.
    /// </summary>
    /// <param name="slides" />
    /// <returns>byte array of powerpoint file</returns>
    public PowerpointAsByteResult PowerpointAsByte(IList<powerpointimage> slides)
    {

        PowerpointAsByteResult result = new PowerpointAsByteResult();
        //Don't throw any exception across wire.
        try
        {
            result.PptByte = (new PowerpointHelper()).GetPowerpointAsByte(slides);
        }
        catch (Exception ex)
        {
            result.ErrorMessage = string.Format(
              "Error while converting images to powerpoint:\n{0}",ex.Message);
        }
        return result;
    }
}

Class diagram of the WCF Service

PowerpointService.png

Somethings to remember before working with the code

  • You need Visual Studio 2010 to open this code.
  • When you run the project, you may receive an error message when making a WCF call. This is because the address of the WCF Service may change in your development server. So first run the WCF Service and take the address and update it in the ServiceReferences.ClientConfig file of the Silverlight project.
  • If you are dealing with images of huge size, then you need to increase the upload size limit in the web.config file. Have a look at this link: http://forums.silverlight.net/forums/p/65327/433543.aspx.

Conclusion

I believe this article will help at least a few people who need this functionality. Please test this code and post your comments on any issues/suggestions.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here