Callum
Callum

Reputation: 879

Hiding Data from Powerpoint Charts using the MS Office Interop

I'm updating software that cuts up and stitches PowerPoint slides together for end users. The slides contain charts. I need to find a way of hiding the raw chart data from the users that receive the files.

Is there anyway of doing this natively within the PowerPoint interop? I've tried Read-Only but the user can still get at the data.

Upvotes: 0

Views: 952

Answers (3)

Callum
Callum

Reputation: 879

Ok. Here is my final answer to my question. This shows the completed code that can perfectly replicate the slide while keeping the charts from being edited i.e. buy turning it into a .png.

This also solves the previous problem of the placeholders being left.

Hopefully some of this code is helpful to someone trawling the internet like I did.

//Open the slides presentation
var pres = _application.Presentations.Open2007(item.PresentationPath,
    Microsoft.Office.Core.MsoTriState.msoFalse,
    Microsoft.Office.Core.MsoTriState.msoFalse,
    Microsoft.Office.Core.MsoTriState.msoFalse,
    Microsoft.Office.Core.MsoTriState.msoFalse);

 //For slide ranges
 foreach (var i in range)
 {
     //Get the old slide
     var oldSlide = pres.Slides[i];
     oldSlide.Copy();

     //Paste the slide into the new presentation
     var newSlide = newPresentation.Slides.Paste(totalSlides + 1);
     newSlide.Design = oldSlide.Design;
     newSlide.ColorScheme = oldSlide.ColorScheme;

     /* The shapes haven't retained their content because we are not in slide...
     view because there is no window. */

     //Delete all the shapes that were just pasted in because of the slide paste.
     for (int k = newSlide.Shapes.Count; k > 0; k--)
     {
         newSlide.Shapes[k].Delete();
     }

     //Put in our shapes
     //Loop forwards, because we arn't editing the list and forward is required to
     //maintain the zorder we want on some slides.
     for (int j = 1; j <= oldSlide.Shapes.Count; j++)
     {
         var oldShape = oldSlide.Shapes[j];
         oldShape.Copy();

         //Paste Put it where it should be on the page
         /* This is a special case where the client have put textboxes in the
         Powerpoint and rotated throwing off the position, so we need treat as rotated
         shapes to make it right. */
         if (oldShape.HasTextFrame == MsoTriState.msoTrue && Math.Abs(oldShape.Rotation) > 0)
         {
             //Paste as a shape because it's a more complex object
             //set ALL THE PROPERTIES just in case.
             var newShape = newSlide.Shapes.PasteSpecial(PpPasteDataType.ppPasteShape);
             newShape.Rotation = oldShape.Rotation;
             newShape.Top = oldShape.Top;
             newShape.Left = oldShape.Left;
             newShape.TextFrame.Orientation = oldShape.TextFrame.Orientation;
             newShape.TextFrame.WordWrap = oldShape.TextFrame.WordWrap;
             newShape.TextFrame.VerticalAnchor = oldShape.TextFrame.VerticalAnchor;
         }
         else // Act normally
         {
             //Paste the old shape into the new slide as an image to ENSURE FORMATTING
             var newShape = newSlide.Shapes.PasteSpecial(PpPasteDataType.ppPastePNG);
             newShape.Top = oldShape.Top;
             newShape.Left = oldShape.Left;
         }
     }

     totalSlides += ((item.EndIndex - item.StartIndex) + 1);

     pres.Close();
 }

After the new presentation has been compiled, you must delete all placeholders.

//Loop through all slides
foreach (Slide exportSlide in newPresentation.Slides)
{
    //Delete the placeholders
    for (int i = exportSlide.Shapes.Placeholders.Count; i > 0; i--)
    {
       exportSlide.Shapes.Placeholders[i].Delete();
    }
}

Upvotes: 2

Callum
Callum

Reputation: 879

Using the principals of Steve's code I've created a bespoke one for my use. As I am interacting with PowerPoint as a Component Service, I don't have an ActiveWindow or anything.

//Loop through all slides
foreach (Slide exportSlide in newPresentation.Slides)
{
    //Loop through all shapes
    foreach (Shape shape in exportSlide.Shapes)
    {
        //If the shape is a chart
        if (shape.HasChart == MsoTriState.msoTrue)
        {
            //Copy to clipboard
            shape.Copy();

            //Paste as an image
            var newShape = exportSlide.Shapes.PasteSpecial(PpPasteDataType.ppPastePNG);

            //Move back to chart position
            newShape.Left = shape.Left;
            newShape.Top = shape.Top;

            //Delete the original shape
            shape.Delete();
        }
    }
}

This works fine for replacing the charts with images (no data at all). The only issue now is that because the slides where created with a layout containing chart, when you open the slide in Powerpoint the GUI displays an "Insert Chart" box. I've tried:

exportSlide.Layout = PpSlideLayout.ppLayoutBlank;

However because of my clients custom templates this is not blank, so it's not usable.

Upvotes: 0

Steve Rindsberg
Steve Rindsberg

Reputation: 14809

VBA to ungroup a chart (in order to remove any connection to the original data)

Sub UngroupAChart()

    Dim oSh As Shape
    Dim oNewSh As Shape
    Dim oNewShapes As ShapeRange
    Dim oSl As Slide

    ' for demo purposes, use the currently selected
    ' shape; up to tester to select a chart
    Set oSh = ActiveWindow.Selection.ShapeRange(1)

    ' Get a reference to the shape's parent slide
    ' We'll need it later
    Set oSl = oSh.Parent

    ' put the shape on the clipboard
    oSh.Copy

    Set oNewSh = oSl.Shapes.PasteSpecial(ppPasteEnhancedMetafile)(1)

    oNewSh.Ungroup

    ' once you're done testing, delete the original chart
    'oSh.Delete

End Sub

Upvotes: 0

Related Questions