OpenXML SDK Preset AutoShapes, BuildFreeForm and Fill Problems

D

DD

I'm hoping someone may be able to help me with BuildFreeForm. I'm not sure if
this is the right forum - if not please feel free to point me and this thread
in the right direction.

What I'm trying to do is recreate an AutoShape with BuildFreeForm in
PowerPoint (or Excel, etc.). For simple types, like the Heart AutoShape, this
works fine. When there are complex shapes, it doesn't work very well though.
While I can recreate the outline of the shape, the Fill functionality doesn't
work - this is where I'm getting stuck. I'm using VBA as it is quicker to
debug and VSTO doesn't appear to offer any advantage in speed or
functionality.

The reason I'm doing this is to eventually take a user-modified AutoShape
and transform it into WPF XAML so that it can be edited as a WPF shape and
round-tripped back to PowerPoint. AutoShapes do not expose ShapeNodes, so it
appears this is the only way to reach my goal (if you know of a different
way, I'm all ears!).

For example, I have gotten the formulas and paths to create the AutoShape
for "foldedCorner" in the OpenXML SDK (see REFERENCES below - Reference 1).
It is as follows:
==============================
<foldedCorner>
<avLst xmlns="http://schemas.openxmlformats.org/drawingml/2006/main">
<gd name="adj" fmla="val 16667" />
</avLst>
<gdLst xmlns="http://schemas.openxmlformats.org/drawingml/2006/main">
<gd name="a" fmla="pin 0 adj 50000" />
<gd name="dy2" fmla="*/ ss a 100000" />
<gd name="dy1" fmla="*/ dy2 1 5" />
<gd name="x1" fmla="+- r 0 dy2" />
<gd name="x2" fmla="+- x1 dy1 0" />
<gd name="y2" fmla="+- b 0 dy2" />
<gd name="y1" fmla="+- y2 dy1 0" />
</gdLst>
<ahLst xmlns="http://schemas.openxmlformats.org/drawingml/2006/main">
<ahXY gdRefX="adj" minX="0" maxX="50000">
<pos x="x1" y="b" />
</ahXY>
</ahLst>
<cxnLst xmlns="http://schemas.openxmlformats.org/drawingml/2006/main">
<cxn ang="3cd4">
<pos x="hc" y="t" />
</cxn>
<cxn ang="cd2">
<pos x="l" y="vc" />
</cxn>
<cxn ang="cd4">
<pos x="hc" y="b" />
</cxn>
<cxn ang="0">
<pos x="r" y="vc" />
</cxn>
</cxnLst>
<rect l="l" t="t" r="r" b="y2"
xmlns="http://schemas.openxmlformats.org/drawingml/2006/main" />
<pathLst xmlns="http://schemas.openxmlformats.org/drawingml/2006/main">
<path stroke="false" extrusionOk="false">
<moveTo>
<pt x="l" y="t" />
</moveTo>
<lnTo>
<pt x="r" y="t" />
</lnTo>
<lnTo>
<pt x="r" y="y2" />
</lnTo>
<lnTo>
<pt x="x1" y="b" />
</lnTo>
<lnTo>
<pt x="l" y="b" />
</lnTo>
<close />
</path>
<path stroke="false" fill="darkenLess" extrusionOk="false">
<moveTo>
<pt x="x1" y="b" />
</moveTo>
<lnTo>
<pt x="x2" y="y1" />
</lnTo>
<lnTo>
<pt x="r" y="y2" />
</lnTo>
<close />
</path>
<path fill="none" extrusionOk="false">
<moveTo>
<pt x="x1" y="b" />
</moveTo>
<lnTo>
<pt x="x2" y="y1" />
</lnTo>
<lnTo>
<pt x="r" y="y2" />
</lnTo>
<lnTo>
<pt x="x1" y="b" />
</lnTo>
<lnTo>
<pt x="l" y="b" />
</lnTo>
<lnTo>
<pt x="l" y="t" />
</lnTo>
<lnTo>
<pt x="r" y="t" />
</lnTo>
<lnTo>
<pt x="r" y="y2" />
</lnTo>
</path>
</pathLst>
</foldedCorner>
==============================

As I'm not looking at recreating the adjustments right now, I ignore that
and only use values from avLst, gdLst and pathList to try to re-create the
foldedCorner.

The first thing I do is open PowerPoint, change the layout of the first
slide to "Blank" and then add a "Folded Corner" Autoshape from the Ribbon. I
do this to get the width and height dimensions if I change those, but
otherwise usually just leave as the default.

Then, I run the following VBA code on procedure
"DrawFoldedCornerfromPresetShape"
==============================
Sub DrawFoldedCornerfromPresetShape()
Dim w As Single
Dim h As Single
Dim adj As Single
adj = 16667
'Get Height and Width of existing present FoldedCorner shape
Dim sh1 As Shape
Set sh1 = ActivePresentation.Slides(1).Shapes(1)
w = sh1.Width
h = sh1.Height
Dim L, T, R, B As Single
L = 0: T = 0: R = w: B = h
Dim a, DY2, DY1, X1, X2, Y2, Y1 As Single
a = Pin(0, adj, 50000)
DY2 = MultiplyDivide(Min(w, h), a, 100000) 'ss is min
DY1 = MultiplyDivide(DY2, 1, 5)
X1 = AddSubtract(R, 0, DY2)
X2 = AddSubtract(X1, DY1, 0)
Y2 = AddSubtract(B, 0, DY2)
Y1 = AddSubtract(Y2, DY1, 0)
Dim sh2 As Shape
With ActivePresentation.Slides(1).Shapes.BuildFreeform(msoEditingAuto,
L, T)
'change x1 to "R" to get full fill
'this is the first in the path list
.AddNodes msoSegmentLine, msoEditingAuto, R, T
.AddNodes msoSegmentLine, msoEditingAuto, R, Y2
.AddNodes msoSegmentLine, msoEditingAuto, X1, B
.AddNodes msoSegmentLine, msoEditingAuto, L, B
'this is the second in the path list
.AddNodes msoSegmentLine, msoEditingAuto, X1, B 'moveto
.AddNodes msoSegmentLine, msoEditingAuto, X2, Y1
.AddNodes msoSegmentLine, msoEditingAuto, R, Y2
'this is the Third in the path list
.AddNodes msoSegmentLine, msoEditingAuto, X1, B 'moveto
.AddNodes msoSegmentLine, msoEditingAuto, X2, Y1
.AddNodes msoSegmentLine, msoEditingAuto, R, Y2
.AddNodes msoSegmentLine, msoEditingAuto, X1, B
.AddNodes msoSegmentLine, msoEditingAuto, L, B
.AddNodes msoSegmentLine, msoEditingAuto, L, T
.AddNodes msoSegmentLine, msoEditingAuto, R, T
.AddNodes msoSegmentLine, msoEditingAuto, R, Y2
Set sh2 = .ConvertToShape
End With
End Sub
'USED FOR "ls". See REFERENCES below - Reference 2
Function Max(ByVal w As Single, ByVal h As Single) As Single
If w > h Then Max = w Else Max = h
End Function
'END "ls"
'USED FOR "ss". See REFERENCES below - Reference 3
Function Min(ByVal w As Single, ByVal h As Single) As Single
If w < h Then Min = w Else Min = h
End Function
'END "ss"
'Used for "fmla". See REFERENCES below - Reference 4
Function Pin(ByVal x As Single, ByVal y As Single, ByVal z As Single) As
Single
If (y < x) Then
Pin = x
ElseIf (y > z) Then
Pin = z
Else: Pin = y
End If
End Function
Function MultiplyDivide(ByVal x As Single, ByVal y As Single, ByVal z As
Single) As Single
MultiplyDivide = ((x * y) / z)
End Function
Function AddSubtract(ByVal x As Single, ByVal y As Single, ByVal z As
Single) As Single
AddSubtract = ((x + y) - z)
End Function
'END "fmla"
==============================

The shape outline is created just fine, but when I use the "fill" function
from the toolbar, it only fills halfway. I have tried changing values here
and there, but can't seem to get everything correct, so I'm wondering if
someone can help out here with BuildFreeForm.

++++++++++++++
REFERENCES:
1. Preset Shape Definitions for AutoShapes:
Link: http://www.ecma-international.org/publications/standards/Ecma-376.htm
File: ECMA-376 2nd edition Part 1.zip
Path: ..\ECMA-376, Second Edition, Part 1 - Fundamentals And Markup Language
Reference\OfficeOpenXML-DrawingMLGeometries\presentShapeDefinitions.xml

2. ls
Link:
http://www.documentinteropinitiativ...376/07ca4953-a012-4078-a2e4-7532cca102c4.aspx

3. ss
Link:http://www.documentinteropinitiativ...376/07ca4953-a012-4078-a2e4-7532cca102c4.aspx

4. fmla
Link:
http://www.documentinteropinitiativ...376/df1ed123-a72d-4a25-b6c0-5cbc38959cc5.aspx
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top