codequest
asked on
In PowerPoint openxml, add or subtract a text box outline style
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(offset 2)
transform2D1.Append(extent s2)
'============ PRE-SET GEOMETRY (Rectangle)=============== ===
Dim presetGeometry1 As New A.PresetGeometry() With { _
.Preset = A.ShapeTypeValues.Rectangl e _
}
Dim adjustValueList1 As New A.AdjustValueList()
presetGeometry1.Append(adj ustValueLi st1)
'----- this adds the outline for particular types of shapes -----------
Select Case varSP.SubPartType
Case "Graphic"
wrkLableOutline = PPTX.GetSolidDarkOutline()
shapeProperties1.Append(wr kLableOutl ine)
End Select
'----- create Nofill for all shapes
Dim wrkNoFillWholeShape As New A.NoFill()
'============= Add it all up ========================== ==========
shapeProperties1.Append(tr ansform2D1 )
shapeProperties1.Append(pr esetGeomet ry1)
shapeProperties1.Append(wr kNoFillWho leShape) '---- becomes purple without this
'------------------------T his allows testing to see if the outline has been added ------------------------
Dim outline1 As A.Outline = shapeProperties1.GetFirstC hild(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.[Sing le], _
.Alignment = A.PenAlignmentValues.Cente r }
Dim solidFill5 As New A.SolidFill()
Dim schemeColor21 As New A.SchemeColor() With {
_ .Val = A.SchemeColorValues.PhColo r _ } Dim shade4 As New A.Shade() With { _ .Val = 95000 _ } Dim saturationModulation5 As New A.SaturationModulation() With { _ .Val = 105000 _ }
schemeColor21.Append(shade 4) schemeColor21.Append(satur ationModul ation5)
solidFill5.Append(schemeCo lor21)
Dim presetDash2 As New A.PresetDash() With { _ .Val = A.PresetLineDashValues.Sol id _ }
Outline3.Append(solidFill5 ) outline3.Append(presetDash 2)
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;
}
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(offset
transform2D1.Append(extent
'============ PRE-SET GEOMETRY (Rectangle)===============
Dim presetGeometry1 As New A.PresetGeometry() With { _
.Preset = A.ShapeTypeValues.Rectangl
}
Dim adjustValueList1 As New A.AdjustValueList()
presetGeometry1.Append(adj
'----- this adds the outline for particular types of shapes -----------
Select Case varSP.SubPartType
Case "Graphic"
wrkLableOutline = PPTX.GetSolidDarkOutline()
shapeProperties1.Append(wr
End Select
'----- create Nofill for all shapes
Dim wrkNoFillWholeShape As New A.NoFill()
'============= Add it all up ==========================
shapeProperties1.Append(tr
shapeProperties1.Append(pr
shapeProperties1.Append(wr
'------------------------T
Dim outline1 As A.Outline = shapeProperties1.GetFirstC
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.[Sing
.Alignment = A.PenAlignmentValues.Cente
Dim solidFill5 As New A.SolidFill()
Dim schemeColor21 As New A.SchemeColor() With {
_ .Val = A.SchemeColorValues.PhColo
schemeColor21.Append(shade
solidFill5.Append(schemeCo
Dim presetDash2 As New A.PresetDash() With { _ .Val = A.PresetLineDashValues.Sol
Outline3.Append(solidFill5
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;
}
ASKER
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.
Compare the two documents in the OpenXML SDK Productivity tool, looking at the difference in the XML:
Then look at the reflected code that would create the difference.
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
Run it both ways, with the differential code executed and not executed
Compare the XML
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
Here is the starting point: create a PPT with a textbox without an outline; copy it; add an outline to the textbox.
Compare the two documents in the OpenXML SDK Productivity tool, looking at the difference in the XML:
Then look at the reflected code that would create the difference.
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
Run it both ways, with the differential code executed and not executed
Compare the XML
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
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
I discovered the answer.
I created a PowerPoint XML, with a single shape that has a style applied:
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.RgbColorMode
sysClr (System Color)
LineReference.SystemColor