scanny / python-pptx

Create Open XML PowerPoint documents in Python
MIT License
2.38k stars 515 forks source link

BuildFreeform Method #81

Closed maspireone closed 10 years ago

maspireone commented 10 years ago

Hi Scanny,

Can you give me a hint that how can I add function like BuildFreeform Method in VBA to create curve through 4 points. If I would like to create a function like that on top of your code, where should I start. Please help to let me know. Thank you.

The detail of the function is list below. http://msdn.microsoft.com/en-us/library/office/aa212150(v=office.11).aspx

scanny commented 10 years ago

Hi maspireone, I would determine what XML is added to the PowerPoint file when you make that call with VBA and see if I could work out from there how to do the same. It might go something like this:

  1. Create a baseline presentation to compare against. Maybe having one blank slide, whatever is the minimum you need before you can reasonably make that VBA call. Save this file as before.pptx.
  2. Execute a typical BuildFreeform method call using VBA on before.pptx. Save that file as after.pptx.
  3. Use opc-diag to do a diff on the two to isolate the specific XML that is added by the call. You can consult the documentation for opc-diag to learn how to install and use it. the short version is roughly:
$ pip install opc-diag
$ opc diff before.pptx after.pptx

Once you get it narrowed down to a specific set of elements paste it back in here and I can help you further.

maspireone commented 10 years ago

Hi Scanny,

Thanks. The following is the result. It's a closed curve shape. Please be noted. How can I create a function for this in python-pptx. Please help to let me know where to start.

       <a:chExt cx="0" cy="0"/>
     </a:xfrm>
   </p:grpSpPr>
  <p:sp>
    <p:nvSpPr>
      <p:cNvPr id="5" name="Freeform 4"/>
      <p:cNvSpPr/>
      <p:nvPr/>
    </p:nvSpPr>
    <p:spPr>
      <a:xfrm>
        <a:off x="2756647" y="1918179"/>
        <a:ext cx="3993777" cy="1994915"/>
      </a:xfrm>
      <a:custGeom>
        <a:avLst/>
        <a:gdLst>
          <a:gd name="connsiteX0" fmla="*/ 0 w 3993777"/>
          <a:gd name="connsiteY0" fmla="*/ 1994915 h 1994915"/>
          <a:gd name="connsiteX1" fmla="*/ 1707777 w 3993777"/>
          <a:gd name="connsiteY1" fmla="*/ 152668 h 1994915"/>
          <a:gd name="connsiteX2" fmla="*/ 3993777 w 3993777"/>
          <a:gd name="connsiteY2" fmla="*/ 152668 h 1994915"/>
          <a:gd name="connsiteX0" fmla="*/ 0 w 3993777"/>
          <a:gd name="connsiteY0" fmla="*/ 1994915 h 1994915"/>
          <a:gd name="connsiteX1" fmla="*/ 1707777 w 3993777"/>
          <a:gd name="connsiteY1" fmla="*/ 152668 h 1994915"/>
          <a:gd name="connsiteX2" fmla="*/ 3993777 w 3993777"/>
          <a:gd name="connsiteY2" fmla="*/ 152668 h 1994915"/>
          <a:gd name="connsiteX3" fmla="*/ 0 w 3993777"/>
          <a:gd name="connsiteY3" fmla="*/ 1994915 h 1994915"/>
        </a:gdLst>
        <a:ahLst/>
        <a:cxnLst>
          <a:cxn ang="0">
            <a:pos x="connsiteX0" y="connsiteY0"/>
          </a:cxn>
          <a:cxn ang="0">
            <a:pos x="connsiteX1" y="connsiteY1"/>
          </a:cxn>
          <a:cxn ang="0">
            <a:pos x="connsiteX2" y="connsiteY2"/>
          </a:cxn>
          <a:cxn ang="0">
            <a:pos x="connsiteX3" y="connsiteY3"/>
          </a:cxn>
        </a:cxnLst>
        <a:rect l="l" t="t" r="r" b="b"/>
        <a:pathLst>
          <a:path w="3993777" h="1994915">
            <a:moveTo>
              <a:pt x="0" y="1994915"/>
            </a:moveTo>
            <a:cubicBezTo>
              <a:pt x="521074" y="1227312"/>
              <a:pt x="1042148" y="459709"/>
              <a:pt x="1707777" y="152668"/>
            </a:cubicBezTo>
            <a:cubicBezTo>
              <a:pt x="2373407" y="-154373"/>
              <a:pt x="3565712" y="85433"/>
              <a:pt x="3993777" y="152668"/>
            </a:cubicBezTo>
            <a:lnTo>
              <a:pt x="0" y="1994915"/>
            </a:lnTo>
            <a:close/>
          </a:path>
        </a:pathLst>
      </a:custGeom>
      <a:noFill/>
    </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>
 </p:spTree>
 <p:extLst>
   <p:ext uri="{BB962C8B-B14F-4D97-AF65-F5344CB8AC3E}">
scanny commented 10 years ago

I'll need to see the specific VBA call you used to create this. Can you paste it in?

maspireone commented 10 years ago

Please see below.

Sub Shape() Set myDocument = ActivePresentation.Slides(1)

With myDocument.Shapes.BuildFreeform(msoSegmentLine, 217.0588, 308) .AddNodes 1, 1, 258.0883, 248, 299.1177, 187, 351.5294, 163 .AddNodes 1, 1, 403.9413, 139, 497.8235, 158, 531.5294, 163 .AddNodes 0, 0, 217.0588, 308 .ConvertToShape End With End Sub

scanny commented 10 years ago

Interesting. I'm sure I never would have come across this one on my own, thanks for asking this one :)

Here are a few insights:

Unfortunately it looks like PowerPoint is calculating the smooth curve values to bezier curve values internally. So it looks like you'll be on your own for that. Your VBA call has a starting and ending point for each node whereas the XML has two additional points for each node, I expect these determine the shape of the curve.

Hope that helps, let us know how you go :)

maspireone commented 10 years ago

Sure. Thanks for the information. I will keep you updated.

stcmeh commented 7 years ago

Hi there - any progress on this issue?