Solved

In PowerPoint openxml, add or subtract a text box outline style

Posted on 2015-02-02
4
352 Views
Last Modified: 2015-02-11
Using VS2013 Premium, asp.net. vb.net, website, win7

I have a dictionary of class objects which describe graphic element (rectangles, arrows, text boxes) by position and text content. I merge this with a blank PowerPoint presentation.  The elements show up in the correct positions.  However, I can't figure out how to change some of the styling, starting with the text box outline style.

>  started with a PowerPoint 2013 document with one slide with one shape
>  used the OpenXML SDK Productivity Tool to reflect it to C#, converted that the VB.Net, wrapped a project around it.
>  located the code where the shape was added to the slide shape tree
>  replace that with a function call that imports the dictionary, translates the dictionary  class objects into openxml shapes, and adds the shapes to the shape tree.  

That all works fine.  

However, some of the shapes are graphic rectangles which need outlines, and others are text boxes that don't.

In a very simple SDK comparison of two documents, one with text box with outline, and the other with textbox with "no line", the only difference in the XML is this:

 <a:ln>    
    <a:solidFill>      
         <a:schemeClr val="tx1"/>      
    </a:solidFill>    
</a:ln>

So, I've spent maybe eight hours using the SDK and reflected code to look at the different text documents trying to figure out why the outlines are or are not added.   I eventually located the theme that contained the LineStyleList that contains the Outlines ( <a:ln> ), and was able to identify which theme outline was being applied to ALL the elements.  

However, I haven't figured out how to either:

1) turn off all the outlines in the theme (which I can do) and add them to particular shapes where needed (which I can't do), OR
2) leave the theme outline in place, and remove the outlines from particular elements.

I've gotten closer with 1), which seems to make more sense.  I actually do add the outline to certain of the shapes, and I can see in the Immediate Window that they have been added...but they don't show up in the output document.

I'm going to keep experimenting, however, it seems like the theme is overriding whatever I try to do at the individual shape level.  

I'm hoping someone might have some insights that would help me move this along.  I'm going to have to deal with similar issues with respect to font sizes, and perhaps similar issues in some Excel exports I also need to do, so this might be useful for the community to have a solution for.

Here's the key code:

 

===== FIRST APPROACH :  Theme default is "no outlines"

========== THIS CREATE A SHAPE PROPERTIES OBJECT TO ATTACH TO THE SHAPE

Public Function CreateShapeProperties( _

            dLeftX As Integer, dTopY As Integer, _

            dWidthX As Integer, dHeightY As Integer, _

            varSP As MapGraphicSubPart) As ShapeProperties  '---- MapGraphicSubPart is the class object that contains the graphic and text information

        Dim shapeProperties1 As New ShapeProperties

        '====== Transform Properties - top,left,width, height=============

        Dim transform2D1 As New A.Transform2D()

        Dim offset2 As New A.Offset() With { _

             .X = dLeftX, _

             .Y = dTopY _

        }

        Dim extents2 As New A.Extents() With { _

             .Cx = dWidthX, _

             .Cy = dHeightY _

        }

        transform2D1.Append(offset2)

        transform2D1.Append(extents2)

        '============   PRE-SET GEOMETRY (Rectangle)==================

        Dim presetGeometry1 As New A.PresetGeometry() With { _

             .Preset = A.ShapeTypeValues.Rectangle _

        }

        Dim adjustValueList1 As New A.AdjustValueList()

        presetGeometry1.Append(adjustValueList1)

 

'-----  this adds the outline for particular types of shapes -----------

                     Select Case varSP.SubPartType

                           Case "Graphic"

                                  wrkLableOutline = PPTX.GetSolidDarkOutline()

                                  shapeProperties1.Append(wrkLableOutline)

                     End Select

 

              '----- create Nofill for all shapes

              Dim wrkNoFillWholeShape As New A.NoFill()

              '=============  Add it all up ====================================

              shapeProperties1.Append(transform2D1)

              shapeProperties1.Append(presetGeometry1)

              shapeProperties1.Append(wrkNoFillWholeShape)    '---- becomes purple without this

 

              '------------------------This allows testing to see if the outline has been added ------------------------

              Dim outline1 As A.Outline = shapeProperties1.GetFirstChild(Of A.Outline)()

              Dim wrkStop As String = 1  ‘---- at breakpoint here, outline is present, with all detail

 

End function

 

'======== THIS CREATES THE OUTLINE THAT IS APPENDED TO THE SHAPE ABOVE ======
'---------------IT WAS COPIED FROM THE CODE THAT CREATES THE THEME-------------------------

Public Shared Function GetSolidDarkOutline() As A.Outline


Dim outline3 As New A.Outline() With { _.Width = 9525, _.CapType = A.LineCapValues.Flat, _      .CompoundLineType = A.CompoundLineValues.[Single], _      
.Alignment = A.PenAlignmentValues.Center  }

Dim solidFill5 As New A.SolidFill()

Dim schemeColor21 As New A.SchemeColor() With {
_      .Val = A.SchemeColorValues.PhColor _      }      Dim shade4 As New A.Shade() With { _      .Val = 95000 _      }      Dim saturationModulation5 As New A.SaturationModulation() With { _      .Val = 105000 _      }

schemeColor21.Append(shade4)      schemeColor21.Append(saturationModulation5)

solidFill5.Append(schemeColor21)

Dim presetDash2 As New A.PresetDash() With { _      .Val = A.PresetLineDashValues.Solid _      }

Outline3.Append(solidFill5)      outline3.Append(presetDash2)

Return outline3

End Function

 

===========================================

THE SECOND APPROACH:  Try to remove outline

>  This can't find the outline when the shapeproperties is produced (i.e = nothing)

THE THIRD APPROACH:  Try to write in a new outline:  (Unconverted C#;  I implemented something like this in VB.NET in a variation of the first function above)

>  This causes the text to be blanked out.   The text is can still be found  in the document, via the SDK,  it just isn't visible any more in PowerPoint

 public Outline GenerateOutline()        {
          Outline outline1 = new Outline();  
         NoFill noFill1 = new NoFill();
         outline1.Append(noFill1);            
        return outline1;      
}
0
Comment
Question by:codequest
  • 3
4 Comments
 
LVL 96

Expert Comment

by:Bob Learned
ID: 40586650
Let's review to make certain that I understand the issue.

I created a PowerPoint XML, with a single shape that has a style applied:

	
<p:sp>
	<p:nvSpPr>
		<p:cNvPr id="4" name="Rectangle 3"/>
		<p:cNvSpPr/>
		<p:nvPr/>
	</p:nvSpPr>
	<p:spPr>
		<a:xfrm>
			<a:off x="633046" y="597877"/>
			<a:ext cx="3789485" cy="2277208"/>
		</a:xfrm>
		<a:prstGeom prst="rect">
			<a:avLst/>
		</a:prstGeom>
	</p:spPr>
	<p:style>
		<a:lnRef idx="2">
			<a:schemeClr val="accent1">
				<a:shade val="50000"/>
			</a:schemeClr>
		</a:lnRef>
		<a:fillRef idx="1">
			<a:schemeClr val="accent1"/>
		</a:fillRef>
		<a:effectRef idx="0">
			<a:schemeClr val="accent1"/>
		</a:effectRef>
		<a:fontRef idx="minor">
			<a:schemeClr val="lt1"/>
		</a:fontRef>
	</p:style>
	<p:txBody>
		<a:bodyPr rtlCol="0" anchor="ctr"/>
		<a:lstStyle/>
		<a:p>
			<a:pPr algn="ctr"/>
			<a:endParaRPr lang="en-US"/>
		</a:p>
	</p:txBody>
</p:sp>

Open in new window


1) The Shape class is <p:sp>

Shape class
https://msdn.microsoft.com/en-us/library/office/documentformat.openxml.presentation.shape.aspx

2) It has a ShapeStyle child <p:style>

ShapeStyle class
https://msdn.microsoft.com/en-us/library/office/documentformat.openxml.presentation.shapestyle.aspx

3) The ShapeStyle has a LineReference property <a:lnRef>.

LineReference class
https://msdn.microsoft.com/en-us/library/office/documentformat.openxml.drawing.linereference.aspx

The LineReference class has different properties for color:

LineReference properties
https://msdn.microsoft.com/en-us/library/office/documentformat.openxml.drawing.linereference_properties.aspx

hslClr (Hue, Saturation, Luminance Color Model)
LineReference.HslColor

prstClr (Preset Color)
LineReference.PresetColor

schemeClr (Scheme Color)
LineReference.SchemeColor

scrgbClr (RGB Color Model - Percentage Variant)
RgbColorModelPercentage

srgbClr (RGB Color Model - Hex Variant)
LineReference.RgbColorModelHex

sysClr (System Color)
LineReference.SystemColor
0
 
LVL 2

Author Comment

by:codequest
ID: 40587036
Thanks for your attention to this.   This is a test setup:

Here is the starting point:  create a PPT with a textbox without an outline;  copy it; add an outline to the textbox.

 Comparison of two powerpoints slides, one with shape with outline, one with shape without outline
Compare the two documents in the OpenXML SDK Productivity tool, looking at the difference in the XML:
Location of the differences in XML, in the SDK tool
Then look at the reflected code that would create the difference.
Differential code, from the SDK Tool
Open the PPT without the outline in the SDK, and Reflect the full code required to generate that entire PPT.  Put that code in a class in a new website project.  Create a webform that will execute that code on page load.
(see attached)

Snapshot showing the differential code added to the Generated code above
Snapshot showing the differential code added to the Generated code above
Run it both ways, with the differential code executed and not executed
snapshot showing PPT output with added code active
snapshot showing PPT output with added code bypassed (by if statement)
Compare the XML
Snapshot of SDK XML showing the comparative difference in the two generated PPTs
The comparative XML of the output documents looks the same as it did in the comparison of the starting documents, however, the output PPT that should have the shape with outline shows nothing.  Strangely, the XML shows that the shape is in the pptx, but does not show in the PPT GUI.

The goal is to be able to generate an entire PPTX using code, and to be able to interject changes into that code, somewhat like was done in the text example above.   However, I cannot get even this very simple change to work.  That's the problem.
GenPPT-wo-outline.cs
0
 
LVL 2

Accepted Solution

by:
codequest earned 0 total points
ID: 40595185
ANSWERED:  

The answer came from a different angle. Another element of the ShapeProperties object is the PresetGeometry , which has a ShapeTypeValue

   Dim presetGeometry1 As A.PresetGeometry = Nothing
  presetGeometry1 = New A.PresetGeometry() With { _
                       .Preset = A.ShapeTypeValues.Rectangle}
              shapeProperties1.Append(presetGeometry1)

While experimenting, I discovered that textboxes do not require ANY preset geometry.

I rewrote the code to not add the PresetGeometry for the textboxes, then set the applicable theme style to have a "dark, solid" outline instead of "no outline". The rectangles appear with outlines according to the theme, and the textboxes appear where they should, without outlines.
0
 
LVL 2

Author Closing Comment

by:codequest
ID: 40602724
I discovered the answer.
0

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

In my previous two articles we discussed Binary Serialization (http://www.experts-exchange.com/A_4362.html) and XML Serialization (http://www.experts-exchange.com/A_4425.html). In this article we will try to know more about SOAP (Simple Object Acces…
Wouldn’t it be nice if you could test whether an element is contained in an array by using a Contains method just like the one available on List objects? Wouldn’t it be good if you could write code like this? (CODE) In .NET 3.5, this is possible…
This video discusses moving either the default database or any database to a new volume.
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …

758 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now