在 OpenXML 的 PPT 元素,形状的翻转与旋转是有逻辑关系,本文来和大家聊聊形状的翻转和形状的旋转的关系

本文来和小伙伴聊聊最复杂的 ConnectionShape 形状的方向,这个 ConnectionShape 如果是箭头,那么请问箭头方向被多少个属性影响?有很多个影响,最简单的就是 cx 和 cy 的影响。其次就是形状的旋转,而形状的翻转影响是形状本身

先来聊聊 PPT 元素里面的 ConnectionShape 形状,也就是线条形状的,如箭头的方向,在 PPTX 格式的文档的形状的线条形状方向是需要由元素的坐标和 cx 和 cy 决定,如下面这个简单的课件

这个课件的箭头内容如下

<p:spPr bwMode="auto">
  <a:xfrm>
    <a:off x="952500" y="952500" />
    <a:ext cx="952500" cy="952500" />
  </a:xfrm>
  <a:prstGeom prst="line">
    <a:avLst />
  </a:prstGeom>
  <a:noFill />
  <a:ln w="38100">
    <a:solidFill>
      <a:srgbClr val="FF0000" />
    </a:solidFill>
    <a:round />
    <a:headEnd />
    <a:tailEnd type="triangle" w="med" len="med" />
  </a:ln>
  <a:extLst>
    <a:ext uri="{909E8E84-426E-40DD-AFC4-6F175D3DCCD1}">
      <a14:hiddenFill xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main">
        <a:noFill />
      </a14:hiddenFill>
    </a:ext>
  </a:extLst>
</p:spPr>

课件可以从 github 下载

箭头的方向是通过 a:xfrm 决定的

  <a:xfrm>
    <a:off x="952500" y="952500" />
    <a:ext cx="952500" cy="952500" />
  </a:xfrm>

根据 Office Open XML 的测量单位 这里的单位是 EMU 单位,而 952500 就是大概 100 像素。首先通过 a:off 决定元素的坐标,请看下图

上面图片红色的是箭头,也就是 PPTX 文档里面的形状,而黑色的是辅助线。可以看到使用 a:off 决定元素的坐标,而这个形状线条多长和方向就通过 a:ext 决定,请看下面

可以看到箭头距离画布的左上角是 100 像素,而刚好箭头的指向就是刚好 x 是 100 而 y 也是 100 的方向。换句话说,可以将线条形状认为是通过两个点绘制的,而两个点是通过 a:offa:ext 这两个作为点

如果此时进行翻转,将会发生什么?试试下面代码

<p:spPr bwMode="auto">
  <a:xfrm flipV="1">
    <a:off x="952500" y="952500" />
    <a:ext cx="952500" cy="952500" />
  </a:xfrm>
  <a:prstGeom prst="line">
    <a:avLst />
  </a:prstGeom>
  <a:noFill />
  <a:ln w="38100">
    <a:solidFill>
      <a:srgbClr val="FF0000" />
    </a:solidFill>
    <a:round />
    <a:headEnd />
    <a:tailEnd type="triangle" w="med" len="med" />
  </a:ln>
  <a:extLst>
    <a:ext uri="{909E8E84-426E-40DD-AFC4-6F175D3DCCD1}">
      <a14:hiddenFill xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main">
        <a:noFill />
      </a14:hiddenFill>
    </a:ext>
  </a:extLst>
</p:spPr>

对比上面代码其实加添加了 flipV="1" 表示垂直翻转,点击 形状箭头方向 最简箭头 翻转.pptx 即可下载此课件

  <a:xfrm flipV="1">
    <a:off x="952500" y="952500" />
    <a:ext cx="952500" cy="952500" />
  </a:xfrm>

在 OpenXML SDK 的 flipV="1" 对应代码如下

BooleanValue verticalFlip = transform.VerticalFlip;

那么垂直翻转是什么含义?其实是在垂直方向给镜像,如下图

而在 PPT 中,在进行垂直方向镜像之后,不能更改元素的坐标,也就是如果绘制出线条形状的外接矩形,可以看到外接矩形在元素进行翻转前后的坐标和大小不变

那么如果加上旋转呢?其实旋转是独立的,只是作用在形状的外接矩形上。在2D渲染,新旋转再翻转和先翻转再旋转的效果是不相同的

在 PPT 里,如果加上旋转如下面代码,是先翻转再旋转

<p:spPr bwMode="auto">
  <a:xfrm rot="2700000" flipV="1">
    <a:off x="952500" y="952500" />
    <a:ext cx="952500" cy="952500" />
  </a:xfrm>
  <a:prstGeom prst="line">
    <a:avLst />
  </a:prstGeom>
  <a:noFill />
  <a:ln w="38100">
    <a:solidFill>
      <a:srgbClr val="FF0000" />
    </a:solidFill>
    <a:round />
    <a:headEnd />
    <a:tailEnd type="triangle" w="med" len="med" />
  </a:ln>
  <a:extLst>
    <a:ext uri="{909E8E84-426E-40DD-AFC4-6F175D3DCCD1}">
      <a14:hiddenFill xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main">
        <a:noFill />
      </a14:hiddenFill>
    </a:ext>
  </a:extLst>
</p:spPr>

这份课件可以在 github 下载

在 OpenXML 的旋转使用 rot 表示,通过 Office Open XML 的测量单位 可以了解单位是角度,每 60000 表示一度,也就是代码 rot="2700000" 是 45 度。旋转方向默认是顺时针

而通过 a:ext cx="952500" cy="952500" 可以看到是箭头倾斜 45 度,也就是 x 方向是 100 像素和 y 方向是 100 像素,刚好是外接正方形的对角线。正方形的对角线一定是 45 度。而此时的旋转是 45 度,所以要么箭头成垂直的,要么是水平的,也就是 180 度和 90 度

在 PPT 的元素,是先翻转,然后对外接矩形旋转。在翻转之后的箭头是 45 度,而加上旋转是在翻转之后加上的,此时加上 45 度也是 90 度

所以可以看到上面代码的箭头是 90 度的

关于元素的宽度高度等请看 C# dotnet 使用 OpenXml 解析 PPT 元素的坐标和宽度高度

在调试这部分细节的时候,就需要用到我的工具了,这个工具可以将 PPTX 等 Office 文档解压缩出来,方便小伙伴编辑里面的文档内容,编辑完成之后可以打包为 PPTX 文档看修改的效果。这个工具的安装方法很简单,在命令行输入下面代码即可安装

dotnet tool isntall -g dotnetCampus.OfficeDocumentZipper

打开工具可以在命令行输入下面代码

OfficeDocumentZipper

这个工具在 GitHub 完全开源,请看 dotnet OpenXML 解压缩文档为文件夹工具

翻转与文本

以上所聊的都是形状翻转时不带文本的,如果带了文本就需要关注文本的方向了

如以下的形状带文本的文档内容

<p:sp>
  <p:nvSpPr>
    <p:cNvPr id="2" name="等腰三角形 1" />
    <p:cNvSpPr />
    <p:nvPr />
  </p:nvSpPr>
  <p:spPr>
    <a:xfrm>
      <a:off x="4073236" y="2211186" />
      <a:ext cx="2876203" cy="1820487" />
    </a:xfrm>
    <!-- 忽略代码 -->
  </p:spPr>
  <p:style>
    <!-- 忽略代码 -->
  </p:style>
  <p:txBody>
    <a:bodyPr rtlCol="0" anchor="ctr" />
    <a:lstStyle />
    <a:p>
      <a:pPr algn="ctr" />
      <a:r>
        <a:rPr lang="en-US" altLang="zh-CN" dirty="0" smtClean="0" />
        <a:t>lindexi</a:t>
      </a:r>
      <a:endParaRPr lang="zh-CN" altLang="en-US" dirty="0" />
    </a:p>
  </p:txBody>
</p:sp>

在 PPT 显示如下

而如果给 a:xfrm 加上翻转和旋转,如下代码

<a:xfrm rot="2469930" flipH="1">
  <a:off x="4073236" y="2211186" />
  <a:ext cx="2876203" cy="1820487" />
</a:xfrm>

此时显示如下

可以看到文本没有跟随进行水平翻转。如果文本有跟随水平翻转,那么显示效果应该是如下

因此在进行水平翻转时,将不会让文本跟随翻转

而在带文本的形状进行垂直翻转时,此时的文本是跟随翻转的,如以下文档

<a:xfrm flipV="1">
  <a:off x="3865418" y="2286000" />
  <a:ext cx="2651760" cy="1953491" />
</a:xfrm>

带文本的形状的翻转效果如下

  • 水平翻转时,文本不跟随翻转
  • 垂直翻转时,文本跟随翻转

上面的文档,我放在 github 欢迎大家访问

以上的规则在组合内依然是对的,如果想不开的话,试试形状的翻转和组合一起用

步骤如下:

  • 形状 a 创建
  • 复制形状 a 作为 b 形状
  • 水平翻转 b 形状
  • 复制形状 a 作为 c 形状
  • 垂直翻转 c 形状
  • 组合 a 形状和 b 形状作为 A 组合
  • 水平翻转 A 组合
  • 组合 A 和 c 形状组合作为 B 组合
  • 垂直翻转 B 组合
  • 复制形状 a 作为 d 形状
  • 组合 d 形状和 B 组合作为 C 组合
  • 水平翻转 C 组合

然后你再试试去解析这部分的文档

更多请看 Office 使用 OpenXML SDK 解析文档博客目录


本文会经常更新,请阅读原文: https://dotnet-campus.github.io//post/dotnet-OpenXML-SDK-%E5%BD%A2%E7%8A%B6%E7%9A%84%E7%BF%BB%E8%BD%AC%E4%B8%8E%E6%97%8B%E8%BD%AC.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

知识共享许可协议 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 lindexi (包含链接: https://dotnet-campus.github.io/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系