【新增】 PPTX 动画考点优化
This commit is contained in:
@@ -7,6 +7,7 @@ import org.docx4j.jaxb.XPathBinderAssociationIsPartialException;
|
||||
import org.pptx4j.pml.*;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
|
||||
public class ShapePage {
|
||||
|
||||
@@ -79,6 +80,7 @@ public class ShapePage {
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/// 替换文字 说明
|
||||
public static String getShapeText(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
return "待开发";
|
||||
@@ -266,6 +268,7 @@ public class ShapePage {
|
||||
// 3) 未设置 → 视为实线
|
||||
return "solid";
|
||||
}
|
||||
|
||||
// 形状线条 开始箭头类型
|
||||
public static String getShapeLineStartArrow(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
CTShapeProperties spPr = sp.getSpPr();
|
||||
@@ -277,14 +280,17 @@ public class ShapePage {
|
||||
}
|
||||
return "无箭头";
|
||||
}
|
||||
|
||||
// 形状线条 开始箭头粗细
|
||||
public static String getShapeLineStartArrowWidth(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
return "待开发";
|
||||
}
|
||||
|
||||
// 形状线条 结尾箭头类型
|
||||
public static String getShapeLineEndArrow(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
return "待开发";
|
||||
}
|
||||
|
||||
// 形状线条 结尾箭头粗细
|
||||
public static String getShapeLineEndArrowWidth(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
return "待开发";
|
||||
@@ -391,14 +397,17 @@ public class ShapePage {
|
||||
CTSoftEdgesEffect se = getSoftEdge(sp);
|
||||
return (se != null) ? String.valueOf(se.getRad()) : null;
|
||||
}
|
||||
|
||||
// 形状效果 三维效果→绘制
|
||||
public static String getShape3DEffectDraw(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
return "待开发";
|
||||
}
|
||||
|
||||
// 形状效果 三维格式→效果
|
||||
public static String getShape3DEffect(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
return "待开发";
|
||||
}
|
||||
|
||||
// 形状效果 三维旋转→效果
|
||||
public static String getShape3DRotation(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
return "待开发";
|
||||
@@ -415,453 +424,118 @@ public class ShapePage {
|
||||
|
||||
|
||||
// 动画 效果
|
||||
// public static String getAnimation(org.pptx4j.pml.Shape sp, CTSlideTiming timing) throws JAXBException, XPathBinderAssociationIsPartialException {
|
||||
// // 获取形状中的ID
|
||||
// if (sp == null) return "无动画";
|
||||
// long spId = sp.getNvSpPr().getCNvPr().getId();
|
||||
// // 获取动画效果
|
||||
// CTTimeNodeList timeNodeList = timing.getTnLst();
|
||||
// for (Object obj : timeNodeList.getParOrSeqOrExcl()) {
|
||||
// if (obj instanceof CTTLTimeNodeParallel) {
|
||||
// CTTLTimeNodeParallel par = (CTTLTimeNodeParallel) obj;
|
||||
// CTTLCommonTimeNodeData node = par.getCTn();
|
||||
// if (node.getChildTnLst().getParOrSeqOrExcl() != null) {
|
||||
// CTTimeNodeList childTimeNodeList = node.getChildTnLst();
|
||||
// for (Object object : childTimeNodeList.getParOrSeqOrExcl()) {
|
||||
// if (object instanceof CTTLSetBehavior) {
|
||||
// if (((CTTLSetBehavior) object).getCBhvr() != null) {
|
||||
// if (((CTTLSetBehavior) object).getCBhvr().getTgtEl().getSpTgt() != null) {
|
||||
// // 检查目标形状ID是否匹配
|
||||
// if (((CTTLSetBehavior) object).getCBhvr().getTgtEl().getSpTgt().getSpid().equals(String.valueOf(spId))) {
|
||||
// // 返回动画效果
|
||||
//
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if (object instanceof CTTLTimeNodeSequence) {
|
||||
// CTTLTimeNodeSequence seq = (CTTLTimeNodeSequence) object;
|
||||
// CTTimeNodeList seqNodeList = seq.getCTn().getChildTnLst();
|
||||
// for (Object seqObjs : seqNodeList.getParOrSeqOrExcl()) {
|
||||
// if (seqObjs instanceof CTTLSetBehavior) {
|
||||
// if (((CTTLSetBehavior) seqObjs).getCBhvr() != null) {
|
||||
// if (((CTTLSetBehavior) seqObjs).getCBhvr().getTgtEl().getSpTgt() != null) {
|
||||
// // 检查目标形状ID是否匹配
|
||||
// if (((CTTLSetBehavior) seqObjs).getCBhvr().getTgtEl().getSpTgt().getSpid().equals(String.valueOf(spId))) {
|
||||
// // 返回动画效果
|
||||
//
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if (seqObjs instanceof CTTLTimeNodeSequence) {
|
||||
// CTTLTimeNodeSequence seqObj = (CTTLTimeNodeSequence) seqObjs;
|
||||
// CTTimeNodeList seqNodeLists = seqObj.getCTn().getChildTnLst();
|
||||
// for (Object seqObjss : seqNodeLists.getParOrSeqOrExcl()) {
|
||||
// if (seqObjss instanceof CTTLSetBehavior) {
|
||||
// if (((CTTLSetBehavior) seqObjss).getCBhvr() != null) {
|
||||
// if (((CTTLSetBehavior) seqObjss).getCBhvr().getTgtEl().getSpTgt() != null) {
|
||||
// // 检查目标形状ID是否匹配
|
||||
// if (((CTTLSetBehavior) seqObjss).getCBhvr().getTgtEl().getSpTgt().getSpid().equals(String.valueOf(spId))) {
|
||||
// // 返回动画效果
|
||||
//
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// if (node.getDur() != null && !"indefinite".equals(node.getDur())) {
|
||||
// return node.getDur();
|
||||
// }
|
||||
// System.out.println(par.getCTn());
|
||||
// }
|
||||
// }
|
||||
// return "待开发";
|
||||
// }
|
||||
|
||||
public static String getAnimation(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
if (sp == null || timing == null || timing.getTnLst() == null) return "无动画";
|
||||
final String spId = String.valueOf(sp.getNvSpPr().getCNvPr().getId());
|
||||
CTTimeNodeList root = timing.getTnLst();
|
||||
|
||||
// 先找进入类(effect)
|
||||
String entrance = findFirstBehavior(root, spId, /*preferEntrance=*/true);
|
||||
if (entrance != null) return entrance;
|
||||
|
||||
// 再找其它类型(包括 CTTLAnimateBehavior 的 ppt_x/ppt_y)
|
||||
String any = findFirstBehavior(root, spId, /*preferEntrance=*/false);
|
||||
return any != null ? any : "无动画";
|
||||
long spId = sp.getNvSpPr().getCNvPr().getId();
|
||||
CTTimeNodeList ctTimeNodeList = timing.getTnLst();
|
||||
if (ctTimeNodeList == null) return "无动画";
|
||||
// 第一层
|
||||
List<Object> parOrSeqOrExcl = ctTimeNodeList.getParOrSeqOrExcl();
|
||||
String value = getAniationInfo(parOrSeqOrExcl, null, String.valueOf(spId), "type");
|
||||
if (!value.isEmpty()) {
|
||||
return value;
|
||||
}
|
||||
|
||||
/* 递归遍历所有 time nodes,返回首个命中的行为字符串 */
|
||||
private static String findFirstBehavior(CTTimeNodeList list, String spId, boolean preferEntrance) {
|
||||
if (list == null || list.getParOrSeqOrExcl() == null) return null;
|
||||
|
||||
for (Object raw : list.getParOrSeqOrExcl()) {
|
||||
Object node = unwrap(raw);
|
||||
|
||||
// 1) 直接是某种行为(Behavior)
|
||||
String desc = tryDescribeIfBehavior(node, spId, preferEntrance);
|
||||
if (desc != null) return desc;
|
||||
|
||||
// 2) par / seq / excl,进入子列表递归
|
||||
CTTimeNodeList child = getChildList(node);
|
||||
if (child != null) {
|
||||
String got = findFirstBehavior(child, spId, preferEntrance);
|
||||
if (got != null) return got;
|
||||
return "";
|
||||
}
|
||||
public static String getAniationInfo(List<Object> objects, List<Object> upObjects, String spId, String parameter) {
|
||||
for (Object object : objects) {
|
||||
if (object instanceof CTTLSetBehavior) {
|
||||
String spIds = ((CTTLSetBehavior) object).getCBhvr().getTgtEl().getSpTgt().getSpid();
|
||||
// 判断ID是否一致
|
||||
if (spIds.equals(spId)) {
|
||||
// 持续时间
|
||||
if (parameter.equals("dur")) {
|
||||
return ((CTTLSetBehavior) object).getCBhvr().getCTn().getDur();
|
||||
}
|
||||
// 向上获取延迟
|
||||
for (Object upObject : upObjects) {
|
||||
if (upObject instanceof CTTLTimeNodeParallel) {
|
||||
// 获取动画效果
|
||||
if (parameter.equals("type")) {
|
||||
Integer type = ((CTTLTimeNodeParallel) upObject).getCTn().getPresetSubtype();
|
||||
return String.valueOf(type);
|
||||
}
|
||||
// 触发方式
|
||||
if (parameter.equals("function")) {
|
||||
return ((CTTLTimeNodeParallel) upObject).getCTn().getNodeType().value();
|
||||
}
|
||||
// 获取延迟方法
|
||||
for (Object condObject : ((CTTLTimeNodeParallel) upObject).getCTn().getStCondLst().getCond()) {
|
||||
if (condObject instanceof CTTLTimeCondition) {
|
||||
// 获取延迟
|
||||
if (parameter.equals("delay")) {
|
||||
return ((CTTLTimeCondition) condObject).getDelay();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* 如果对象是某种 Behavior,且目标命中当前 spId,则返回描述;否则返回 null */
|
||||
private static String tryDescribeIfBehavior(Object obj, String spId, boolean preferEntrance) {
|
||||
// 统一 unwrap
|
||||
obj = unwrap(obj);
|
||||
|
||||
// --- 进入类效果(Effect)---
|
||||
if (obj instanceof CTTLAnimateEffectBehavior) {
|
||||
CTTLAnimateEffectBehavior b = (CTTLAnimateEffectBehavior) obj;
|
||||
if (isTarget(b.getCBhvr(), spId)) {
|
||||
String filter = safe(b.getFilter()); // 如 "fade"、"strips(downRight)" 等
|
||||
return filter.isEmpty() ? "进入效果" : ("进入效果:" + filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (object instanceof CTTLTimeNodeParallel obj) {
|
||||
String result = getAniationInfo(obj.getCTn().getChildTnLst().getParOrSeqOrExcl(), objects, spId, parameter);
|
||||
if (!result.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (object instanceof CTTLTimeNodeSequence obj) {
|
||||
String result = getAniationInfo(obj.getCTn().getChildTnLst().getParOrSeqOrExcl(), objects, spId, parameter);
|
||||
if (!result.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 非优先阶段:其它类型
|
||||
if (!preferEntrance) {
|
||||
// 通用 Animate (B 动画关键:ppt_x / ppt_y)
|
||||
if (obj instanceof CTTLAnimateBehavior) {
|
||||
CTTLAnimateBehavior b = (CTTLAnimateBehavior) obj;
|
||||
if (isTarget(b.getCBhvr(), spId)) {
|
||||
String attr = firstAttrName(b.getCBhvr());
|
||||
if ("ppt_x".equalsIgnoreCase(attr)) return "位置动画:X(ppt_x)";
|
||||
if ("ppt_y".equalsIgnoreCase(attr)) return "位置动画:Y(ppt_y)";
|
||||
return attr.isEmpty() ? "数值动画(Animate)" : ("数值动画(" + attr + ")");
|
||||
return "";
|
||||
}
|
||||
}
|
||||
if (obj instanceof CTTLAnimateMotionBehavior) {
|
||||
CTTLAnimateMotionBehavior b = (CTTLAnimateMotionBehavior) obj;
|
||||
if (isTarget(b.getCBhvr(), spId)) return "路径动画(Motion)";
|
||||
}
|
||||
if (obj instanceof CTTLAnimateRotationBehavior) {
|
||||
CTTLAnimateRotationBehavior b = (CTTLAnimateRotationBehavior) obj;
|
||||
if (isTarget(b.getCBhvr(), spId)) return "旋转动画";
|
||||
}
|
||||
if (obj instanceof CTTLAnimateScaleBehavior) {
|
||||
CTTLAnimateScaleBehavior b = (CTTLAnimateScaleBehavior) obj;
|
||||
if (isTarget(b.getCBhvr(), spId)) return "缩放动画";
|
||||
}
|
||||
if (obj instanceof CTTLSetBehavior) {
|
||||
CTTLSetBehavior b = (CTTLSetBehavior) obj;
|
||||
if (isTarget(b.getCBhvr(), spId)) {
|
||||
String to = (b.getTo()!=null && b.getTo().getStrVal()!=null) ? safe(b.getTo().getStrVal().getVal()) : "";
|
||||
String attr = firstAttrName(b.getCBhvr());
|
||||
if (!attr.isEmpty() || !to.isEmpty()) {
|
||||
return "属性设置(Set):" + (attr.isEmpty() ? "" : attr) + (to.isEmpty() ? "" : (" -> " + to));
|
||||
}
|
||||
return "属性设置(Set)";
|
||||
}
|
||||
}
|
||||
if (obj instanceof CTTLAnimateColorBehavior) {
|
||||
CTTLAnimateColorBehavior b = (CTTLAnimateColorBehavior) obj;
|
||||
if (isTarget(b.getCBhvr(), spId)) return "颜色动画";
|
||||
}
|
||||
if (obj instanceof CTTLCommandBehavior) {
|
||||
CTTLCommandBehavior b = (CTTLCommandBehavior) obj;
|
||||
if (isTarget(b.getCBhvr(), spId)) return "命令动画(Command)";
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* 提取并返回子节点列表(par/seq/excl 三种) */
|
||||
private static CTTimeNodeList getChildList(Object node) {
|
||||
node = unwrap(node);
|
||||
if (node instanceof CTTLTimeNodeParallel) {
|
||||
CTTLTimeNodeParallel n = (CTTLTimeNodeParallel) node;
|
||||
return n.getCTn() != null ? n.getCTn().getChildTnLst() : null;
|
||||
}
|
||||
if (node instanceof CTTLTimeNodeSequence) {
|
||||
CTTLTimeNodeSequence n = (CTTLTimeNodeSequence) node;
|
||||
return n.getCTn() != null ? n.getCTn().getChildTnLst() : null;
|
||||
}
|
||||
if (node instanceof CTTLTimeNodeExclusive) {
|
||||
CTTLTimeNodeExclusive n = (CTTLTimeNodeExclusive) node;
|
||||
return n.getCTn() != null ? n.getCTn().getChildTnLst() : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* 判断行为的目标是否命中当前形状 spId */
|
||||
private static boolean isTarget(CTTLCommonBehaviorData cb, String spId) {
|
||||
if (cb == null || cb.getTgtEl() == null || cb.getTgtEl().getSpTgt() == null) return false;
|
||||
String tgt = cb.getTgtEl().getSpTgt().getSpid();
|
||||
return String.valueOf(spId).equals(tgt);
|
||||
}
|
||||
|
||||
/* 读第一个 attrName(如 ppt_x / ppt_y / style.visibility ...)*/
|
||||
private static String firstAttrName(CTTLCommonBehaviorData cb) {
|
||||
if (cb == null || cb.getAttrNameLst() == null) return "";
|
||||
java.util.List<String> names = cb.getAttrNameLst().getAttrName();
|
||||
return (names != null && !names.isEmpty()) ? safe(names.get(0)) : "";
|
||||
}
|
||||
|
||||
/* 统一解包 JAXBElement */
|
||||
private static Object unwrap(Object o) {
|
||||
return (o instanceof JAXBElement) ? ((JAXBElement<?>) o).getValue() : o;
|
||||
}
|
||||
|
||||
/* 安全字符串 */
|
||||
private static String safe(String s) {
|
||||
return s == null ? "" : s.trim();
|
||||
}
|
||||
|
||||
|
||||
// 动画-方向
|
||||
public static String getAnimateDirection(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
String dir = getAnimation(sp, timing);
|
||||
if (dir.equals("downRight")) {
|
||||
return "右下";
|
||||
}
|
||||
if (dir.equals("downLeft")) {
|
||||
return "左下";
|
||||
}
|
||||
if (dir.equals("upRight")) {
|
||||
return "右上";
|
||||
}
|
||||
if (dir.equals("upLeft")) {
|
||||
return "左上";
|
||||
}
|
||||
if (dir.equals("right")) {
|
||||
return "向右";
|
||||
}
|
||||
if (dir.equals("left")) {
|
||||
return "向左";
|
||||
}
|
||||
if (dir.equals("down")) {
|
||||
return "向下";
|
||||
}
|
||||
if (dir.equals("up")) {
|
||||
return "向上";
|
||||
}
|
||||
if (dir.equals("fromTop")) {
|
||||
return "从顶部";
|
||||
}
|
||||
if (dir.equals("fromBottom")) {
|
||||
return "从底部";
|
||||
}
|
||||
if (dir.equals("fromLeft")) {
|
||||
return "从左侧";
|
||||
}
|
||||
if (dir.equals("fromRight")) {
|
||||
return "从右侧";
|
||||
}
|
||||
return "";
|
||||
return "待开发";
|
||||
}
|
||||
|
||||
// 动画 触发方式
|
||||
public static String getAnimateTrigger(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
// 获取形状中的ID
|
||||
if (sp == null) return "无动画";
|
||||
long spId = sp.getNvSpPr().getCNvPr().getId();
|
||||
// 获取动画效果
|
||||
CTTimeNodeList timeNodeList = timing.getTnLst();
|
||||
for (Object obj : timeNodeList.getParOrSeqOrExcl()) {
|
||||
if (obj instanceof CTTLTimeNodeParallel) {
|
||||
CTTLTimeNodeParallel par = (CTTLTimeNodeParallel) obj;
|
||||
CTTLCommonTimeNodeData node = par.getCTn();
|
||||
if (node.getChildTnLst().getParOrSeqOrExcl() != null) {
|
||||
CTTimeNodeList childTimeNodeList = node.getChildTnLst();
|
||||
for (Object object : childTimeNodeList.getParOrSeqOrExcl()) {
|
||||
if (object instanceof CTTLTimeNodeSequence) {
|
||||
CTTLTimeNodeSequence seq = (CTTLTimeNodeSequence) object;
|
||||
if (seq.getCTn().getStCondLst() != null) {
|
||||
CTTLTimeConditionList stCondLst = seq.getCTn().getStCondLst();
|
||||
for (CTTLTimeCondition o : stCondLst.getCond()) {
|
||||
if (o.getEvt() != null) {
|
||||
return o.getEvt().value();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CTTimeNodeList seqNodeList = seq.getCTn().getChildTnLst();
|
||||
for (Object seqObj : seqNodeList.getParOrSeqOrExcl()) {
|
||||
if (seqObj instanceof CTTLTimeNodeSequence) {
|
||||
CTTLTimeNodeSequence seqs = (CTTLTimeNodeSequence) seqObj;
|
||||
if (seqs.getCTn().getStCondLst() != null) {
|
||||
CTTLTimeConditionList stCondLst = seqs.getCTn().getStCondLst();
|
||||
for (CTTLTimeCondition o : stCondLst.getCond()) {
|
||||
if (o.getEvt() != null) {
|
||||
return o.getEvt().value();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CTTimeNodeList seqNodeLists = seqs.getCTn().getChildTnLst();
|
||||
for (Object seqObjs : seqNodeLists.getParOrSeqOrExcl()) {
|
||||
if (seqObjs instanceof CTTLTimeNodeSequence) {
|
||||
CTTLTimeNodeSequence seqss = (CTTLTimeNodeSequence) seqObjs;
|
||||
if (seqss.getCTn().getStCondLst() != null) {
|
||||
CTTLTimeConditionList stCondLst = seqss.getCTn().getStCondLst();
|
||||
for (CTTLTimeCondition o : stCondLst.getCond()) {
|
||||
if (o.getEvt() != null) {
|
||||
return o.getEvt().value();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (seqObj instanceof CTTLTimeNodeParallel) {
|
||||
CTTLTimeNodeParallel seqs = (CTTLTimeNodeParallel) seqObj;
|
||||
if (seqs.getCTn().getStCondLst() != null) {
|
||||
CTTLTimeConditionList stCondLst = seqs.getCTn().getStCondLst();
|
||||
for (CTTLTimeCondition o : stCondLst.getCond()) {
|
||||
if (o.getEvt() != null) {
|
||||
return o.getEvt().value();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CTTimeNodeList seqNodeLists = seqs.getCTn().getChildTnLst();
|
||||
for (Object seqObjs : seqNodeLists.getParOrSeqOrExcl()) {
|
||||
if (seqObjs instanceof CTTLTimeNodeSequence) {
|
||||
CTTLTimeNodeSequence seqss = (CTTLTimeNodeSequence) seqObjs;
|
||||
if (seqss.getCTn().getStCondLst() != null) {
|
||||
CTTLTimeConditionList stCondLst = seqss.getCTn().getStCondLst();
|
||||
for (CTTLTimeCondition o : stCondLst.getCond()) {
|
||||
if (o.getEvt() != null) {
|
||||
return o.getEvt().value();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CTTimeNodeList ctTimeNodeList = timing.getTnLst();
|
||||
if (ctTimeNodeList == null) return "无动画";
|
||||
// 第一层
|
||||
List<Object> parOrSeqOrExcl = ctTimeNodeList.getParOrSeqOrExcl();
|
||||
String value = getAniationInfo(parOrSeqOrExcl, null, String.valueOf(spId), "function");
|
||||
if (!value.isEmpty()) {
|
||||
return value;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// 动画 持续时间
|
||||
public static String getAnimationDuration(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
if (sp == null || timing == null || timing.getTnLst() == null) return "无动画";
|
||||
|
||||
final String spId = String.valueOf(sp.getNvSpPr().getCNvPr().getId());
|
||||
CTTimeNodeList root = timing.getTnLst();
|
||||
|
||||
// 先找“进入类效果(effect)”
|
||||
String entrance = findFirstBehavior(root, spId, /*preferEntrance=*/true);
|
||||
if (entrance != null) return entrance;
|
||||
|
||||
// 找不到进入类,再找其它类型(运动、旋转、缩放、Set 等)
|
||||
String any = findFirstBehavior(root, spId, /*preferEntrance=*/false);
|
||||
return any != null ? any : "无动画";
|
||||
long spId = sp.getNvSpPr().getCNvPr().getId();
|
||||
CTTimeNodeList ctTimeNodeList = timing.getTnLst();
|
||||
if (ctTimeNodeList == null) return "无动画";
|
||||
// 第一层
|
||||
List<Object> parOrSeqOrExcl = ctTimeNodeList.getParOrSeqOrExcl();
|
||||
String value = getAniationInfo(parOrSeqOrExcl, null, String.valueOf(spId), "dur");
|
||||
if (!value.isEmpty()) {
|
||||
return value;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// 动画 延迟
|
||||
public static String getAnimationDelay(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
// 获取形状中的ID
|
||||
if (sp == null) return "无动画";
|
||||
long spId = sp.getNvSpPr().getCNvPr().getId();
|
||||
// 获取动画效果
|
||||
CTTimeNodeList timeNodeList = timing.getTnLst();
|
||||
for (Object obj : timeNodeList.getParOrSeqOrExcl()) {
|
||||
if (obj instanceof CTTLTimeNodeParallel) {
|
||||
CTTLTimeNodeParallel par = (CTTLTimeNodeParallel) obj;
|
||||
CTTLCommonTimeNodeData node = par.getCTn();
|
||||
if (node.getChildTnLst().getParOrSeqOrExcl() != null) {
|
||||
CTTimeNodeList childTimeNodeList = node.getChildTnLst();
|
||||
for (Object object : childTimeNodeList.getParOrSeqOrExcl()) {
|
||||
if (object instanceof CTTLTimeNodeSequence) {
|
||||
CTTLTimeNodeSequence seq = (CTTLTimeNodeSequence) object;
|
||||
if (seq.getCTn().getStCondLst() != null) {
|
||||
CTTLTimeConditionList stCondLst = seq.getCTn().getStCondLst();
|
||||
for (CTTLTimeCondition o : stCondLst.getCond()) {
|
||||
if (o.getEvt() != null) {
|
||||
return o.getDelay();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CTTimeNodeList seqNodeList = seq.getCTn().getChildTnLst();
|
||||
for (Object seqObj : seqNodeList.getParOrSeqOrExcl()) {
|
||||
if (seqObj instanceof CTTLTimeNodeSequence) {
|
||||
CTTLTimeNodeSequence seqs = (CTTLTimeNodeSequence) seqObj;
|
||||
if (seqs.getCTn().getStCondLst() != null) {
|
||||
CTTLTimeConditionList stCondLst = seqs.getCTn().getStCondLst();
|
||||
for (CTTLTimeCondition o : stCondLst.getCond()) {
|
||||
if (o.getEvt() != null) {
|
||||
return o.getDelay();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CTTimeNodeList seqNodeLists = seqs.getCTn().getChildTnLst();
|
||||
for (Object seqObjs : seqNodeLists.getParOrSeqOrExcl()) {
|
||||
if (seqObjs instanceof CTTLTimeNodeSequence) {
|
||||
CTTLTimeNodeSequence seqss = (CTTLTimeNodeSequence) seqObjs;
|
||||
if (seqss.getCTn().getStCondLst() != null) {
|
||||
CTTLTimeConditionList stCondLst = seqss.getCTn().getStCondLst();
|
||||
for (CTTLTimeCondition o : stCondLst.getCond()) {
|
||||
if (o.getEvt() != null) {
|
||||
return o.getDelay();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (seqObj instanceof CTTLTimeNodeParallel) {
|
||||
CTTLTimeNodeParallel seqs = (CTTLTimeNodeParallel) seqObj;
|
||||
if (seqs.getCTn().getStCondLst() != null) {
|
||||
CTTLTimeConditionList stCondLst = seqs.getCTn().getStCondLst();
|
||||
for (CTTLTimeCondition o : stCondLst.getCond()) {
|
||||
if (o.getEvt() != null) {
|
||||
return o.getDelay();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CTTimeNodeList seqNodeLists = seqs.getCTn().getChildTnLst();
|
||||
for (Object seqObjs : seqNodeLists.getParOrSeqOrExcl()) {
|
||||
if (seqObjs instanceof CTTLTimeNodeSequence) {
|
||||
CTTLTimeNodeSequence seqss = (CTTLTimeNodeSequence) seqObjs;
|
||||
if (seqss.getCTn().getStCondLst() != null) {
|
||||
CTTLTimeConditionList stCondLst = seqss.getCTn().getStCondLst();
|
||||
for (CTTLTimeCondition o : stCondLst.getCond()) {
|
||||
if (o.getEvt() != null) {
|
||||
return o.getDelay();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CTTimeNodeList ctTimeNodeList = timing.getTnLst();
|
||||
if (ctTimeNodeList == null) return "无动画";
|
||||
// 第一层
|
||||
List<Object> parOrSeqOrExcl = ctTimeNodeList.getParOrSeqOrExcl();
|
||||
String value = getAniationInfo(parOrSeqOrExcl, null, String.valueOf(spId), "delay");
|
||||
if (!value.isEmpty()) {
|
||||
return value;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// 形状动作,鼠标单机-动作
|
||||
|
||||
|
||||
@@ -1223,6 +897,7 @@ public class ShapePage {
|
||||
}
|
||||
return "0";
|
||||
}
|
||||
|
||||
/// 段落 缩进→度量值
|
||||
public static String getTextBoxParagraphIndentMeasure(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
if (sp.getTxBody() != null) {
|
||||
@@ -1236,6 +911,7 @@ public class ShapePage {
|
||||
}
|
||||
return "0";
|
||||
}
|
||||
|
||||
/// 段落 间距→段前
|
||||
public static String getTextBoxParagraphSpaceBefore(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
if (sp.getTxBody() != null) {
|
||||
@@ -1249,6 +925,7 @@ public class ShapePage {
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/// 段落 间距→段后
|
||||
public static String getTextBoxParagraphSpaceAfter(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
if (sp.getTxBody() != null) {
|
||||
@@ -1262,6 +939,7 @@ public class ShapePage {
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/// 段落 间距→行距→类型
|
||||
public static String getTextBoxParagraphSpaceLine(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
if (sp.getTxBody() != null) {
|
||||
@@ -1278,6 +956,7 @@ public class ShapePage {
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/// 段落 间距→行距→设置值
|
||||
public static String getTextBoxParagraphSpaceLineValue(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
if (sp.getTxBody() != null) {
|
||||
@@ -1294,6 +973,7 @@ public class ShapePage {
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/// 段落 项目符号和编号→类型
|
||||
public static String getTextBoxParagraphSymbol(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
return "待开发";
|
||||
@@ -1331,6 +1011,7 @@ public class ShapePage {
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/// 文本填充 纯色填充→颜色
|
||||
public static String getTextBoxParagraphFillColor(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
if (sp.getTxBody() != null) {
|
||||
@@ -1355,26 +1036,32 @@ public class ShapePage {
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/// 文本填充 渐变填充→效果
|
||||
public static String getTextBoxParagraphFillGradient(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
return "待开发";
|
||||
}
|
||||
|
||||
/// 文本填充 图片填充→效果
|
||||
public static String getTextBoxParagraphFillImage(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
return "待开发";
|
||||
}
|
||||
|
||||
/// 文本填充 纹理填充→效果
|
||||
public static String getTextBoxParagraphFillTexture(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
return "待开发";
|
||||
}
|
||||
|
||||
/// 文本填充 图案填充→效果
|
||||
public static String getTextBoxParagraphFillPattern(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
return "待开发";
|
||||
}
|
||||
|
||||
/// 文本填充 填充透明度
|
||||
public static String getTextBoxParagraphFillOpacity(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
return "待开发";
|
||||
}
|
||||
|
||||
/// 文本轮廓 颜色
|
||||
public static String getTextBoxParagraphOutlineColor(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
if (sp.getTxBody() != null) {
|
||||
@@ -1391,6 +1078,7 @@ public class ShapePage {
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/// 文本轮廓 透明度
|
||||
public static String getTextBoxParagraphOutlineOpacity(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
if (sp.getTxBody() != null) {
|
||||
@@ -1404,8 +1092,7 @@ public class ShapePage {
|
||||
int alpha = 0;
|
||||
if (fill.getSrgbClr() != null) {
|
||||
alpha = Integer.parseInt(fill.getSrgbClr().getVal());
|
||||
}
|
||||
else if (fill.getSchemeClr() != null) {
|
||||
} else if (fill.getSchemeClr() != null) {
|
||||
alpha = fill.getSchemeClr().getVal().ordinal();
|
||||
}
|
||||
return String.valueOf((100000 - alpha) / 1000.0);
|
||||
@@ -1415,6 +1102,7 @@ public class ShapePage {
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/// 文本轮廓 宽度
|
||||
public static String getTextBoxParagraphOutlineWidth(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
if (sp.getTxBody() != null) {
|
||||
@@ -1434,6 +1122,7 @@ public class ShapePage {
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/// 文本轮廓 高度
|
||||
public static String getTextBoxParagraphOutlineHeight(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
if (sp.getTxBody() != null) {
|
||||
@@ -1453,10 +1142,12 @@ public class ShapePage {
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/// 文本轮廓 复合类型
|
||||
public static String getTextBoxParagraphOutlineType(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
return "待开发";
|
||||
}
|
||||
|
||||
/// 文本轮廓 短划线类型
|
||||
public static String getTextBoxParagraphOutlineDashType(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
return "待开发";
|
||||
@@ -1481,6 +1172,7 @@ public class ShapePage {
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// 文字效果 阴影→预设
|
||||
// 文字效果 阴影→效果
|
||||
public static String getTextBoxParagraphShadowEffect(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
@@ -1525,14 +1217,17 @@ public class ShapePage {
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// 文字效果 发光→绘制
|
||||
public static String getTextBoxParagraphGlowDraw(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
return "待开发";
|
||||
}
|
||||
|
||||
// 文字效果 发光→效果
|
||||
public static String getTextBoxParagraphGlowEffect(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
return "待开发";
|
||||
}
|
||||
|
||||
// 文字效果 转换→弯曲
|
||||
public static String getTextBoxParagraphConvertCurve(org.pptx4j.pml.Shape sp, CTSlideTiming timing) {
|
||||
return "待开发";
|
||||
|
@@ -5,6 +5,7 @@ import org.docx4j.dml.*;
|
||||
import org.pptx4j.pml.*;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
|
||||
public class ShapePic {
|
||||
|
||||
@@ -409,447 +410,113 @@ public class ShapePic {
|
||||
|
||||
|
||||
// 动画 效果
|
||||
// public static String getAnimation(org.pptx4j.pml.Shape sp, CTSlideTiming timing) throws JAXBException, XPathBinderAssociationIsPartialException {
|
||||
// // 获取形状中的ID
|
||||
// if (sp == null) return "无动画";
|
||||
// long spId = sp.getNvSpPr().getCNvPr().getId();
|
||||
// // 获取动画效果
|
||||
// CTTimeNodeList timeNodeList = timing.getTnLst();
|
||||
// for (Object obj : timeNodeList.getParOrSeqOrExcl()) {
|
||||
// if (obj instanceof CTTLTimeNodeParallel) {
|
||||
// CTTLTimeNodeParallel par = (CTTLTimeNodeParallel) obj;
|
||||
// CTTLCommonTimeNodeData node = par.getCTn();
|
||||
// if (node.getChildTnLst().getParOrSeqOrExcl() != null) {
|
||||
// CTTimeNodeList childTimeNodeList = node.getChildTnLst();
|
||||
// for (Object object : childTimeNodeList.getParOrSeqOrExcl()) {
|
||||
// if (object instanceof CTTLSetBehavior) {
|
||||
// if (((CTTLSetBehavior) object).getCBhvr() != null) {
|
||||
// if (((CTTLSetBehavior) object).getCBhvr().getTgtEl().getSpTgt() != null) {
|
||||
// // 检查目标形状ID是否匹配
|
||||
// if (((CTTLSetBehavior) object).getCBhvr().getTgtEl().getSpTgt().getSpid().equals(String.valueOf(spId))) {
|
||||
// // 返回动画效果
|
||||
//
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if (object instanceof CTTLTimeNodeSequence) {
|
||||
// CTTLTimeNodeSequence seq = (CTTLTimeNodeSequence) object;
|
||||
// CTTimeNodeList seqNodeList = seq.getCTn().getChildTnLst();
|
||||
// for (Object seqObjs : seqNodeList.getParOrSeqOrExcl()) {
|
||||
// if (seqObjs instanceof CTTLSetBehavior) {
|
||||
// if (((CTTLSetBehavior) seqObjs).getCBhvr() != null) {
|
||||
// if (((CTTLSetBehavior) seqObjs).getCBhvr().getTgtEl().getSpTgt() != null) {
|
||||
// // 检查目标形状ID是否匹配
|
||||
// if (((CTTLSetBehavior) seqObjs).getCBhvr().getTgtEl().getSpTgt().getSpid().equals(String.valueOf(spId))) {
|
||||
// // 返回动画效果
|
||||
//
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if (seqObjs instanceof CTTLTimeNodeSequence) {
|
||||
// CTTLTimeNodeSequence seqObj = (CTTLTimeNodeSequence) seqObjs;
|
||||
// CTTimeNodeList seqNodeLists = seqObj.getCTn().getChildTnLst();
|
||||
// for (Object seqObjss : seqNodeLists.getParOrSeqOrExcl()) {
|
||||
// if (seqObjss instanceof CTTLSetBehavior) {
|
||||
// if (((CTTLSetBehavior) seqObjss).getCBhvr() != null) {
|
||||
// if (((CTTLSetBehavior) seqObjss).getCBhvr().getTgtEl().getSpTgt() != null) {
|
||||
// // 检查目标形状ID是否匹配
|
||||
// if (((CTTLSetBehavior) seqObjss).getCBhvr().getTgtEl().getSpTgt().getSpid().equals(String.valueOf(spId))) {
|
||||
// // 返回动画效果
|
||||
//
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// if (node.getDur() != null && !"indefinite".equals(node.getDur())) {
|
||||
// return node.getDur();
|
||||
// }
|
||||
// System.out.println(par.getCTn());
|
||||
// }
|
||||
// }
|
||||
// return "待开发";
|
||||
// }
|
||||
|
||||
public static String getAnimation(org.pptx4j.pml.Pic sp, CTSlideTiming timing) {
|
||||
if (sp == null || timing == null || timing.getTnLst() == null) return "无动画";
|
||||
final String spId = String.valueOf(sp.getNvPicPr().getCNvPr().getId());
|
||||
CTTimeNodeList root = timing.getTnLst();
|
||||
|
||||
// 先找进入类(effect)
|
||||
String entrance = findFirstBehavior(root, spId, /*preferEntrance=*/true);
|
||||
if (entrance != null) return entrance;
|
||||
|
||||
// 再找其它类型(包括 CTTLAnimateBehavior 的 ppt_x/ppt_y)
|
||||
String any = findFirstBehavior(root, spId, /*preferEntrance=*/false);
|
||||
return any != null ? any : "无动画";
|
||||
}
|
||||
|
||||
/* 递归遍历所有 time nodes,返回首个命中的行为字符串 */
|
||||
private static String findFirstBehavior(CTTimeNodeList list, String spId, boolean preferEntrance) {
|
||||
if (list == null || list.getParOrSeqOrExcl() == null) return null;
|
||||
|
||||
for (Object raw : list.getParOrSeqOrExcl()) {
|
||||
Object node = unwrap(raw);
|
||||
|
||||
// 1) 直接是某种行为(Behavior)
|
||||
String desc = tryDescribeIfBehavior(node, spId, preferEntrance);
|
||||
if (desc != null) return desc;
|
||||
|
||||
// 2) par / seq / excl,进入子列表递归
|
||||
CTTimeNodeList child = getChildList(node);
|
||||
if (child != null) {
|
||||
String got = findFirstBehavior(child, spId, preferEntrance);
|
||||
if (got != null) return got;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* 如果对象是某种 Behavior,且目标命中当前 spId,则返回描述;否则返回 null */
|
||||
private static String tryDescribeIfBehavior(Object obj, String spId, boolean preferEntrance) {
|
||||
// 统一 unwrap
|
||||
obj = unwrap(obj);
|
||||
|
||||
// --- 进入类效果(Effect)---
|
||||
if (obj instanceof CTTLAnimateEffectBehavior) {
|
||||
CTTLAnimateEffectBehavior b = (CTTLAnimateEffectBehavior) obj;
|
||||
if (isTarget(b.getCBhvr(), spId)) {
|
||||
String filter = safe(b.getFilter()); // 如 "fade"、"strips(downRight)" 等
|
||||
return filter.isEmpty() ? "进入效果" : ("进入效果:" + filter);
|
||||
}
|
||||
}
|
||||
|
||||
// 非优先阶段:其它类型
|
||||
if (!preferEntrance) {
|
||||
// 通用 Animate (B 动画关键:ppt_x / ppt_y)
|
||||
if (obj instanceof CTTLAnimateBehavior) {
|
||||
CTTLAnimateBehavior b = (CTTLAnimateBehavior) obj;
|
||||
if (isTarget(b.getCBhvr(), spId)) {
|
||||
String attr = firstAttrName(b.getCBhvr());
|
||||
if ("ppt_x".equalsIgnoreCase(attr)) return "位置动画:X(ppt_x)";
|
||||
if ("ppt_y".equalsIgnoreCase(attr)) return "位置动画:Y(ppt_y)";
|
||||
return attr.isEmpty() ? "数值动画(Animate)" : ("数值动画(" + attr + ")");
|
||||
}
|
||||
}
|
||||
if (obj instanceof CTTLAnimateMotionBehavior) {
|
||||
CTTLAnimateMotionBehavior b = (CTTLAnimateMotionBehavior) obj;
|
||||
if (isTarget(b.getCBhvr(), spId)) return "路径动画(Motion)";
|
||||
}
|
||||
if (obj instanceof CTTLAnimateRotationBehavior) {
|
||||
CTTLAnimateRotationBehavior b = (CTTLAnimateRotationBehavior) obj;
|
||||
if (isTarget(b.getCBhvr(), spId)) return "旋转动画";
|
||||
}
|
||||
if (obj instanceof CTTLAnimateScaleBehavior) {
|
||||
CTTLAnimateScaleBehavior b = (CTTLAnimateScaleBehavior) obj;
|
||||
if (isTarget(b.getCBhvr(), spId)) return "缩放动画";
|
||||
}
|
||||
if (obj instanceof CTTLSetBehavior) {
|
||||
CTTLSetBehavior b = (CTTLSetBehavior) obj;
|
||||
if (isTarget(b.getCBhvr(), spId)) {
|
||||
String to = (b.getTo()!=null && b.getTo().getStrVal()!=null) ? safe(b.getTo().getStrVal().getVal()) : "";
|
||||
String attr = firstAttrName(b.getCBhvr());
|
||||
if (!attr.isEmpty() || !to.isEmpty()) {
|
||||
return "属性设置(Set):" + (attr.isEmpty() ? "" : attr) + (to.isEmpty() ? "" : (" -> " + to));
|
||||
}
|
||||
return "属性设置(Set)";
|
||||
}
|
||||
}
|
||||
if (obj instanceof CTTLAnimateColorBehavior) {
|
||||
CTTLAnimateColorBehavior b = (CTTLAnimateColorBehavior) obj;
|
||||
if (isTarget(b.getCBhvr(), spId)) return "颜色动画";
|
||||
}
|
||||
if (obj instanceof CTTLCommandBehavior) {
|
||||
CTTLCommandBehavior b = (CTTLCommandBehavior) obj;
|
||||
if (isTarget(b.getCBhvr(), spId)) return "命令动画(Command)";
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* 提取并返回子节点列表(par/seq/excl 三种) */
|
||||
private static CTTimeNodeList getChildList(Object node) {
|
||||
node = unwrap(node);
|
||||
if (node instanceof CTTLTimeNodeParallel) {
|
||||
CTTLTimeNodeParallel n = (CTTLTimeNodeParallel) node;
|
||||
return n.getCTn() != null ? n.getCTn().getChildTnLst() : null;
|
||||
}
|
||||
if (node instanceof CTTLTimeNodeSequence) {
|
||||
CTTLTimeNodeSequence n = (CTTLTimeNodeSequence) node;
|
||||
return n.getCTn() != null ? n.getCTn().getChildTnLst() : null;
|
||||
}
|
||||
if (node instanceof CTTLTimeNodeExclusive) {
|
||||
CTTLTimeNodeExclusive n = (CTTLTimeNodeExclusive) node;
|
||||
return n.getCTn() != null ? n.getCTn().getChildTnLst() : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* 判断行为的目标是否命中当前形状 spId */
|
||||
private static boolean isTarget(CTTLCommonBehaviorData cb, String spId) {
|
||||
if (cb == null || cb.getTgtEl() == null || cb.getTgtEl().getSpTgt() == null) return false;
|
||||
String tgt = cb.getTgtEl().getSpTgt().getSpid();
|
||||
return String.valueOf(spId).equals(tgt);
|
||||
}
|
||||
|
||||
/* 读第一个 attrName(如 ppt_x / ppt_y / style.visibility ...)*/
|
||||
private static String firstAttrName(CTTLCommonBehaviorData cb) {
|
||||
if (cb == null || cb.getAttrNameLst() == null) return "";
|
||||
java.util.List<String> names = cb.getAttrNameLst().getAttrName();
|
||||
return (names != null && !names.isEmpty()) ? safe(names.get(0)) : "";
|
||||
}
|
||||
|
||||
/* 统一解包 JAXBElement */
|
||||
private static Object unwrap(Object o) {
|
||||
return (o instanceof JAXBElement) ? ((JAXBElement<?>) o).getValue() : o;
|
||||
}
|
||||
|
||||
/* 安全字符串 */
|
||||
private static String safe(String s) {
|
||||
return s == null ? "" : s.trim();
|
||||
}
|
||||
|
||||
|
||||
// 动画-方向
|
||||
public static String getAnimateDirection(Pic sp, CTSlideTiming timing) {
|
||||
String dir = getAnimation(sp, timing);
|
||||
if (dir.equals("downRight")) {
|
||||
return "右下";
|
||||
}
|
||||
if (dir.equals("downLeft")) {
|
||||
return "左下";
|
||||
}
|
||||
if (dir.equals("upRight")) {
|
||||
return "右上";
|
||||
}
|
||||
if (dir.equals("upLeft")) {
|
||||
return "左上";
|
||||
}
|
||||
if (dir.equals("right")) {
|
||||
return "向右";
|
||||
}
|
||||
if (dir.equals("left")) {
|
||||
return "向左";
|
||||
}
|
||||
if (dir.equals("down")) {
|
||||
return "向下";
|
||||
}
|
||||
if (dir.equals("up")) {
|
||||
return "向上";
|
||||
}
|
||||
if (dir.equals("fromTop")) {
|
||||
return "从顶部";
|
||||
}
|
||||
if (dir.equals("fromBottom")) {
|
||||
return "从底部";
|
||||
}
|
||||
if (dir.equals("fromLeft")) {
|
||||
return "从左侧";
|
||||
}
|
||||
if (dir.equals("fromRight")) {
|
||||
return "从右侧";
|
||||
long spId = sp.getNvPicPr().getCNvPr().getId();
|
||||
CTTimeNodeList ctTimeNodeList = timing.getTnLst();
|
||||
if (ctTimeNodeList == null) return "无动画";
|
||||
// 第一层
|
||||
List<Object> parOrSeqOrExcl = ctTimeNodeList.getParOrSeqOrExcl();
|
||||
String value = getAniationInfo(parOrSeqOrExcl, null, String.valueOf(spId), "type");
|
||||
if (!value.isEmpty()) {
|
||||
return value;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
public static String getAniationInfo(List<Object> objects, List<Object> upObjects, String spId, String parameter) {
|
||||
for (Object object : objects) {
|
||||
if (object instanceof CTTLSetBehavior) {
|
||||
String spIds = ((CTTLSetBehavior) object).getCBhvr().getTgtEl().getSpTgt().getSpid();
|
||||
// 判断ID是否一致
|
||||
if (spIds.equals(spId)) {
|
||||
// 持续时间
|
||||
if (parameter.equals("dur")) {
|
||||
return ((CTTLSetBehavior) object).getCBhvr().getCTn().getDur();
|
||||
}
|
||||
// 向上获取延迟
|
||||
for (Object upObject : upObjects) {
|
||||
if (upObject instanceof CTTLTimeNodeParallel) {
|
||||
// 获取动画效果
|
||||
if (parameter.equals("type")) {
|
||||
Integer type = ((CTTLTimeNodeParallel) upObject).getCTn().getPresetSubtype();
|
||||
return String.valueOf(type);
|
||||
}
|
||||
// 触发方式
|
||||
if (parameter.equals("function")) {
|
||||
return ((CTTLTimeNodeParallel) upObject).getCTn().getNodeType().value();
|
||||
}
|
||||
// 获取延迟方法
|
||||
for (Object condObject : ((CTTLTimeNodeParallel) upObject).getCTn().getStCondLst().getCond()) {
|
||||
if (condObject instanceof CTTLTimeCondition) {
|
||||
// 获取延迟
|
||||
if (parameter.equals("delay")) {
|
||||
return ((CTTLTimeCondition) condObject).getDelay();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (object instanceof CTTLTimeNodeParallel obj) {
|
||||
String result = getAniationInfo(obj.getCTn().getChildTnLst().getParOrSeqOrExcl(), objects, spId, parameter);
|
||||
if (!result.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (object instanceof CTTLTimeNodeSequence obj) {
|
||||
String result = getAniationInfo(obj.getCTn().getChildTnLst().getParOrSeqOrExcl(), objects, spId, parameter);
|
||||
if (!result.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
// 动画-方向
|
||||
public static String getAnimateDirection(org.pptx4j.pml.Pic sp, CTSlideTiming timing) {
|
||||
return "待开发";
|
||||
}
|
||||
|
||||
// 动画 触发方式
|
||||
public static String getAnimateTrigger(Pic sp, CTSlideTiming timing) {
|
||||
// 获取形状中的ID
|
||||
if (sp == null) return "无动画";
|
||||
public static String getAnimateTrigger(org.pptx4j.pml.Pic sp, CTSlideTiming timing) {
|
||||
long spId = sp.getNvPicPr().getCNvPr().getId();
|
||||
// 获取动画效果
|
||||
CTTimeNodeList timeNodeList = timing.getTnLst();
|
||||
for (Object obj : timeNodeList.getParOrSeqOrExcl()) {
|
||||
if (obj instanceof CTTLTimeNodeParallel) {
|
||||
CTTLTimeNodeParallel par = (CTTLTimeNodeParallel) obj;
|
||||
CTTLCommonTimeNodeData node = par.getCTn();
|
||||
if (node.getChildTnLst().getParOrSeqOrExcl() != null) {
|
||||
CTTimeNodeList childTimeNodeList = node.getChildTnLst();
|
||||
for (Object object : childTimeNodeList.getParOrSeqOrExcl()) {
|
||||
if (object instanceof CTTLTimeNodeSequence) {
|
||||
CTTLTimeNodeSequence seq = (CTTLTimeNodeSequence) object;
|
||||
if (seq.getCTn().getStCondLst() != null) {
|
||||
CTTLTimeConditionList stCondLst = seq.getCTn().getStCondLst();
|
||||
for (CTTLTimeCondition o : stCondLst.getCond()) {
|
||||
if (o.getEvt() != null) {
|
||||
return o.getEvt().value();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CTTimeNodeList seqNodeList = seq.getCTn().getChildTnLst();
|
||||
for (Object seqObj : seqNodeList.getParOrSeqOrExcl()) {
|
||||
if (seqObj instanceof CTTLTimeNodeSequence) {
|
||||
CTTLTimeNodeSequence seqs = (CTTLTimeNodeSequence) seqObj;
|
||||
if (seqs.getCTn().getStCondLst() != null) {
|
||||
CTTLTimeConditionList stCondLst = seqs.getCTn().getStCondLst();
|
||||
for (CTTLTimeCondition o : stCondLst.getCond()) {
|
||||
if (o.getEvt() != null) {
|
||||
return o.getEvt().value();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CTTimeNodeList seqNodeLists = seqs.getCTn().getChildTnLst();
|
||||
for (Object seqObjs : seqNodeLists.getParOrSeqOrExcl()) {
|
||||
if (seqObjs instanceof CTTLTimeNodeSequence) {
|
||||
CTTLTimeNodeSequence seqss = (CTTLTimeNodeSequence) seqObjs;
|
||||
if (seqss.getCTn().getStCondLst() != null) {
|
||||
CTTLTimeConditionList stCondLst = seqss.getCTn().getStCondLst();
|
||||
for (CTTLTimeCondition o : stCondLst.getCond()) {
|
||||
if (o.getEvt() != null) {
|
||||
return o.getEvt().value();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (seqObj instanceof CTTLTimeNodeParallel) {
|
||||
CTTLTimeNodeParallel seqs = (CTTLTimeNodeParallel) seqObj;
|
||||
if (seqs.getCTn().getStCondLst() != null) {
|
||||
CTTLTimeConditionList stCondLst = seqs.getCTn().getStCondLst();
|
||||
for (CTTLTimeCondition o : stCondLst.getCond()) {
|
||||
if (o.getEvt() != null) {
|
||||
return o.getEvt().value();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CTTimeNodeList seqNodeLists = seqs.getCTn().getChildTnLst();
|
||||
for (Object seqObjs : seqNodeLists.getParOrSeqOrExcl()) {
|
||||
if (seqObjs instanceof CTTLTimeNodeSequence) {
|
||||
CTTLTimeNodeSequence seqss = (CTTLTimeNodeSequence) seqObjs;
|
||||
if (seqss.getCTn().getStCondLst() != null) {
|
||||
CTTLTimeConditionList stCondLst = seqss.getCTn().getStCondLst();
|
||||
for (CTTLTimeCondition o : stCondLst.getCond()) {
|
||||
if (o.getEvt() != null) {
|
||||
return o.getEvt().value();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CTTimeNodeList ctTimeNodeList = timing.getTnLst();
|
||||
if (ctTimeNodeList == null) return "无动画";
|
||||
// 第一层
|
||||
List<Object> parOrSeqOrExcl = ctTimeNodeList.getParOrSeqOrExcl();
|
||||
String value = getAniationInfo(parOrSeqOrExcl, null, String.valueOf(spId), "function");
|
||||
if (!value.isEmpty()) {
|
||||
return value;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// 动画 持续时间
|
||||
public static String getAnimationDuration(Pic sp, CTSlideTiming timing) {
|
||||
if (sp == null || timing == null || timing.getTnLst() == null) return "无动画";
|
||||
|
||||
final String spId = String.valueOf(sp.getNvPicPr().getCNvPr().getId());
|
||||
CTTimeNodeList root = timing.getTnLst();
|
||||
|
||||
// 先找“进入类效果(effect)”
|
||||
String entrance = findFirstBehavior(root, spId, /*preferEntrance=*/true);
|
||||
if (entrance != null) return entrance;
|
||||
|
||||
// 找不到进入类,再找其它类型(运动、旋转、缩放、Set 等)
|
||||
String any = findFirstBehavior(root, spId, /*preferEntrance=*/false);
|
||||
return any != null ? any : "无动画";
|
||||
public static String getAnimationDuration(org.pptx4j.pml.Pic sp, CTSlideTiming timing) {
|
||||
long spId = sp.getNvPicPr().getCNvPr().getId();
|
||||
CTTimeNodeList ctTimeNodeList = timing.getTnLst();
|
||||
if (ctTimeNodeList == null) return "无动画";
|
||||
// 第一层
|
||||
List<Object> parOrSeqOrExcl = ctTimeNodeList.getParOrSeqOrExcl();
|
||||
String value = getAniationInfo(parOrSeqOrExcl, null, String.valueOf(spId), "dur");
|
||||
if (!value.isEmpty()) {
|
||||
return value;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// 动画 延迟
|
||||
public static String getAnimationDelay(Pic sp, CTSlideTiming timing) {
|
||||
// 获取形状中的ID
|
||||
if (sp == null) return "无动画";
|
||||
public static String getAnimationDelay(org.pptx4j.pml.Pic sp, CTSlideTiming timing) {
|
||||
long spId = sp.getNvPicPr().getCNvPr().getId();
|
||||
// 获取动画效果
|
||||
CTTimeNodeList timeNodeList = timing.getTnLst();
|
||||
for (Object obj : timeNodeList.getParOrSeqOrExcl()) {
|
||||
if (obj instanceof CTTLTimeNodeParallel) {
|
||||
CTTLTimeNodeParallel par = (CTTLTimeNodeParallel) obj;
|
||||
CTTLCommonTimeNodeData node = par.getCTn();
|
||||
if (node.getChildTnLst().getParOrSeqOrExcl() != null) {
|
||||
CTTimeNodeList childTimeNodeList = node.getChildTnLst();
|
||||
for (Object object : childTimeNodeList.getParOrSeqOrExcl()) {
|
||||
if (object instanceof CTTLTimeNodeSequence) {
|
||||
CTTLTimeNodeSequence seq = (CTTLTimeNodeSequence) object;
|
||||
if (seq.getCTn().getStCondLst() != null) {
|
||||
CTTLTimeConditionList stCondLst = seq.getCTn().getStCondLst();
|
||||
for (CTTLTimeCondition o : stCondLst.getCond()) {
|
||||
if (o.getEvt() != null) {
|
||||
return o.getDelay();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CTTimeNodeList seqNodeList = seq.getCTn().getChildTnLst();
|
||||
for (Object seqObj : seqNodeList.getParOrSeqOrExcl()) {
|
||||
if (seqObj instanceof CTTLTimeNodeSequence) {
|
||||
CTTLTimeNodeSequence seqs = (CTTLTimeNodeSequence) seqObj;
|
||||
if (seqs.getCTn().getStCondLst() != null) {
|
||||
CTTLTimeConditionList stCondLst = seqs.getCTn().getStCondLst();
|
||||
for (CTTLTimeCondition o : stCondLst.getCond()) {
|
||||
if (o.getEvt() != null) {
|
||||
return o.getDelay();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CTTimeNodeList seqNodeLists = seqs.getCTn().getChildTnLst();
|
||||
for (Object seqObjs : seqNodeLists.getParOrSeqOrExcl()) {
|
||||
if (seqObjs instanceof CTTLTimeNodeSequence) {
|
||||
CTTLTimeNodeSequence seqss = (CTTLTimeNodeSequence) seqObjs;
|
||||
if (seqss.getCTn().getStCondLst() != null) {
|
||||
CTTLTimeConditionList stCondLst = seqss.getCTn().getStCondLst();
|
||||
for (CTTLTimeCondition o : stCondLst.getCond()) {
|
||||
if (o.getEvt() != null) {
|
||||
return o.getDelay();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (seqObj instanceof CTTLTimeNodeParallel) {
|
||||
CTTLTimeNodeParallel seqs = (CTTLTimeNodeParallel) seqObj;
|
||||
if (seqs.getCTn().getStCondLst() != null) {
|
||||
CTTLTimeConditionList stCondLst = seqs.getCTn().getStCondLst();
|
||||
for (CTTLTimeCondition o : stCondLst.getCond()) {
|
||||
if (o.getEvt() != null) {
|
||||
return o.getDelay();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CTTimeNodeList seqNodeLists = seqs.getCTn().getChildTnLst();
|
||||
for (Object seqObjs : seqNodeLists.getParOrSeqOrExcl()) {
|
||||
if (seqObjs instanceof CTTLTimeNodeSequence) {
|
||||
CTTLTimeNodeSequence seqss = (CTTLTimeNodeSequence) seqObjs;
|
||||
if (seqss.getCTn().getStCondLst() != null) {
|
||||
CTTLTimeConditionList stCondLst = seqss.getCTn().getStCondLst();
|
||||
for (CTTLTimeCondition o : stCondLst.getCond()) {
|
||||
if (o.getEvt() != null) {
|
||||
return o.getDelay();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CTTimeNodeList ctTimeNodeList = timing.getTnLst();
|
||||
if (ctTimeNodeList == null) return "无动画";
|
||||
// 第一层
|
||||
List<Object> parOrSeqOrExcl = ctTimeNodeList.getParOrSeqOrExcl();
|
||||
String value = getAniationInfo(parOrSeqOrExcl, null, String.valueOf(spId), "delay");
|
||||
if (!value.isEmpty()) {
|
||||
return value;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
@@ -3,6 +3,13 @@ package pc.exam.pp.module.judgement.utils.wps_pptx.pptx4j;
|
||||
import org.apache.poi.xslf.usermodel.XMLSlideShow;
|
||||
import org.apache.poi.xslf.usermodel.XSLFSlide;
|
||||
import org.apache.xmlbeans.XmlCursor;
|
||||
import org.docx4j.openpackaging.packages.OpcPackage;
|
||||
import org.docx4j.openpackaging.packages.PresentationMLPackage;
|
||||
import org.docx4j.openpackaging.parts.PresentationML.SlidePart;
|
||||
import org.pptx4j.pml.CTSlideTiming;
|
||||
import org.pptx4j.pml.GroupShape;
|
||||
import org.pptx4j.pml.Pic;
|
||||
import org.pptx4j.pml.Shape;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import pc.exam.pp.module.judgement.utils.wps_pptx.pptx4j.vo.SlideDataInfoVO;
|
||||
|
||||
@@ -18,52 +25,42 @@ public class SlideConversion {
|
||||
// 3、获取第三层目录 幻灯片设置/形状 - 幻灯片母版 - 幻灯片设置 - 文件操作
|
||||
public static List<SlideDataInfoVO> SlideDataInfos(MultipartFile file) throws Exception {
|
||||
List<SlideDataInfoVO> dataInfoVOS = new ArrayList<>();
|
||||
try (InputStream inputStream = file.getInputStream();
|
||||
XMLSlideShow pptxXml = new XMLSlideShow(inputStream)) {
|
||||
int index = 0;
|
||||
|
||||
try (InputStream inputStream = file.getInputStream()) {
|
||||
PresentationMLPackage ppt =
|
||||
(PresentationMLPackage) OpcPackage.load(inputStream);
|
||||
// 获取页数
|
||||
List<SlidePart> slideParts = ppt.getMainPresentationPart().getSlideParts();
|
||||
int slideIndexFoFile = 0;
|
||||
String firstId = getStringRandom();
|
||||
setSlideDataInfo(firstId, "", "幻灯片", "slide", "", false, dataInfoVOS);
|
||||
for (XSLFSlide slides : pptxXml.getSlides()){
|
||||
index += 1;
|
||||
for (SlidePart slidePart : slideParts) {
|
||||
slideIndexFoFile ++;
|
||||
String secondId = getStringRandom();
|
||||
setSlideDataInfo(secondId, firstId, "第"+index+"页", "sld", String.valueOf(index), true, dataInfoVOS);
|
||||
setSlideDataInfo(secondId, firstId, "第"+slideIndexFoFile+"页", "sld", String.valueOf(slideIndexFoFile), true, dataInfoVOS);
|
||||
// 获取形状
|
||||
GroupShape spTree = slidePart.getJaxbElement().getCSld().getSpTree();
|
||||
List<Object> shapes = spTree.getSpOrGrpSpOrGraphicFrame();
|
||||
int slideIndexFoShape = 0;
|
||||
// 第三层
|
||||
String thirdId = getStringRandom();
|
||||
int indexCnvPr = 1;
|
||||
setSlideDataInfo(thirdId, secondId, "幻灯片设置", "slideSetting", String.valueOf(index) + "_0", true, dataInfoVOS);
|
||||
XmlCursor spCursor = slides.getXmlObject().newCursor();
|
||||
spCursor.selectPath("declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' .//p:sp");
|
||||
while (spCursor.toNextSelection()) {
|
||||
XmlCursor cNvPrXml = spCursor.newCursor();
|
||||
cNvPrXml.selectPath("declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' .//p:cNvPr/@name");
|
||||
if (cNvPrXml.toNextSelection()) {
|
||||
String name = cNvPrXml.getTextValue();
|
||||
setSlideDataInfo(thirdId, secondId, "幻灯片设置", "slideSetting", String.valueOf(slideIndexFoFile) + "_0", true, dataInfoVOS);
|
||||
for (Object shapeObj : shapes) {
|
||||
slideIndexFoShape ++;
|
||||
// 形状
|
||||
String fourId = getStringRandom();
|
||||
setSlideDataInfo(fourId, secondId, "形状"+indexCnvPr+"->"+name, "shape", String.valueOf(index) + "_" + String.valueOf(indexCnvPr), true, dataInfoVOS);
|
||||
indexCnvPr += 1;
|
||||
if (shapeObj instanceof Shape) {
|
||||
setSlideDataInfo(fourId, secondId, "形状"+slideIndexFoShape+"->"+((Shape) shapeObj).getNvSpPr().getCNvPr().getName(), "shape", String.valueOf(slideIndexFoFile) + "_" + String.valueOf(slideIndexFoShape), true, dataInfoVOS);
|
||||
}
|
||||
if (shapeObj instanceof Pic) {
|
||||
setSlideDataInfo(fourId, secondId, "形状"+slideIndexFoShape+"->"+((Pic) shapeObj).getNvPicPr().getCNvPr().getName(), "shape", String.valueOf(slideIndexFoFile) + "_" + String.valueOf(slideIndexFoShape), true, dataInfoVOS);
|
||||
}
|
||||
XmlCursor picCursor = slides.getXmlObject().newCursor();
|
||||
System.out.println(picCursor.xmlText());
|
||||
picCursor.selectPath("declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' .//p:pic");
|
||||
int indexCnvPrPic = 1;
|
||||
while (picCursor.toNextSelection()) {
|
||||
String fourId = getStringRandom();
|
||||
setSlideDataInfo(fourId, secondId, "图像"+indexCnvPrPic+"->图像", "shapePic", String.valueOf(indexCnvPrPic), true, dataInfoVOS);
|
||||
indexCnvPrPic += 1;
|
||||
}
|
||||
}
|
||||
// 设置
|
||||
String firstIds = getStringRandom();
|
||||
setSlideDataInfo(firstIds, "", "设置", "presentation", String.valueOf(0), false, dataInfoVOS);
|
||||
String secondIds = getStringRandom();
|
||||
setSlideDataInfo(secondIds, firstIds, "幻灯片设置", "presentation", String.valueOf(0), true, dataInfoVOS);
|
||||
|
||||
// 母版
|
||||
// String dFirstId = getStringRandom();
|
||||
// setPptxInfo("母版", "p:sld", "p:sld", filePath, dFirstId, "0", pptxInfoReqVos);
|
||||
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
return dataInfoVOS;
|
||||
}
|
||||
|
Reference in New Issue
Block a user