Merge branch 'master' of http://47.101.60.131:10082/Exam/pengchen-exam-java-localhost into hyc
This commit is contained in:
3715
logs/log.log
3715
logs/log.log
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,21 +1,116 @@
|
||||
package com.example.exam.exam.service.wpspptx.pptx4j;
|
||||
|
||||
import jakarta.xml.bind.JAXBElement;
|
||||
import org.docx4j.dml.*;
|
||||
import org.pptx4j.pml.*;
|
||||
import com.example.exam.exam.service.wpspptx.pptx4j.utils.PtToCmConverter;
|
||||
import com.example.exam.exam.service.wpspptx.pptx4j.utils.Transition;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
|
||||
public class ShapePic {
|
||||
|
||||
// 图片 插入
|
||||
public static String getAddPic(Pic sp, CTSlideTiming timing) {
|
||||
return "是";
|
||||
}
|
||||
|
||||
// 媒体 放映时隐藏
|
||||
public static String getMediaHide(Pic sp, CTSlideTiming timing) {
|
||||
// 获取ID
|
||||
long id = sp.getNvPicPr().getCNvPr().getId();
|
||||
CTTimeNodeList ctTimeNodeList = timing.getTnLst();
|
||||
List<Object> parOrSeqOrExcl = ctTimeNodeList.getParOrSeqOrExcl();
|
||||
for (Object o : parOrSeqOrExcl) {
|
||||
if (o instanceof CTTLTimeNodeParallel) {
|
||||
CTTimeNodeList ctTimeNodes = ((CTTLTimeNodeParallel) o).getCTn().getChildTnLst();
|
||||
for (Object o1 : ctTimeNodes.getParOrSeqOrExcl()) {
|
||||
if (o1 instanceof CTTLMediaNodeVideo) {
|
||||
// 获取spId
|
||||
String spId = ((CTTLMediaNodeVideo) o1).getCMediaNode().getTgtEl().getSpTgt().getSpid();
|
||||
if (String.valueOf(id).equals(spId)) {
|
||||
return ((CTTLMediaNodeVideo) o1).getCMediaNode().isShowWhenStopped() ? "否" : "是";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// 媒体 播放完返回开头
|
||||
public static String getMediaLoop(Pic sp, CTSlideTiming timing) {
|
||||
// 获取ID
|
||||
long id = sp.getNvPicPr().getCNvPr().getId();
|
||||
CTTimeNodeList ctTimeNodeList = timing.getTnLst();
|
||||
List<Object> parOrSeqOrExcl = ctTimeNodeList.getParOrSeqOrExcl();
|
||||
for (Object o : parOrSeqOrExcl) {
|
||||
if (o instanceof CTTLTimeNodeParallel) {
|
||||
CTTimeNodeList ctTimeNodes = ((CTTLTimeNodeParallel) o).getCTn().getChildTnLst();
|
||||
for (Object o1 : ctTimeNodes.getParOrSeqOrExcl()) {
|
||||
if (o1 instanceof CTTLMediaNodeVideo) {
|
||||
// 获取spId
|
||||
String spId = ((CTTLMediaNodeVideo) o1).getCMediaNode().getTgtEl().getSpTgt().getSpid();
|
||||
if (String.valueOf(id).equals(spId)) {
|
||||
STTLTimeNodeFillType sttlTimeNodeFillType = ((CTTLMediaNodeVideo) o1).getCMediaNode().getCTn().getFill();
|
||||
String value = sttlTimeNodeFillType.value();
|
||||
return value.equals("remove") ? "是" : "否";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// 自选图形 - 类型
|
||||
public static String getShapeType(Pic sp, CTSlideTiming timing) {
|
||||
CTShapeProperties ctShapeProperties = sp.getSpPr();
|
||||
CTPresetGeometry2D prst = ctShapeProperties.getPrstGeom();
|
||||
if (prst != null && prst.getPrst() != null) {
|
||||
STShapeType t = prst.getPrst();
|
||||
switch (t) {
|
||||
case HEXAGON:
|
||||
return "六边形";
|
||||
case RECT:
|
||||
return "矩形";
|
||||
case ROUND_RECT:
|
||||
return "圆角矩形";
|
||||
case ELLIPSE:
|
||||
return "椭圆";
|
||||
case TRIANGLE:
|
||||
return "三角形";
|
||||
case DIAMOND:
|
||||
return "菱形";
|
||||
case PARALLELOGRAM:
|
||||
return "平行四边形";
|
||||
case TRAPEZOID:
|
||||
return "梯形";
|
||||
case OCTAGON:
|
||||
return "八边形";
|
||||
case PENTAGON:
|
||||
return "五边形";
|
||||
default:
|
||||
return "预设形状:" + t.value();
|
||||
}
|
||||
}
|
||||
if (ctShapeProperties.getCustGeom() != null) {
|
||||
return "自定义几何(custGeom)";
|
||||
}
|
||||
return "未指定几何";
|
||||
}
|
||||
|
||||
// 大小 - 高度
|
||||
public static String getShapeSizeHeight(Pic sp, CTSlideTiming timing) {
|
||||
CTTransform2D xfrm = sp.getSpPr().getXfrm();
|
||||
// 获取位置和尺寸(单位 EMU,1英寸=914400 EMU,1cm≈360000 EMU)
|
||||
CTPositiveSize2D ext = xfrm.getExt(); // 尺寸
|
||||
double heightPt = emuToPt(ext.getCy());
|
||||
return String.valueOf(heightPt);
|
||||
// 转换成磅
|
||||
double pt = Math.round(heightPt * 100.0) / 100.0;
|
||||
// 转换成厘米
|
||||
double cm = PtToCmConverter.pointsToCm(pt);
|
||||
return pt + "磅(" + cm + "厘米)";
|
||||
}
|
||||
|
||||
// 大小 - 宽度
|
||||
@@ -24,29 +119,20 @@ public class ShapePic {
|
||||
// 获取位置和尺寸(单位 EMU,1英寸=914400 EMU,1cm≈360000 EMU)
|
||||
CTPositiveSize2D ext = xfrm.getExt(); // 尺寸
|
||||
double widthPt = emuToPt(ext.getCx());
|
||||
return String.valueOf(widthPt);
|
||||
// 转换成磅
|
||||
double pt = Math.round(widthPt * 100.0) / 100.0;
|
||||
// 转换成厘米
|
||||
double cm = PtToCmConverter.pointsToCm(pt);
|
||||
return pt + "磅(" + cm + "厘米)";
|
||||
}
|
||||
|
||||
// 大小 - 锁定纵横比
|
||||
public static String getShapeSizeLockAspectRatio(Pic sp, CTSlideTiming timing) {
|
||||
CTTransform2D xfrm = sp.getSpPr().getXfrm();
|
||||
// 获取位置和尺寸(单位 EMU,1英寸=914400 EMU,1cm≈360000 EMU)
|
||||
CTPositiveSize2D ext = xfrm.getExt(); // 尺寸
|
||||
Boolean lockAspectRatio = null;
|
||||
if (sp.getSpPr().getPrstGeom() != null &&
|
||||
sp.getSpPr().getPrstGeom().getAvLst() != null) {
|
||||
// 这个部分一般不会直接提供锁定横纵比,要看 spPr.getExtLst()
|
||||
if (sp.getSpPr().getExtLst() != null) {
|
||||
// pptx4j 没有直接的 getter,要自己解析 XML
|
||||
String xml = sp.getSpPr().getExtLst().toString();
|
||||
if (xml.contains("lockAspectRatio=\"1\"") || xml.contains("lockAspectRatio=\"true\"")) {
|
||||
lockAspectRatio = true;
|
||||
} else if (xml.contains("lockAspectRatio=\"0\"") || xml.contains("lockAspectRatio=\"false\"")) {
|
||||
lockAspectRatio = false;
|
||||
}
|
||||
}
|
||||
CTPictureLocking ctPictureLocking = sp.getNvPicPr().getCNvPicPr().getPicLocks();
|
||||
if (ctPictureLocking != null) {
|
||||
return ctPictureLocking.isNoChangeAspect() ? "是" : "否";
|
||||
}
|
||||
return String.valueOf(lockAspectRatio);
|
||||
return "否";
|
||||
}
|
||||
|
||||
// EMU 转 pt
|
||||
@@ -183,9 +269,19 @@ public class ShapePic {
|
||||
if (spPr != null && spPr.getLn() != null) {
|
||||
CTLineProperties ln = spPr.getLn();
|
||||
// 颜色
|
||||
if (ln.getSolidFill() != null && ln.getSolidFill().getSrgbClr() != null) {
|
||||
if (ln.getSolidFill() != null) {
|
||||
CTSRgbColor rgb = ln.getSolidFill().getSrgbClr();
|
||||
return rgb.getVal();
|
||||
if (rgb != null) {
|
||||
return rgb.getVal();
|
||||
}
|
||||
CTScRgbColor scrgb = ln.getSolidFill().getScrgbClr();
|
||||
if (scrgb != null) {
|
||||
return "RGB(" + scrgb.getR() + "," + scrgb.getG() + "," + scrgb.getB() + ")";
|
||||
}
|
||||
CTSchemeColor ctSchemeColor = ln.getSolidFill().getSchemeClr();
|
||||
if (ctSchemeColor != null) {
|
||||
return ctSchemeColor.getVal().value();
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
@@ -261,6 +357,7 @@ public class ShapePic {
|
||||
// 3) 未设置 → 视为实线
|
||||
return "solid";
|
||||
}
|
||||
|
||||
// 形状线条 开始箭头类型
|
||||
public static String getShapeLineStartArrow(Pic sp, CTSlideTiming timing) {
|
||||
CTShapeProperties spPr = sp.getSpPr();
|
||||
@@ -272,14 +369,17 @@ public class ShapePic {
|
||||
}
|
||||
return "无箭头";
|
||||
}
|
||||
|
||||
// 形状线条 开始箭头粗细
|
||||
public static String getShapeLineStartArrowWidth(Pic sp, CTSlideTiming timing) {
|
||||
return "待开发";
|
||||
}
|
||||
|
||||
// 形状线条 结尾箭头类型
|
||||
public static String getShapeLineEndArrow(Pic sp, CTSlideTiming timing) {
|
||||
return "待开发";
|
||||
}
|
||||
|
||||
// 形状线条 结尾箭头粗细
|
||||
public static String getShapeLineEndArrowWidth(Pic sp, CTSlideTiming timing) {
|
||||
return "待开发";
|
||||
@@ -302,12 +402,12 @@ public class ShapePic {
|
||||
// 形状效果 阴影-效果
|
||||
public static String getShapeShadowEffect(Pic sp, CTSlideTiming timing) {
|
||||
if (sp == null || sp.getSpPr() == null) {
|
||||
return "无阴影";
|
||||
return "否";
|
||||
}
|
||||
CTShapeProperties spPr = sp.getSpPr();
|
||||
CTEffectList effList = spPr.getEffectLst();
|
||||
if (effList == null) {
|
||||
return "无阴影";
|
||||
return "否";
|
||||
}
|
||||
|
||||
if (effList.getOuterShdw() != null) {
|
||||
@@ -317,7 +417,7 @@ public class ShapePic {
|
||||
} else if (effList.getPrstShdw() != null) {
|
||||
return "预设阴影";
|
||||
}
|
||||
return "无阴影";
|
||||
return "否";
|
||||
}
|
||||
|
||||
// 形状效果 倒影-绘制
|
||||
@@ -325,21 +425,21 @@ public class ShapePic {
|
||||
CTShapeProperties spPr = sp.getSpPr();
|
||||
CTEffectList effList = spPr.getEffectLst();
|
||||
if (effList == null) {
|
||||
return "无倒影";
|
||||
return "否";
|
||||
}
|
||||
|
||||
CTReflectionEffect reflection = effList.getReflection();
|
||||
if (reflection != null) {
|
||||
// 如果需要详细参数,这里可以读取
|
||||
return "有倒影";
|
||||
return "是";
|
||||
}
|
||||
return "无倒影";
|
||||
return "否";
|
||||
}
|
||||
|
||||
// 形状效果 倒影-效果
|
||||
public static String getShapeReflectionEffect(Pic sp, CTSlideTiming timing) {
|
||||
CTReflectionEffect r = SlideUtils.getReflectionPic(sp);
|
||||
if (r == null) return "无倒影";
|
||||
if (r == null) return "否";
|
||||
|
||||
// —— 1) 倒影覆盖程度:用 stPos/endPos(0..100000)估算 —— //
|
||||
double st = SlideUtils.to100k(BigInteger.valueOf(r.getStPos()), 0);
|
||||
@@ -352,12 +452,12 @@ public class ShapePic {
|
||||
} else if (coverage >= 0.45) {
|
||||
coverageLabel = "半倒影";
|
||||
} else {
|
||||
coverageLabel = "短倒影";
|
||||
coverageLabel = "紧密倒影";
|
||||
}
|
||||
|
||||
// —— 2) 偏移描述:dist EMU -> pt;<1pt 视作“紧贴”,否则 "Xpt 偏移" —— //
|
||||
// —— 2) 偏移描述:dist EMU -> pt;<1pt 视作“接触”,否则 "Xpt 偏移" —— //
|
||||
double distPt = emuToPt(r.getDist()); // 可能为 0
|
||||
String offsetLabel = distPt < 1.0 ? "紧贴" : (SlideUtils.fmt1(distPt) + "pt 偏移");
|
||||
String offsetLabel = distPt < 1.0 ? "接触" : (SlideUtils.fmt1(distPt) + "pt 偏移");
|
||||
|
||||
return coverageLabel + " " + offsetLabel;
|
||||
}
|
||||
@@ -367,7 +467,7 @@ public class ShapePic {
|
||||
if (sp == null || sp.getSpPr() == null) return null;
|
||||
CTShapeProperties spPr = sp.getSpPr();
|
||||
CTEffectList eff = spPr.getEffectLst();
|
||||
return (eff != null) ? eff.getGlow().toString() : null;
|
||||
return (eff != null) ? "是" : "否";
|
||||
}
|
||||
|
||||
// 形状效果 发光-效果
|
||||
@@ -386,14 +486,17 @@ public class ShapePic {
|
||||
CTSoftEdgesEffect se = getSoftEdge(sp);
|
||||
return (se != null) ? String.valueOf(se.getRad()) : null;
|
||||
}
|
||||
|
||||
// 形状效果 三维效果→绘制
|
||||
public static String getShape3DEffectDraw(Pic sp, CTSlideTiming timing) {
|
||||
return "待开发";
|
||||
}
|
||||
|
||||
// 形状效果 三维格式→效果
|
||||
public static String getShape3DEffect(Pic sp, CTSlideTiming timing) {
|
||||
return "待开发";
|
||||
}
|
||||
|
||||
// 形状效果 三维旋转→效果
|
||||
public static String getShape3DRotation(Pic sp, CTSlideTiming timing) {
|
||||
return "待开发";
|
||||
@@ -410,7 +513,7 @@ public class ShapePic {
|
||||
|
||||
|
||||
// 动画 效果
|
||||
public static String getAnimation(org.pptx4j.pml.Pic sp, CTSlideTiming timing) {
|
||||
public static String getAnimation(Pic sp, CTSlideTiming timing) {
|
||||
long spId = sp.getNvPicPr().getCNvPr().getId();
|
||||
CTTimeNodeList ctTimeNodeList = timing.getTnLst();
|
||||
if (ctTimeNodeList == null) return "无动画";
|
||||
@@ -418,19 +521,74 @@ public class ShapePic {
|
||||
List<Object> parOrSeqOrExcl = ctTimeNodeList.getParOrSeqOrExcl();
|
||||
String value = getAniationInfo(parOrSeqOrExcl, null, String.valueOf(spId), "type");
|
||||
if (!value.isEmpty()) {
|
||||
return value;
|
||||
String type = value.split("-")[0];
|
||||
// 动画类别
|
||||
String presetClass = value.split("-")[1];
|
||||
String presetClassCn = Transition.presetClass(presetClass);
|
||||
// 动画效果
|
||||
String presetID = value.split("-")[2];
|
||||
return presetClassCn + "->" + presetID;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public static String getAniationInfo(List<Object> objects, List<Object> upObjects, String spId, String parameter) {
|
||||
boolean isDur = false;
|
||||
boolean isDirection = false;
|
||||
for (Object object : objects) {
|
||||
// 判断持续时间
|
||||
if (isDur) {
|
||||
if (object instanceof CTTLAnimateEffectBehavior) {
|
||||
return ((CTTLAnimateEffectBehavior) object).getCBhvr().getCTn().getDur();
|
||||
}
|
||||
}
|
||||
// 判断方向
|
||||
if (isDirection) {
|
||||
if (object instanceof CTTLAnimateEffectBehavior) {
|
||||
return Transition.effectWithDirToChinese(((CTTLAnimateEffectBehavior) object).getFilter());
|
||||
} else {
|
||||
// 获取行动轨迹
|
||||
for (Object ob : objects) {
|
||||
if (ob instanceof CTTLAnimateBehavior) {
|
||||
List<CTTLTimeAnimateValue> cttlTimeAnimateValues = ((CTTLAnimateBehavior) ob).getTavLst().getTav();
|
||||
for (CTTLTimeAnimateValue cttlTimeAnimateValue : cttlTimeAnimateValues) {
|
||||
if (cttlTimeAnimateValue.getVal().getStrVal().getVal().contains("0-#ppt_h/") ||
|
||||
cttlTimeAnimateValue.getVal().getStrVal().getVal().contains("-#ppt_h")) {
|
||||
return "自顶部";
|
||||
}
|
||||
if (cttlTimeAnimateValue.getVal().getStrVal().getVal().contains("#ppt_h+") ||
|
||||
cttlTimeAnimateValue.getVal().getStrVal().getVal().contains("+#ppt_h")) {
|
||||
return "自底部";
|
||||
}
|
||||
if (cttlTimeAnimateValue.getVal().getStrVal().getVal().contains("+#ppt_w") ||
|
||||
cttlTimeAnimateValue.getVal().getStrVal().getVal().contains("#ppt_w+")) {
|
||||
return "自右侧";
|
||||
}
|
||||
if (cttlTimeAnimateValue.getVal().getStrVal().getVal().contains("0-#ppt_w/") ||
|
||||
cttlTimeAnimateValue.getVal().getStrVal().getVal().contains("-#ppt_w") ||
|
||||
cttlTimeAnimateValue.getVal().getStrVal().getVal().contains("-N")) {
|
||||
return "自左侧";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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();
|
||||
isDur = true;
|
||||
String dur = ((CTTLSetBehavior) object).getCBhvr().getCTn().getDur();
|
||||
if (dur != null) {
|
||||
return dur;
|
||||
}
|
||||
|
||||
}
|
||||
if (parameter.equals("direction")) {
|
||||
isDirection = true;
|
||||
}
|
||||
// 向上获取延迟
|
||||
for (Object upObject : upObjects) {
|
||||
@@ -438,10 +596,13 @@ public class ShapePic {
|
||||
// 获取动画效果
|
||||
if (parameter.equals("type")) {
|
||||
Integer type = ((CTTLTimeNodeParallel) upObject).getCTn().getPresetSubtype();
|
||||
return String.valueOf(type);
|
||||
String presetClass = ((CTTLTimeNodeParallel) upObject).getCTn().getPresetClass().value();
|
||||
Integer presetID = ((CTTLTimeNodeParallel) upObject).getCTn().getPresetID();
|
||||
return type + "-" + presetClass + "-" + presetID;
|
||||
}
|
||||
// 触发方式
|
||||
if (parameter.equals("function")) {
|
||||
String CTTLTimeNodeParallelFunction = ((CTTLTimeNodeParallel) upObject).getCTn().getNodeType().value();
|
||||
return ((CTTLTimeNodeParallel) upObject).getCTn().getNodeType().value();
|
||||
}
|
||||
// 获取延迟方法
|
||||
@@ -454,9 +615,28 @@ public class ShapePic {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (upObject instanceof CTTLCommonTimeNodeData) {
|
||||
// 获取动画效果
|
||||
if (parameter.equals("type")) {
|
||||
Integer type = ((CTTLCommonTimeNodeData) upObject).getPresetSubtype();
|
||||
String presetClass = ((CTTLCommonTimeNodeData) upObject).getPresetClass().value();
|
||||
Integer presetID = ((CTTLCommonTimeNodeData) upObject).getPresetID();
|
||||
return type + "-" + presetClass + "-" + presetID;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 特殊取值的情况
|
||||
if (object instanceof CTTLCommonTimeNodeData) {
|
||||
// 获取动画效果
|
||||
if (parameter.equals("type")) {
|
||||
Integer type = ((CTTLCommonTimeNodeData) object).getPresetSubtype();
|
||||
String presetClass = ((CTTLCommonTimeNodeData) object).getPresetClass().value();
|
||||
Integer presetID = ((CTTLCommonTimeNodeData) object).getPresetID();
|
||||
return type + "-" + presetClass + "-" + presetID;
|
||||
}
|
||||
}
|
||||
if (object instanceof CTTLTimeNodeParallel obj) {
|
||||
String result = getAniationInfo(obj.getCTn().getChildTnLst().getParOrSeqOrExcl(), objects, spId, parameter);
|
||||
if (!result.isEmpty()) {
|
||||
@@ -475,12 +655,21 @@ public class ShapePic {
|
||||
}
|
||||
|
||||
// 动画-方向
|
||||
public static String getAnimateDirection(org.pptx4j.pml.Pic sp, CTSlideTiming timing) {
|
||||
return "待开发";
|
||||
public static String getAnimateDirection(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), "direction");
|
||||
if (!value.isEmpty()) {
|
||||
return value;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// 动画 触发方式
|
||||
public static String getAnimateTrigger(org.pptx4j.pml.Pic sp, CTSlideTiming timing) {
|
||||
public static String getAnimateTrigger(Pic sp, CTSlideTiming timing) {
|
||||
long spId = sp.getNvPicPr().getCNvPr().getId();
|
||||
CTTimeNodeList ctTimeNodeList = timing.getTnLst();
|
||||
if (ctTimeNodeList == null) return "无动画";
|
||||
@@ -488,13 +677,13 @@ public class ShapePic {
|
||||
List<Object> parOrSeqOrExcl = ctTimeNodeList.getParOrSeqOrExcl();
|
||||
String value = getAniationInfo(parOrSeqOrExcl, null, String.valueOf(spId), "function");
|
||||
if (!value.isEmpty()) {
|
||||
return value;
|
||||
return Transition.toCn(value);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// 动画 持续时间
|
||||
public static String getAnimationDuration(org.pptx4j.pml.Pic sp, CTSlideTiming timing) {
|
||||
public static String getAnimationDuration(Pic sp, CTSlideTiming timing) {
|
||||
long spId = sp.getNvPicPr().getCNvPr().getId();
|
||||
CTTimeNodeList ctTimeNodeList = timing.getTnLst();
|
||||
if (ctTimeNodeList == null) return "无动画";
|
||||
@@ -502,13 +691,13 @@ public class ShapePic {
|
||||
List<Object> parOrSeqOrExcl = ctTimeNodeList.getParOrSeqOrExcl();
|
||||
String value = getAniationInfo(parOrSeqOrExcl, null, String.valueOf(spId), "dur");
|
||||
if (!value.isEmpty()) {
|
||||
return value;
|
||||
return (double) Integer.parseInt(value) / 1000 + "秒";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// 动画 延迟
|
||||
public static String getAnimationDelay(org.pptx4j.pml.Pic sp, CTSlideTiming timing) {
|
||||
public static String getAnimationDelay(Pic sp, CTSlideTiming timing) {
|
||||
long spId = sp.getNvPicPr().getCNvPr().getId();
|
||||
CTTimeNodeList ctTimeNodeList = timing.getTnLst();
|
||||
if (ctTimeNodeList == null) return "无动画";
|
||||
@@ -516,9 +705,11 @@ public class ShapePic {
|
||||
List<Object> parOrSeqOrExcl = ctTimeNodeList.getParOrSeqOrExcl();
|
||||
String value = getAniationInfo(parOrSeqOrExcl, null, String.valueOf(spId), "delay");
|
||||
if (!value.isEmpty()) {
|
||||
return value;
|
||||
return (double) Integer.parseInt(value) / 1000 + "秒";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/// 形状动作,鼠标单机-动作
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,17 +1,91 @@
|
||||
package com.example.exam.exam.service.wpspptx.pptx4j;
|
||||
|
||||
import org.docx4j.openpackaging.exceptions.Docx4JException;
|
||||
import org.docx4j.openpackaging.packages.PresentationMLPackage;
|
||||
import org.docx4j.openpackaging.parts.PresentationML.SlidePart;
|
||||
import org.docx4j.openpackaging.parts.PresentationML.MainPresentationPart;
|
||||
import org.pptx4j.pml.CTShowInfoKiosk;
|
||||
import org.pptx4j.pml.Presentation;
|
||||
import org.pptx4j.pml.PresentationPr;
|
||||
import com.example.exam.exam.service.wpspptx.pptx4j.utils.PptxUtils;
|
||||
import com.example.exam.exam.service.wpspptx.pptx4j.utils.PtToCmConverter;
|
||||
import com.example.exam.exam.service.wpspptx.pptx4j.utils.PtToEmuConverter;
|
||||
|
||||
public class SlideAllSetting {
|
||||
// 设计 主题模板
|
||||
public static String getAllSlideTheme( SlidePart slidePart, PresentationMLPackage presentation) throws Docx4JException {
|
||||
public static String getAllSlideTheme(MainPresentationPart mpp, PresentationPr presentationPr) {
|
||||
// 获取第一个幻灯片母版(通常主主题在这里)
|
||||
return "WPS";
|
||||
}
|
||||
|
||||
// 幻灯片切换 切换声音
|
||||
// 幻灯片放映
|
||||
// 幻灯片放映-放映类型
|
||||
public static String getAllSlideShowType(MainPresentationPart mpp, PresentationPr presentationPr) {
|
||||
|
||||
CTShowInfoKiosk ctShowInfoKiosk = presentationPr.getShowPr().getKiosk();
|
||||
if (ctShowInfoKiosk != null) {
|
||||
return "在展台浏览(全屏)";
|
||||
} else {
|
||||
return "演示者放映(全屏)";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 幻灯片放映-循环播放,按ESC键终止
|
||||
public static String getAllSlideShowLoop(MainPresentationPart mpp, PresentationPr presentationPr) {
|
||||
return presentationPr.getShowPr().isLoop() ? "是" : "否";
|
||||
}
|
||||
|
||||
// 幻灯片放映-放映范围
|
||||
public static String getAllSlideShowRange(MainPresentationPart mpp, PresentationPr presentationPr) {
|
||||
long st = presentationPr.getShowPr().getSldRg().getSt();
|
||||
long end = presentationPr.getShowPr().getSldRg().getEnd();
|
||||
return "第" + st + "页-第" + end + "页";
|
||||
}
|
||||
|
||||
// 幻灯片大小 幻灯片大小
|
||||
public static String getAllSlideSize(MainPresentationPart mpp, PresentationPr presentationPr) {
|
||||
// 拿到 JAXB 模型对象
|
||||
Presentation pres = (Presentation) mpp.getJaxbElement();
|
||||
int cx = pres.getSldSz().getCx();
|
||||
int cy = pres.getSldSz().getCy();
|
||||
return PptxUtils.detectAspectName(cx, cy);
|
||||
}
|
||||
|
||||
//幻灯片大小 宽度
|
||||
public static String getAllSlideSizeCx(MainPresentationPart mpp, PresentationPr presentationPr) {
|
||||
// 拿到 JAXB 模型对象
|
||||
Presentation pres = (Presentation) mpp.getJaxbElement();
|
||||
int cx = pres.getSldSz().getCx();
|
||||
return PtToEmuConverter.emuToPt(cx)+ "磅("+ PtToCmConverter.pointsToCm(PtToEmuConverter.emuToPt(cx))+"厘米)";
|
||||
}
|
||||
|
||||
//幻灯片大小 高度
|
||||
public static String getAllSlideSizeCy(MainPresentationPart mpp, PresentationPr presentationPr) {
|
||||
// 拿到 JAXB 模型对象
|
||||
Presentation pres = (Presentation) mpp.getJaxbElement();
|
||||
int cy = pres.getSldSz().getCy();
|
||||
return PtToEmuConverter.emuToPt(cy)+ "磅("+ PtToCmConverter.pointsToCm(PtToEmuConverter.emuToPt(cy))+"厘米)";
|
||||
}
|
||||
|
||||
// 幻灯片大小 幻灯片编号起始值
|
||||
public static String getAllSlideSizeStartNum(MainPresentationPart mpp, PresentationPr presentationPr) {
|
||||
// 拿到 JAXB 模型对象
|
||||
Presentation pres = (Presentation) mpp.getJaxbElement();
|
||||
int firstNum = pres.getFirstSlideNum();
|
||||
return String.valueOf(firstNum);
|
||||
}
|
||||
|
||||
// 幻灯片大小 方向
|
||||
public static String getAllSlideSizeOrientation(MainPresentationPart mpp, PresentationPr presentationPr) {
|
||||
Presentation pres = (Presentation) mpp.getJaxbElement();
|
||||
int cy = pres.getSldSz().getCy();
|
||||
int cx = pres.getSldSz().getCx();
|
||||
return cy > cx ? "纵向" : "横向";
|
||||
}
|
||||
|
||||
// 幻灯片大小 备注方向
|
||||
public static String getAllSlideSizeNoteOrientation(MainPresentationPart mpp, PresentationPr presentationPr) {
|
||||
Presentation pres = (Presentation) mpp.getJaxbElement();
|
||||
long cy = pres.getNotesSz().getCy();
|
||||
long cx = pres.getNotesSz().getCx();
|
||||
return cx > cy ? "横向" : "纵向";
|
||||
}
|
||||
}
|
||||
|
@@ -5,13 +5,11 @@ import com.example.exam.exam.service.wpspptx.pptx4j.vo.WpsSlideInfoVo;
|
||||
import org.docx4j.openpackaging.exceptions.Docx4JException;
|
||||
import org.docx4j.openpackaging.packages.OpcPackage;
|
||||
import org.docx4j.openpackaging.packages.PresentationMLPackage;
|
||||
import org.docx4j.openpackaging.parts.PresentationML.MainPresentationPart;
|
||||
import org.docx4j.openpackaging.parts.PresentationML.SlideMasterPart;
|
||||
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.pptx4j.pml.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -20,8 +18,9 @@ import java.util.List;
|
||||
|
||||
public class SlideMaster {
|
||||
|
||||
|
||||
public static List<JudgementSlidesVO> slideMaster(List<WpsSlideInfoVo> wpsSlideInfoVos, MultipartFile file) throws IOException, Docx4JException {
|
||||
// isFile files = new isFile("E:\\Project\\Exam\\Software\\Temp\\1.pptx");
|
||||
// File files = new File("E:\\Project\\Exam\\Software\\Temp\\1.pptx");
|
||||
List<JudgementSlidesVO> judgementSlidesVOS = new ArrayList<>();
|
||||
// 1、获取想要判断的文件地址(文件流)
|
||||
try (InputStream inputStream = file.getInputStream()) {
|
||||
@@ -29,6 +28,8 @@ public class SlideMaster {
|
||||
// 加载 .pptx 文件
|
||||
PresentationMLPackage ppt =
|
||||
(PresentationMLPackage) OpcPackage.load(inputStream);
|
||||
// 获取母版
|
||||
SlideMasterPart slideMasterPart = SlideMasterUtils.getSlideMaster(ppt);
|
||||
// 你可以在这里处理 ppt,比如读取文字、页数等
|
||||
for (WpsSlideInfoVo wpsSlideInfoVo : wpsSlideInfoVos) {
|
||||
// 幻灯片位置(第几张幻灯片)
|
||||
@@ -44,79 +45,96 @@ public class SlideMaster {
|
||||
String examCode = wpsSlideInfoVo.getExamCode();
|
||||
// 方式方法
|
||||
String method = wpsSlideInfoVo.getMethod();
|
||||
|
||||
String content = wpsSlideInfoVo.getSlideIndex() + "@" + firstName + "@" + function + "@" + examName + "@" + examCode + "@" + method;
|
||||
// 查询幻灯片图片
|
||||
List<SlidePart> slideParts = ppt.getMainPresentationPart().getSlideParts();
|
||||
int slideIndexFoFile = 0;
|
||||
for (SlidePart slidePart : slideParts) {
|
||||
slideIndexFoFile++;
|
||||
if (method.equals("shape")) {
|
||||
// 获取幻灯片内容
|
||||
if (slideIndex.equals(String.valueOf(slideIndexFoFile))) {
|
||||
// 查询幻灯片
|
||||
// 遍历 shape tree 中的 sp(shape)元素
|
||||
GroupShape spTree = slidePart.getJaxbElement().getCSld().getSpTree();
|
||||
CTSlideTiming timing = slidePart.getJaxbElement().getTiming();
|
||||
List<Object> shapes = spTree.getSpOrGrpSpOrGraphicFrame();
|
||||
int shapeIndexFoFile = 0;
|
||||
for (Object shapeObj : shapes) {
|
||||
shapeIndexFoFile++;
|
||||
if (shapeObj instanceof Shape shape) {
|
||||
if (shapeIndex.equals(String.valueOf(shapeIndexFoFile))) {
|
||||
// 目标对象
|
||||
ShapePage shapeFunction = new ShapePage();
|
||||
// 获取参数中类型的定义
|
||||
Class<?>[] paramTypes = {Shape.class, CTSlideTiming.class};
|
||||
// 带参数的方法调用示例
|
||||
Method methodWithArgs = shapeFunction.getClass().getMethod(function, paramTypes);
|
||||
// 实际参数值
|
||||
Object[] arguments = {shape, timing};
|
||||
String value = (String) methodWithArgs.invoke(shapeFunction, arguments);
|
||||
if (!value.isEmpty()) {
|
||||
JudgementSlidesVO judgementSlidesVO = new JudgementSlidesVO();
|
||||
judgementSlidesVO.setContent(content + "@" + value);
|
||||
judgementSlidesVO.setContentIn(firstName + examName + value);
|
||||
judgementSlidesVO.setScoreRate(1);
|
||||
judgementSlidesVOS.add(judgementSlidesVO);
|
||||
// 获取整个ppt文件的设置
|
||||
if (method.equals("slideAllSetting")) {
|
||||
MainPresentationPart mpp = ppt.getMainPresentationPart();
|
||||
PresentationPr presentationPr = SlideMasterUtils.getPresentationPr(ppt);
|
||||
SlideAllSetting slideAllSettingFunction = new SlideAllSetting();
|
||||
Class<?>[] paramTypes = {MainPresentationPart.class, PresentationPr.class};
|
||||
Method methodWithArgs = slideAllSettingFunction.getClass().getMethod(function, paramTypes);
|
||||
Object[] arguments = {mpp, presentationPr};
|
||||
String value = (String) methodWithArgs.invoke(slideAllSettingFunction, arguments);
|
||||
if (!value.isEmpty()) {
|
||||
JudgementSlidesVO judgementSlidesVO = new JudgementSlidesVO();
|
||||
judgementSlidesVO.setContent(content + "@" + value);
|
||||
judgementSlidesVO.setContentIn(firstName + examName + value);
|
||||
judgementSlidesVO.setScoreRate(1);
|
||||
judgementSlidesVOS.add(judgementSlidesVO);
|
||||
}
|
||||
} else {
|
||||
// 查询幻灯片图片
|
||||
List<SlidePart> slideParts = ppt.getMainPresentationPart().getSlideParts();
|
||||
int slideIndexFoFile = 0;
|
||||
for (SlidePart slidePart : slideParts) {
|
||||
slideIndexFoFile++;
|
||||
if (method.equals("shape")) {
|
||||
// 获取幻灯片内容
|
||||
if (slideIndex.equals(String.valueOf(slideIndexFoFile))) {
|
||||
// 查询幻灯片
|
||||
// 遍历 shape tree 中的 sp(shape)元素
|
||||
GroupShape spTree = slidePart.getJaxbElement().getCSld().getSpTree();
|
||||
CTSlideTiming timing = slidePart.getJaxbElement().getTiming();
|
||||
List<Object> shapes = spTree.getSpOrGrpSpOrGraphicFrame();
|
||||
int shapeIndexFoFile = 0;
|
||||
for (Object shapeObj : shapes) {
|
||||
shapeIndexFoFile++;
|
||||
if (shapeObj instanceof Shape shape) {
|
||||
if (shapeIndex.equals(String.valueOf(shapeIndexFoFile))) {
|
||||
// 目标对象
|
||||
ShapePage shapeFunction = new ShapePage();
|
||||
// 获取参数中类型的定义
|
||||
Class<?>[] paramTypes = {Shape.class, CTSlideTiming.class};
|
||||
// 带参数的方法调用示例
|
||||
Method methodWithArgs = shapeFunction.getClass().getMethod(function, paramTypes);
|
||||
// 实际参数值
|
||||
Object[] arguments = {shape, timing};
|
||||
String value = (String) methodWithArgs.invoke(shapeFunction, arguments);
|
||||
if (!value.isEmpty()) {
|
||||
JudgementSlidesVO judgementSlidesVO = new JudgementSlidesVO();
|
||||
judgementSlidesVO.setContent(content + "@" + value);
|
||||
judgementSlidesVO.setContentIn(firstName + examName + value);
|
||||
judgementSlidesVO.setScoreRate(1);
|
||||
judgementSlidesVOS.add(judgementSlidesVO);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (shapeObj instanceof Pic pic) {
|
||||
if (shapeIndex.equals(String.valueOf(shapeIndexFoFile))) {
|
||||
// 目标对象
|
||||
ShapePic shapePicFunction = new ShapePic();
|
||||
// 获取参数中类型的定义
|
||||
Class<?>[] paramTypes = {Pic.class, CTSlideTiming.class};
|
||||
// 带参数的方法调用示例
|
||||
Method methodWithArgs = shapePicFunction.getClass().getMethod(function, paramTypes);
|
||||
// 实际参数值
|
||||
Object[] arguments = {pic, timing};
|
||||
String value = (String) methodWithArgs.invoke(shapePicFunction, arguments);
|
||||
if (!value.isEmpty()) {
|
||||
JudgementSlidesVO judgementSlidesVO = new JudgementSlidesVO();
|
||||
judgementSlidesVO.setContent(content + "@" + value);
|
||||
judgementSlidesVO.setContentIn(firstName + examName + value);
|
||||
judgementSlidesVO.setScoreRate(1);
|
||||
judgementSlidesVOS.add(judgementSlidesVO);
|
||||
} else if (shapeObj instanceof Pic pic) {
|
||||
if (shapeIndex.equals(String.valueOf(shapeIndexFoFile))) {
|
||||
// 目标对象
|
||||
ShapePic shapePicFunction = new ShapePic();
|
||||
// 获取参数中类型的定义
|
||||
Class<?>[] paramTypes = {Pic.class, CTSlideTiming.class};
|
||||
// 带参数的方法调用示例
|
||||
Method methodWithArgs = shapePicFunction.getClass().getMethod(function, paramTypes);
|
||||
// 实际参数值
|
||||
Object[] arguments = {pic, timing};
|
||||
String value = (String) methodWithArgs.invoke(shapePicFunction, arguments);
|
||||
if (!value.isEmpty()) {
|
||||
JudgementSlidesVO judgementSlidesVO = new JudgementSlidesVO();
|
||||
judgementSlidesVO.setContent(content + "@" + value);
|
||||
judgementSlidesVO.setContentIn(firstName + examName + value);
|
||||
judgementSlidesVO.setScoreRate(1);
|
||||
judgementSlidesVOS.add(judgementSlidesVO);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (method.equals("slideSetting")) {
|
||||
if (slideIndex.equals(String.valueOf(slideIndexFoFile))) {
|
||||
SlideSetting slideSettingFunction = new SlideSetting();
|
||||
Class<?>[] paramTypes = {SlidePart.class, PresentationMLPackage.class};
|
||||
Method methodWithArgs = slideSettingFunction.getClass().getMethod(function, paramTypes);
|
||||
Object[] arguments = {slidePart, ppt};
|
||||
String value = (String) methodWithArgs.invoke(slideSettingFunction, arguments);
|
||||
if (!value.isEmpty()) {
|
||||
JudgementSlidesVO judgementSlidesVO = new JudgementSlidesVO();
|
||||
judgementSlidesVO.setContent(content + "@" + value);
|
||||
judgementSlidesVO.setContentIn(firstName + examName + value);
|
||||
judgementSlidesVO.setScoreRate(1);
|
||||
judgementSlidesVOS.add(judgementSlidesVO);
|
||||
if (method.equals("slideSetting")) {
|
||||
if (slideIndex.equals(String.valueOf(slideIndexFoFile))) {
|
||||
SlideSetting slideSettingFunction = new SlideSetting();
|
||||
Class<?>[] paramTypes = {SlidePart.class, PresentationMLPackage.class, SlideMasterPart.class};
|
||||
Method methodWithArgs = slideSettingFunction.getClass().getMethod(function, paramTypes);
|
||||
Object[] arguments = {slidePart, ppt, slideMasterPart};
|
||||
String value = (String) methodWithArgs.invoke(slideSettingFunction, arguments);
|
||||
if (!value.isEmpty()) {
|
||||
JudgementSlidesVO judgementSlidesVO = new JudgementSlidesVO();
|
||||
judgementSlidesVO.setContent(content + "@" + value);
|
||||
judgementSlidesVO.setContentIn(firstName + examName + value);
|
||||
judgementSlidesVO.setScoreRate(1);
|
||||
judgementSlidesVOS.add(judgementSlidesVO);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,158 @@
|
||||
package com.example.exam.exam.service.wpspptx.pptx4j;
|
||||
|
||||
import org.docx4j.XmlUtils;
|
||||
import org.docx4j.openpackaging.packages.PresentationMLPackage;
|
||||
import org.docx4j.openpackaging.parts.JaxbXmlPart;
|
||||
import org.docx4j.openpackaging.parts.Part;
|
||||
import org.docx4j.openpackaging.parts.PresentationML.MainPresentationPart;
|
||||
import org.docx4j.openpackaging.parts.PresentationML.NotesMasterPart;
|
||||
import org.docx4j.openpackaging.parts.PresentationML.SlideMasterPart;
|
||||
import org.docx4j.openpackaging.parts.relationships.RelationshipsPart;
|
||||
import org.docx4j.relationships.Relationship;
|
||||
import org.pptx4j.jaxb.Context;
|
||||
import org.pptx4j.pml.CTNotesMasterIdList;
|
||||
import org.pptx4j.pml.CTNotesMasterIdListEntry;
|
||||
import org.pptx4j.pml.Presentation;
|
||||
import org.pptx4j.pml.PresentationPr;
|
||||
|
||||
|
||||
public class SlideMasterUtils {
|
||||
|
||||
public static SlideMasterPart getSlideMaster(PresentationMLPackage ppt) {
|
||||
// 2. 获取 Presentation 对象
|
||||
MainPresentationPart mpp = ppt.getMainPresentationPart();
|
||||
Presentation pres = (Presentation) mpp.getJaxbElement();
|
||||
RelationshipsPart rels = ppt.getMainPresentationPart().getRelationshipsPart();
|
||||
// 获取母版ID
|
||||
Presentation.SldMasterIdLst idList = pres.getSldMasterIdLst();
|
||||
for (Presentation.SldMasterIdLst.SldMasterId smId : idList.getSldMasterId()) {
|
||||
// 不同生成类版本,取 r:id 的方法名可能不同:getRid() 或 getId2()
|
||||
String rId = null;
|
||||
try {
|
||||
rId = smId.getRid(); // 新一点的模型常见
|
||||
} catch (Throwable ignore) {
|
||||
}
|
||||
if (rId == null) {
|
||||
try {
|
||||
// 某些版本字段名为 id2(即 r:id)
|
||||
rId = (String) Presentation.SldMasterIdLst.SldMasterId.class.getMethod("getId2").invoke(smId);
|
||||
} catch (Throwable ignore) {
|
||||
}
|
||||
}
|
||||
if (rId == null) {
|
||||
System.out.println("找不到该 sldMasterId 对应的 r:id。");
|
||||
continue;
|
||||
}
|
||||
Relationship rel = rels.getRelationshipByID(rId);
|
||||
if (rel == null) {
|
||||
System.out.println("关系未找到: " + rId);
|
||||
continue;
|
||||
}
|
||||
// 再通过关系拿到具体的 Part
|
||||
Part part = rels.getPart(rel);
|
||||
if (part instanceof SlideMasterPart) {
|
||||
SlideMasterPart master = (SlideMasterPart) part;
|
||||
return master;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获取备注母版 NotesMasterPart(若文件未显式定义备注母版则返回 null)
|
||||
*/
|
||||
public static NotesMasterPart getNotesMaster(PresentationMLPackage ppt) {
|
||||
// 2. 获取 Presentation 对象
|
||||
MainPresentationPart mpp = ppt.getMainPresentationPart();
|
||||
Presentation pres = (Presentation) mpp.getJaxbElement();
|
||||
RelationshipsPart rels = ppt.getMainPresentationPart().getRelationshipsPart();
|
||||
// 获取母版ID
|
||||
CTNotesMasterIdList idList = pres.getNotesMasterIdLst();
|
||||
CTNotesMasterIdListEntry smId = idList.getNotesMasterId();
|
||||
String rId = null;
|
||||
try {
|
||||
rId = smId.getId(); // 新一点的模型常见
|
||||
} catch (Throwable ignore) {
|
||||
}
|
||||
if (rId == null) {
|
||||
try {
|
||||
// 某些版本字段名为 id2(即 r:id)
|
||||
rId = (String) CTNotesMasterIdList.class.getMethod("getId2").invoke(smId);
|
||||
} catch (Throwable ignore) {
|
||||
}
|
||||
}
|
||||
Relationship rel = rels.getRelationshipByID(rId);
|
||||
// 再通过关系拿到具体的 Part
|
||||
Part part = rels.getPart(rel);
|
||||
if (part instanceof NotesMasterPart) {
|
||||
NotesMasterPart notes = (NotesMasterPart) part;
|
||||
return notes;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// /ppt/presProps.xml 的关系类型
|
||||
private static final String REL_TYPE_PRES_PROPS =
|
||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/presProps";
|
||||
|
||||
// (可选兜底)/ppt/presProps.xml 的 Content-Type
|
||||
private static final String PRES_PROPS_CT =
|
||||
"application/vnd.openxmlformats-officedocument.presentationml.presentationProperties+xml";
|
||||
|
||||
/**
|
||||
* 仿照你给的 getSlideMaster 写法:
|
||||
* 从 MainPresentationPart 的关系里定位 /ppt/presProps.xml,返回 PresentationPr。
|
||||
* 若不存在或无法解析,则返回 null。
|
||||
*/
|
||||
public static PresentationPr getPresentationPr(PresentationMLPackage ppt) {
|
||||
try {
|
||||
MainPresentationPart mpp = ppt.getMainPresentationPart();
|
||||
RelationshipsPart rels = mpp.getRelationshipsPart();
|
||||
|
||||
// 1) 先按关系类型精确查找
|
||||
for (Relationship rel : rels.getRelationships().getRelationship()) {
|
||||
if (REL_TYPE_PRES_PROPS.equals(rel.getType())) {
|
||||
Part part = rels.getPart(rel);
|
||||
PresentationPr pr = toPresentationPr(part);
|
||||
if (pr != null) return pr;
|
||||
}
|
||||
}
|
||||
|
||||
// 2) 兜底:在整包里按 Content-Type 扫描(有的文件没建关系时可用)
|
||||
for (Part p : ppt.getParts().getParts().values()) {
|
||||
if (PRES_PROPS_CT.equals(p.getContentType())) {
|
||||
PresentationPr pr = toPresentationPr(p);
|
||||
if (pr != null) return pr;
|
||||
}
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 Part 转为 PresentationPr:
|
||||
* - 若 JAXB 根对象已是 PresentationPr,直接返回;
|
||||
* - 否则把 JAXB 对象序列化为 XML,再用 Context.jcPML 反序列化成 PresentationPr(兼容老版本根类型 CTPresentationProperties)。
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static PresentationPr toPresentationPr(Part part) {
|
||||
try {
|
||||
if (part instanceof JaxbXmlPart) {
|
||||
Object jaxb = ((JaxbXmlPart<?>) part).getJaxbElement();
|
||||
if (jaxb instanceof PresentationPr) {
|
||||
return (PresentationPr) jaxb;
|
||||
}
|
||||
// 兼容老版本类型:用 XML 重新反解为 PresentationPr
|
||||
String xml = XmlUtils.marshaltoString(jaxb, true);
|
||||
Object obj = XmlUtils.unmarshalString(xml, Context.jcPML, PresentationPr.class);
|
||||
return (PresentationPr) obj;
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -3,15 +3,17 @@ package com.example.exam.exam.service.wpspptx.pptx4j;
|
||||
import org.docx4j.openpackaging.exceptions.Docx4JException;
|
||||
import org.docx4j.openpackaging.packages.PresentationMLPackage;
|
||||
import org.docx4j.openpackaging.parts.PresentationML.SlideLayoutPart;
|
||||
import org.docx4j.openpackaging.parts.PresentationML.SlideMasterPart;
|
||||
import org.docx4j.openpackaging.parts.PresentationML.SlidePart;
|
||||
import org.pptx4j.pml.*;
|
||||
import com.example.exam.exam.service.wpspptx.pptx4j.utils.Transition;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
// 单个幻灯片设置
|
||||
public class SlideSetting {
|
||||
// 幻灯片 版式
|
||||
public static String getSlideLayout(SlidePart slidePart, PresentationMLPackage presentation) throws Docx4JException {
|
||||
public static String getSlideLayout(SlidePart slidePart, PresentationMLPackage presentation, SlideMasterPart slideMasterPart) throws Docx4JException {
|
||||
SlideLayoutPart layoutPart = slidePart.getSlideLayoutPart();
|
||||
if (layoutPart.getContents().getCSld() != null) {
|
||||
return layoutPart.getContents().getCSld().getName();
|
||||
@@ -19,19 +21,23 @@ public class SlideSetting {
|
||||
return "";
|
||||
}
|
||||
// 设计 主题模板
|
||||
public static String getSlideTheme(SlidePart slidePart, PresentationMLPackage presentation) throws Docx4JException {
|
||||
public static String getSlideTheme(SlidePart slidePart, PresentationMLPackage presentation, SlideMasterPart slideMasterPart) throws Docx4JException {
|
||||
// 获取第一个幻灯片母版(通常主主题在这里)
|
||||
return "WPS";
|
||||
}
|
||||
|
||||
// 背景填充 填充方式
|
||||
public static String getSlideBackground(SlidePart slidePart, PresentationMLPackage presentation) throws Docx4JException {
|
||||
public static String getSlideBackground(SlidePart slidePart, PresentationMLPackage presentation, SlideMasterPart slideMasterPart) throws Docx4JException {
|
||||
Sld slide = slidePart.getContents();
|
||||
CTBackground ctBackground = slidePart.getContents().getCSld().getBg();
|
||||
if (ctBackground != null) {
|
||||
CTBackgroundProperties ctBackgroundProperties = ctBackground.getBgPr();
|
||||
return getBackgroundFillType(ctBackgroundProperties);
|
||||
} else {
|
||||
// 需要检查母版的设置
|
||||
CTBackgroundProperties ctBackgroundProperties = slideMasterPart.getJaxbElement().getCSld().getBg().getBgPr();
|
||||
return getBackgroundFillType(ctBackgroundProperties);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
private static String getBackgroundFillType(CTBackgroundProperties bgPr) {
|
||||
if (bgPr.getSolidFill() != null) return "纯色填充";
|
||||
@@ -43,7 +49,7 @@ public class SlideSetting {
|
||||
return "未知填充类型";
|
||||
}
|
||||
// 背景填充 纯色填充-颜色
|
||||
public static String getSlideBackgroundSolidColor(SlidePart slidePart, PresentationMLPackage presentation) throws Docx4JException {
|
||||
public static String getSlideBackgroundSolidColor(SlidePart slidePart, PresentationMLPackage presentation, SlideMasterPart slideMasterPart) throws Docx4JException {
|
||||
CTBackground ctBackground = slidePart.getContents().getCSld().getBg();
|
||||
if (ctBackground != null) {
|
||||
CTBackgroundProperties ctBackgroundProperties = ctBackground.getBgPr();
|
||||
@@ -67,41 +73,65 @@ public class SlideSetting {
|
||||
}
|
||||
|
||||
// 背景填充 隐藏背景图形
|
||||
public static String getSlideBackgroundHideShape(SlidePart slidePart, PresentationMLPackage presentation) throws Docx4JException {
|
||||
public static String getSlideBackgroundHideShape(SlidePart slidePart, PresentationMLPackage presentation, SlideMasterPart slideMasterPart) throws Docx4JException {
|
||||
return "待开发";
|
||||
}
|
||||
|
||||
// 幻灯片切换 切换效果
|
||||
public static String getSlideTransition(SlidePart slidePart, PresentationMLPackage presentation) throws Docx4JException {
|
||||
public static String getSlideTransition(SlidePart slidePart, PresentationMLPackage presentation, SlideMasterPart slideMasterPart) throws Docx4JException {
|
||||
Sld slides = (Sld) slidePart.getJaxbElement();
|
||||
Sld slide = (Sld) slidePart.getContents();
|
||||
CTSlideTransition ctSlideTransition = slide.getTransition();
|
||||
return "";
|
||||
}
|
||||
// 幻灯片切换 切换声音
|
||||
public static String getSlideTransitionSound(SlidePart slidePart, PresentationMLPackage presentation) throws Docx4JException {
|
||||
public static String getSlideTransitionSound(SlidePart slidePart, PresentationMLPackage presentation, SlideMasterPart slideMasterPart) throws Docx4JException {
|
||||
Sld slide = (Sld) slidePart.getContents();
|
||||
CTSlideTransition ctSlideTransition = slide.getTransition();
|
||||
CTTransitionSoundAction ctTransitionSoundAction = ctSlideTransition.getSndAc();
|
||||
if (ctTransitionSoundAction != null) {
|
||||
return ctTransitionSoundAction.getStSnd().getSnd().getName();
|
||||
// 将获取的声音文件,进行转换成中文
|
||||
return Transition.getCnName(ctTransitionSoundAction.getStSnd().getSnd().getName());
|
||||
}
|
||||
return "";
|
||||
}
|
||||
// 幻灯片切换 单机鼠标换片
|
||||
public static String getSlideTransitionMouse(SlidePart slidePart, PresentationMLPackage presentation, SlideMasterPart slideMasterPart) throws Docx4JException {
|
||||
Sld slide = (Sld) slidePart.getContents();
|
||||
CTSlideTransition ctSlideTransition = slide.getTransition();
|
||||
if (ctSlideTransition != null) {
|
||||
return ctSlideTransition.isAdvClick() ? "是" : "否";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
// 幻灯片切换 效果
|
||||
public static String getSlideTransitionEffect(SlidePart slidePart, PresentationMLPackage presentation, SlideMasterPart slideMasterPart) throws Docx4JException {
|
||||
Sld slide = (Sld) slidePart.getContents();
|
||||
CTSlideTransition ctSlideTransition = slide.getTransition();
|
||||
if (ctSlideTransition != null) {
|
||||
String value = ctSlideTransition.getBlinds().getDir().value();
|
||||
if (value.equals("vert")) {
|
||||
return "百叶窗->垂直";
|
||||
}
|
||||
if (value.equals("horz")) {
|
||||
return "百叶窗->水平";
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// 幻灯片切换 切换速度
|
||||
public static String getSlideTransitionSpeed(SlidePart slidePart, PresentationMLPackage presentation) throws Docx4JException {
|
||||
public static String getSlideTransitionSpeed(SlidePart slidePart, PresentationMLPackage presentation, SlideMasterPart slideMasterPart) throws Docx4JException {
|
||||
Sld slide = (Sld) slidePart.getContents();
|
||||
CTSlideTransition ctSlideTransition = slide.getTransition();
|
||||
Long speed = ctSlideTransition.getAdvTm();
|
||||
if (speed != null) {
|
||||
return String.valueOf(speed) + "毫秒";
|
||||
return speed / 1000 + "秒";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// 隐藏幻灯片
|
||||
public static String getSlideHide(SlidePart slidePart, PresentationMLPackage presentation) throws Docx4JException {
|
||||
public static String getSlideHide(SlidePart slidePart, PresentationMLPackage presentation, SlideMasterPart slideMasterPart) throws Docx4JException {
|
||||
Sld sld = slidePart.getJaxbElement();
|
||||
if (sld != null) {
|
||||
return sld.isShow() ? "显示幻灯片" : "隐藏幻灯片";
|
||||
@@ -110,7 +140,7 @@ public class SlideSetting {
|
||||
}
|
||||
|
||||
// 页眉页脚 包含→日期和时间
|
||||
public static String getSlideHeaderFooterDateTime(SlidePart slidePart, PresentationMLPackage presentation) throws Docx4JException {
|
||||
public static String getSlideHeaderFooterDateTime(SlidePart slidePart, PresentationMLPackage presentation, SlideMasterPart slideMasterPart) throws Docx4JException {
|
||||
GroupShape spTree = slidePart.getJaxbElement().getCSld().getSpTree();
|
||||
List<Object> shapes = spTree.getSpOrGrpSpOrGraphicFrame();
|
||||
for (Object shapeObj : shapes) {
|
||||
@@ -124,7 +154,7 @@ public class SlideSetting {
|
||||
return "";
|
||||
}
|
||||
// 页眉页脚 包含→幻灯片编号
|
||||
public static String getSlideHeaderFooterSlideNumber(SlidePart slidePart, PresentationMLPackage presentation) throws Docx4JException {
|
||||
public static String getSlideHeaderFooterSlideNumber(SlidePart slidePart, PresentationMLPackage presentation, SlideMasterPart slideMasterPart) throws Docx4JException {
|
||||
GroupShape spTree = slidePart.getJaxbElement().getCSld().getSpTree();
|
||||
List<Object> shapes = spTree.getSpOrGrpSpOrGraphicFrame();
|
||||
for (Object shapeObj : shapes) {
|
||||
@@ -138,7 +168,7 @@ public class SlideSetting {
|
||||
return "";
|
||||
}
|
||||
// 页眉页脚 包含→页脚
|
||||
public static String getSlideHeaderFooterFooter(SlidePart slidePart, PresentationMLPackage presentation) throws Docx4JException {
|
||||
public static String getSlideHeaderFooterFooter(SlidePart slidePart, PresentationMLPackage presentation, SlideMasterPart slideMasterPart) throws Docx4JException {
|
||||
GroupShape spTree = slidePart.getJaxbElement().getCSld().getSpTree();
|
||||
List<Object> shapes = spTree.getSpOrGrpSpOrGraphicFrame();
|
||||
for (Object shapeObj : shapes) {
|
||||
|
@@ -0,0 +1,116 @@
|
||||
package com.example.exam.exam.service.wpspptx.pptx4j.utils;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class HexColorUtils {
|
||||
|
||||
// 常见颜色映射表(可按需扩展)
|
||||
private static final Map<String, String> COLOR_NAME_MAP = new HashMap<>();
|
||||
|
||||
static {
|
||||
// -------------------- 基础色 --------------------
|
||||
COLOR_NAME_MAP.put("#000000", "黑色");
|
||||
COLOR_NAME_MAP.put("#FFFFFF", "白色");
|
||||
COLOR_NAME_MAP.put("#FF0000", "红色");
|
||||
COLOR_NAME_MAP.put("#00FF00", "亮绿色");
|
||||
COLOR_NAME_MAP.put("#0000FF", "蓝色");
|
||||
COLOR_NAME_MAP.put("#FFFF00", "黄色");
|
||||
COLOR_NAME_MAP.put("#00FFFF", "青色");
|
||||
COLOR_NAME_MAP.put("#FF00FF", "洋红色");
|
||||
|
||||
// -------------------- Office 常见标准色 --------------------
|
||||
COLOR_NAME_MAP.put("#0070C0", "蓝色");
|
||||
COLOR_NAME_MAP.put("#00B050", "绿色");
|
||||
COLOR_NAME_MAP.put("#7030A0", "紫罗兰色");
|
||||
COLOR_NAME_MAP.put("#C00000", "深红色");
|
||||
COLOR_NAME_MAP.put("#FFC000", "橙黄色");
|
||||
|
||||
// -------------------- 灰阶 --------------------
|
||||
COLOR_NAME_MAP.put("#808080", "灰色");
|
||||
COLOR_NAME_MAP.put("#C0C0C0", "银色");
|
||||
COLOR_NAME_MAP.put("#A9A9A9", "深灰色");
|
||||
COLOR_NAME_MAP.put("#D3D3D3", "浅灰色");
|
||||
COLOR_NAME_MAP.put("#F5F5F5", "白烟色");
|
||||
|
||||
// -------------------- 常见网页颜色 --------------------
|
||||
COLOR_NAME_MAP.put("#800000", "栗色");
|
||||
COLOR_NAME_MAP.put("#808000", "橄榄色");
|
||||
COLOR_NAME_MAP.put("#800080", "紫色");
|
||||
COLOR_NAME_MAP.put("#008080", "水鸭色");
|
||||
COLOR_NAME_MAP.put("#FFA500", "橙色");
|
||||
COLOR_NAME_MAP.put("#A52A2A", "棕色");
|
||||
COLOR_NAME_MAP.put("#F5F5DC", "米色");
|
||||
COLOR_NAME_MAP.put("#FFC0CB", "粉红色");
|
||||
COLOR_NAME_MAP.put("#ADD8E6", "浅蓝色");
|
||||
COLOR_NAME_MAP.put("#90EE90", "浅绿色");
|
||||
COLOR_NAME_MAP.put("#FFD700", "金色");
|
||||
COLOR_NAME_MAP.put("#FA8072", "鲑鱼色");
|
||||
COLOR_NAME_MAP.put("#FF4500", "橙红色");
|
||||
COLOR_NAME_MAP.put("#4682B4", "钢蓝色");
|
||||
COLOR_NAME_MAP.put("#2E8B57", "海绿色");
|
||||
COLOR_NAME_MAP.put("#B22222", "耐火砖红");
|
||||
COLOR_NAME_MAP.put("#6B8E23", "橄榄褐色");
|
||||
COLOR_NAME_MAP.put("#DAA520", "秋麒麟色");
|
||||
COLOR_NAME_MAP.put("#5F9EA0", "军服蓝");
|
||||
COLOR_NAME_MAP.put("#D2691E", "巧克力色");
|
||||
|
||||
// -------------------- WPS/Excel 扩展色 --------------------
|
||||
COLOR_NAME_MAP.put("#1F497D", "深蓝色");
|
||||
COLOR_NAME_MAP.put("#4F81BD", "中蓝色");
|
||||
COLOR_NAME_MAP.put("#9BBB59", "草绿色");
|
||||
COLOR_NAME_MAP.put("#8064A2", "紫罗兰色");
|
||||
COLOR_NAME_MAP.put("#F79646", "杏橙色");
|
||||
COLOR_NAME_MAP.put("#C0504D", "砖红色");
|
||||
|
||||
COLOR_NAME_MAP.put("#31869B", "蓝绿色");
|
||||
COLOR_NAME_MAP.put("#E46C0A", "深橙色");
|
||||
COLOR_NAME_MAP.put("#77933C", "苔藓绿");
|
||||
COLOR_NAME_MAP.put("#963634", "褐红色");
|
||||
COLOR_NAME_MAP.put("#4BACC6", "湖蓝色");
|
||||
COLOR_NAME_MAP.put("#604A7B", "深紫色");
|
||||
|
||||
// -------------------- 柔和色调 --------------------
|
||||
COLOR_NAME_MAP.put("#B6DDE8", "浅湖蓝色");
|
||||
COLOR_NAME_MAP.put("#E6B8B7", "浅褐红色");
|
||||
COLOR_NAME_MAP.put("#D8E4BC", "浅草绿色");
|
||||
COLOR_NAME_MAP.put("#CCC0DA", "浅紫色");
|
||||
COLOR_NAME_MAP.put("#F2DCDB", "浅玫瑰色");
|
||||
COLOR_NAME_MAP.put("#B8CCE4", "浅蓝灰色");
|
||||
}
|
||||
|
||||
/**
|
||||
* 把十六进制颜色转成 "颜色名 RGB(r,g,b)" 格式的字符串
|
||||
* @param hex 十六进制颜色,例如 "00B050" 或 "#00B050"
|
||||
* @return 格式化后的字符串
|
||||
*/
|
||||
public static String hexToColorString(String hex) {
|
||||
if (hex == null || hex.isEmpty()) {
|
||||
return "无效颜色";
|
||||
}
|
||||
|
||||
// 去掉 # 前缀
|
||||
if (hex.startsWith("#")) {
|
||||
hex = hex.substring(1);
|
||||
}
|
||||
|
||||
// 转换为 Color
|
||||
Color color = new Color(Integer.parseInt(hex, 16));
|
||||
int r = color.getRed();
|
||||
int g = color.getGreen();
|
||||
int b = color.getBlue();
|
||||
|
||||
// 转回统一的十六进制形式(大写,带 #)
|
||||
String hexKey = String.format("#%02X%02X%02X", r, g, b);
|
||||
|
||||
// 查找颜色名
|
||||
String name = COLOR_NAME_MAP.getOrDefault(hexKey, "未知颜色");
|
||||
|
||||
return String.format("%s RGB(%d,%d,%d)", name, r, g, b);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,20 @@
|
||||
package com.example.exam.exam.service.wpspptx.pptx4j.utils;
|
||||
|
||||
public class PptxUtils {
|
||||
public static String detectAspectName(long width, long height) {
|
||||
if (width <= 0 || height <= 0) return "自定";
|
||||
// 不区分横竖:3:4 也当 4:3
|
||||
long w = Math.max(width, height), h = Math.min(width, height);
|
||||
double tol = 0.01; // 允许1%误差
|
||||
|
||||
// 判断 4:3 -> w/h ≈ 4/3 <=> |w*3 - h*4| / max(w*3, h*4) <= tol
|
||||
long l43 = w * 3, r43 = h * 4;
|
||||
if (Math.abs(l43 - r43) <= Math.max(l43, r43) * tol) return "4:3";
|
||||
|
||||
// 判断 16:9 -> w/h ≈ 16/9 <=> |w*9 - h*16| / max(w*9, h*16) <= tol
|
||||
long l169 = w * 9, r169 = h * 16;
|
||||
if (Math.abs(l169 - r169) <= Math.max(l169, r169) * tol) return "16:9";
|
||||
|
||||
return "自定义";
|
||||
}
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
package com.example.exam.exam.service.wpspptx.pptx4j.utils;
|
||||
|
||||
public class PtToCmConverter {
|
||||
|
||||
// 基础转换常数
|
||||
public static final double POINTS_PER_INCH = 72.0;
|
||||
public static final double CM_PER_INCH = 2.54;
|
||||
public static final double PT_TO_CM = CM_PER_INCH / POINTS_PER_INCH;
|
||||
|
||||
/**
|
||||
* 将点(pt)转换为厘米(cm)
|
||||
* @param points 点数
|
||||
* @return 厘米数
|
||||
*/
|
||||
public static int pointsToCm(double points) {
|
||||
return (int) Math.round(points * PT_TO_CM);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将厘米(cm)转换为点(pt)
|
||||
* @param cm 厘米数
|
||||
* @return 点数
|
||||
*/
|
||||
public static double cmToPoints(double cm) {
|
||||
return cm / PT_TO_CM;
|
||||
}
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
package com.example.exam.exam.service.wpspptx.pptx4j.utils;
|
||||
|
||||
public class PtToEmuConverter {
|
||||
// 基础转换常数
|
||||
public static final double EMU = 12700;
|
||||
|
||||
public static double ptToEmu(double pt) {
|
||||
return pt * EMU;
|
||||
}
|
||||
|
||||
public static double emuToPt(double emu) {
|
||||
return emu / EMU;
|
||||
}
|
||||
}
|
@@ -0,0 +1,205 @@
|
||||
package com.example.exam.exam.service.wpspptx.pptx4j.utils;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class Transition {
|
||||
|
||||
private static final Pattern P = Pattern.compile("\\(([^)]+)\\)");
|
||||
public static String getCnName(String fileName) {
|
||||
if (fileName == null) return "未知";
|
||||
|
||||
switch (fileName.toLowerCase()) {
|
||||
case "wind.wav":
|
||||
return "风声 / 微风";
|
||||
case "applause.wav":
|
||||
return "掌声";
|
||||
case "breeze.wav":
|
||||
return "清风 / 微风拂过";
|
||||
case "whoosh.wav":
|
||||
case "swoosh.wav":
|
||||
return "呼啸 / 划过";
|
||||
case "chime.wav":
|
||||
return "叮当 / 玲声";
|
||||
case "camera.wav":
|
||||
return "相机快门";
|
||||
case "cashregister.wav":
|
||||
return "收银机";
|
||||
case "typewriter.wav":
|
||||
return "打字机";
|
||||
case "laser.wav":
|
||||
return "激光";
|
||||
case "explosion.wav":
|
||||
case "explode.wav":
|
||||
return "爆炸";
|
||||
case "drumroll.wav":
|
||||
return "擂鼓 / 滚奏";
|
||||
case "click.wav":
|
||||
return "单机";
|
||||
case "coin.wav":
|
||||
return "硬币";
|
||||
case "bomb.wav":
|
||||
return "炸弹";
|
||||
case "scream.wav":
|
||||
return "尖叫";
|
||||
case "arrow.wav":
|
||||
return "箭矢";
|
||||
case "push.wav":
|
||||
return "推入声";
|
||||
case "hammer.wav":
|
||||
return "锤击";
|
||||
case "tada.wav":
|
||||
return "哒哒 / 庆祝";
|
||||
case "horn.wav":
|
||||
case "carhorn.wav":
|
||||
return "喇叭 / 汽车喇叭";
|
||||
case "doorbell.wav":
|
||||
return "门铃";
|
||||
case "ding.wav":
|
||||
return "叮";
|
||||
case "gong.wav":
|
||||
return "锣";
|
||||
case "beep.wav":
|
||||
return "嘟声";
|
||||
case "notify.wav":
|
||||
return "提示音";
|
||||
case "pop.wav":
|
||||
return "啪嗒 / 弹出";
|
||||
case "zip.wav":
|
||||
case "zipper.wav":
|
||||
return "拉链 / 嗖";
|
||||
case "sparkle.wav":
|
||||
return "闪光";
|
||||
case "rattle.wav":
|
||||
return "哗啦";
|
||||
case "thunder.wav":
|
||||
return "雷鸣";
|
||||
case "bell.wav":
|
||||
return "铃声";
|
||||
case "ring.wav":
|
||||
return "电话铃";
|
||||
case "whistle.wav":
|
||||
return "口哨";
|
||||
default:
|
||||
return "未知";
|
||||
}
|
||||
}
|
||||
|
||||
public static String toCn(String trigger) {
|
||||
if (trigger == null) return "";
|
||||
switch (trigger == null ? "" : trigger.trim().toLowerCase()) {
|
||||
case "onclick":
|
||||
case "clickeffect": return "单击时";
|
||||
|
||||
case "witheffect": return "之前";
|
||||
case "onbegin": return "与上一动画同时";
|
||||
|
||||
case "aftereffect":
|
||||
case "onend": return "上一动画之后";
|
||||
|
||||
case "onnext": return "下一次单击";
|
||||
case "onprev": return "上一次单击";
|
||||
case "onload": return "幻灯片载入时";
|
||||
case "onmouseover": return "鼠标移入时";
|
||||
case "onmouseout": return "鼠标移出时";
|
||||
case "ondblclick": return "双击时";
|
||||
case "onstopaudio": return "音频停止时";
|
||||
case "onbeginaudio":
|
||||
case "onplay": return "音频开始时";
|
||||
case "onendaudio": return "音频结束时";
|
||||
case "onbookmark": return "书签到达时";
|
||||
case "onresume": return "恢复播放时";
|
||||
case "onpause": return "暂停时";
|
||||
case "onstop": return "停止时";
|
||||
default: return trigger; // 或者返回 "(未知触发)"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static String presetClass(String trigger) {
|
||||
if (trigger == null) return "";
|
||||
switch (trigger.trim().toLowerCase()) {
|
||||
case "entr": return "进入";
|
||||
case "exit": return "退出";
|
||||
case "emph": return "强调";
|
||||
case "path": return "动作路径";
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static String getDirection(String spec) {
|
||||
if (spec == null) return null;
|
||||
Matcher m = P.matcher(spec);
|
||||
return m.find() ? m.group(1).trim() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将方向英文/短码汉化;可直接传入诸如 "downRight"、"rd"、"rightDown"、"vert"、"in" 等。
|
||||
* @param raw 方向原始字符串(不区分大小写,允许下划线/中横线/驼峰)
|
||||
* @return 对应的中文(若无法识别,原样返回)
|
||||
*/
|
||||
public static String toChinese(String raw) {
|
||||
if (raw == null || raw.isEmpty()) return raw;
|
||||
String s = normalize(raw);
|
||||
|
||||
switch (s) {
|
||||
// 单向
|
||||
case "l": case "left": return "向左";
|
||||
case "r": case "right": return "向右";
|
||||
case "u": case "up": return "向上";
|
||||
case "d": case "down": return "向下";
|
||||
|
||||
// 斜向
|
||||
case "lu": case "upleft": case "leftup": return "左上";
|
||||
case "ru": case "upright": case "rightup": return "右上";
|
||||
case "ld": case "downleft": case "leftdown": return "左下";
|
||||
case "rd": case "downright": case "rightdown": return "右下";
|
||||
|
||||
// 其他常见关键字
|
||||
case "vert": case "vertical": return "垂直";
|
||||
case "horz": case "horizontal": return "水平";
|
||||
case "in": return "向内";
|
||||
case "out": return "向外";
|
||||
|
||||
default:
|
||||
return raw; // 不识别则原样返回,避免误判
|
||||
}
|
||||
}
|
||||
|
||||
/** 归一化:去空格/分隔符、转小写、转驼峰组合为连续词 */
|
||||
private static String normalize(String s) {
|
||||
s = s.trim().toLowerCase(Locale.ROOT);
|
||||
s = s.replaceAll("[_\\-\\s]", ""); // 去掉下划线/中横线/空格
|
||||
return s;
|
||||
}
|
||||
|
||||
/** 示例:把效果+方向组合成人类可读中文,比如 "strips(downRight)" → "条纹(右下)" */
|
||||
public static String effectWithDirToChinese(String dir) {
|
||||
return toChinese(getDirection(dir));
|
||||
}
|
||||
|
||||
/** 常见效果英文→中文(可按需扩展) */
|
||||
public static String effectToChinese(String effect) {
|
||||
if (effect == null) return "效果";
|
||||
String e = effect.trim().toLowerCase(Locale.ROOT);
|
||||
switch (e) {
|
||||
case "strips": return "条纹";
|
||||
case "blinds": return "百叶窗";
|
||||
case "wipe": return "擦除";
|
||||
case "push": return "推出";
|
||||
case "split": return "分割";
|
||||
case "checkerboard":return "棋盘格";
|
||||
case "cover": return "覆盖";
|
||||
case "uncover": return "揭开";
|
||||
case "randombars": return "随机条";
|
||||
case "shape": return "形状";
|
||||
case "circle": return "圆形";
|
||||
case "diamond": return "菱形";
|
||||
case "plus": return "十字形";
|
||||
case "fade": return "淡入";
|
||||
case "appear": return "出现";
|
||||
default: return effect; // 未收录则原样
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user