Merge pull request '【修改】文字考点段落,线性汉化' (#2) from hyc into master
Reviewed-on: #2
This commit is contained in:
@@ -2,6 +2,7 @@ package pc.exam.pp.module.judgement.utils.wps_word.docx4j.drawing;
|
|||||||
|
|
||||||
import jakarta.xml.bind.*;
|
import jakarta.xml.bind.*;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
|
import org.apache.xmlbeans.XmlCursor;
|
||||||
import org.docx4j.XmlUtils;
|
import org.docx4j.XmlUtils;
|
||||||
import org.docx4j.dml.*;
|
import org.docx4j.dml.*;
|
||||||
import org.docx4j.dml.chartDrawing.CTPicture;
|
import org.docx4j.dml.chartDrawing.CTPicture;
|
||||||
@@ -24,6 +25,7 @@ import javax.xml.parsers.DocumentBuilder;
|
|||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import javax.xml.xpath.XPath;
|
import javax.xml.xpath.XPath;
|
||||||
import javax.xml.xpath.XPathConstants;
|
import javax.xml.xpath.XPathConstants;
|
||||||
|
import javax.xml.xpath.XPathExpression;
|
||||||
import javax.xml.xpath.XPathFactory;
|
import javax.xml.xpath.XPathFactory;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
@@ -1328,10 +1330,10 @@ public static String getSolidFillColor(List<JudgementWordsVO> judgementWordsVOS,
|
|||||||
return "是";
|
return "是";
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 预设类型(shadow preset)
|
// 2. 预设类型
|
||||||
public static String getShadowPreset(List<JudgementWordsVO> judgementWordsVOS, Anchor anchor, int betoLong, WordprocessingMLPackage wordMLPackage) {
|
public static String getShadowPreset(List<JudgementWordsVO> judgementWordsVOS, Anchor anchor, int betoLong, WordprocessingMLPackage wordMLPackage) {
|
||||||
CTReflectionEffect shadow = getReflectionEffect(anchor);
|
CTReflectionEffect shadow = getReflectionEffect(anchor);
|
||||||
if (shadow == null) return "无";
|
if (shadow == null) return "无预设";
|
||||||
|
|
||||||
// 例如根据blurRad、dist、dir组合判断
|
// 例如根据blurRad、dist、dir组合判断
|
||||||
BigInteger blurRad = BigInteger.valueOf(shadow.getBlurRad());
|
BigInteger blurRad = BigInteger.valueOf(shadow.getBlurRad());
|
||||||
|
@@ -8,6 +8,7 @@ import org.docx4j.XmlUtils;
|
|||||||
import org.docx4j.dml.*;
|
import org.docx4j.dml.*;
|
||||||
import org.docx4j.dml.chartDrawing.CTPicture;
|
import org.docx4j.dml.chartDrawing.CTPicture;
|
||||||
import org.docx4j.dml.picture.Pic;
|
import org.docx4j.dml.picture.Pic;
|
||||||
|
import org.docx4j.dml.wordprocessingDrawing.Anchor;
|
||||||
import org.docx4j.dml.wordprocessingDrawing.CTWrapSquare;
|
import org.docx4j.dml.wordprocessingDrawing.CTWrapSquare;
|
||||||
import org.docx4j.dml.wordprocessingDrawing.Inline;
|
import org.docx4j.dml.wordprocessingDrawing.Inline;
|
||||||
import org.docx4j.dml.wordprocessingDrawing.Inline;
|
import org.docx4j.dml.wordprocessingDrawing.Inline;
|
||||||
@@ -753,8 +754,80 @@ public class DrawingInline {
|
|||||||
|
|
||||||
// 获取“预设”
|
// 获取“预设”
|
||||||
public static String getShadowPresetType(List<JudgementWordsVO> judgementWordsVOS, Inline anchor, int betoLong, WordprocessingMLPackage wordMLPackage) {
|
public static String getShadowPresetType(List<JudgementWordsVO> judgementWordsVOS, Inline anchor, int betoLong, WordprocessingMLPackage wordMLPackage) {
|
||||||
|
CTOuterShadowEffect shadow = getOuterShadow(anchor);
|
||||||
|
CTInnerShadowEffect innerShadow= getInnerShadow(anchor);
|
||||||
|
CTPresetShadowEffect presetShadow = getPresetShadow(anchor);
|
||||||
|
if (shadow != null ) {
|
||||||
|
|
||||||
return "无预设";
|
Long blurRadObj = shadow.getBlurRad();
|
||||||
|
Long distObj = shadow.getDist();
|
||||||
|
Long dirObj = (long) shadow.getDir();
|
||||||
|
|
||||||
|
long blurRad = blurRadObj != null ? blurRadObj : 0L;
|
||||||
|
long dist = distObj != null ? distObj : 0L;
|
||||||
|
long dir = dirObj != null ? dirObj : 0L;
|
||||||
|
// 转换为角度
|
||||||
|
double angle = dir / 60000.0;
|
||||||
|
|
||||||
|
// 1️⃣ 偏移阴影(外部)
|
||||||
|
if (angle == 45 ) return "偏移右下";
|
||||||
|
if (angle == 90 ) return "偏移下";
|
||||||
|
if (angle == 135) return "偏移左下";
|
||||||
|
if (angle == 0&&dist!=0 ) return "偏移右";
|
||||||
|
if (angle == 180 ) return "偏移左";
|
||||||
|
if (angle ==315 ) return "偏移右上";
|
||||||
|
if (angle == 270 ) return "偏移上";
|
||||||
|
if (angle == 225) return "偏移左上";
|
||||||
|
if (dist==0) return "中";
|
||||||
|
|
||||||
|
}
|
||||||
|
if (innerShadow!=null){
|
||||||
|
|
||||||
|
Long blurRadObj = innerShadow.getBlurRad();
|
||||||
|
Long distObj = innerShadow.getDist();
|
||||||
|
Long dirObj = (long) innerShadow.getDir();
|
||||||
|
|
||||||
|
long blurRad = blurRadObj != null ? blurRadObj : 0L;
|
||||||
|
long dist = distObj != null ? distObj : 0L;
|
||||||
|
long dir = dirObj != null ? dirObj : 0L;
|
||||||
|
// 转换为角度
|
||||||
|
double angle = dir / 60000.0;
|
||||||
|
// 2️⃣ 内部阴影(dist 较小,blurRad 中等)
|
||||||
|
if (angle == 45 ) return "内部右下";
|
||||||
|
if (angle == 90 ) return "内部下";
|
||||||
|
if (angle == 135) return "内部左下";
|
||||||
|
if (angle == 00&&dist!=0 ) return "内部右";
|
||||||
|
if (angle == 180 ) return "内部左";
|
||||||
|
if (angle ==315 ) return "内部右上";
|
||||||
|
if (angle == 270 ) return "内部上";
|
||||||
|
if (angle == 225) return "内部左上";
|
||||||
|
if (dist==0) return "中";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (presetShadow!=null){
|
||||||
|
Long blurRadObj = shadow.getBlurRad();
|
||||||
|
Long distObj = shadow.getDist();
|
||||||
|
Long dirObj = (long) shadow.getDir();
|
||||||
|
|
||||||
|
long blurRad = blurRadObj != null ? blurRadObj : 0L;
|
||||||
|
long dist = distObj != null ? distObj : 0L;
|
||||||
|
long dir = dirObj != null ? dirObj : 0L;
|
||||||
|
// 转换为角度
|
||||||
|
double angle = dir / 60000.0;
|
||||||
|
|
||||||
|
|
||||||
|
// 3️⃣ 透视阴影(dist 和 blurRad 都较大)
|
||||||
|
if (angle == 225) return "透视左上";
|
||||||
|
if (angle ==315 ) return "透视右上";
|
||||||
|
if (angle == 90 ) return "透视下";
|
||||||
|
if (angle == 135) return "透视左下";
|
||||||
|
if (angle == 45 ) return "透视右下";
|
||||||
|
if (dist==0) return "中";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return "无";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1324,7 +1397,34 @@ public static String getSolidFillColor(List<JudgementWordsVO> judgementWordsVOS,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static CTInnerShadowEffect getInnerShadow(Inline anchor) {
|
||||||
|
if (anchor == null || anchor.getDocPr() == null) return null;
|
||||||
|
|
||||||
|
if (anchor.getGraphic() != null &&
|
||||||
|
anchor.getGraphic().getGraphicData() != null &&
|
||||||
|
anchor.getGraphic().getGraphicData().getPic() != null) {
|
||||||
|
|
||||||
|
CTShapeProperties spPr = anchor.getGraphic().getGraphicData().getPic().getSpPr();
|
||||||
|
if (spPr != null && spPr.getEffectLst() != null && spPr.getEffectLst().getInnerShdw() != null) {
|
||||||
|
return spPr.getEffectLst().getInnerShdw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
private static CTPresetShadowEffect getPresetShadow(Inline anchor) {
|
||||||
|
if (anchor == null || anchor.getGraphic() == null) return null;
|
||||||
|
|
||||||
|
Object graphicData = anchor.getGraphic().getGraphicData().getAny().get(0);
|
||||||
|
if (graphicData instanceof JAXBElement) {
|
||||||
|
graphicData = ((JAXBElement<?>) graphicData).getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (graphicData instanceof CTPresetShadowEffect) {
|
||||||
|
return (CTPresetShadowEffect) graphicData;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private static String getShapeName(String shapeType) {
|
private static String getShapeName(String shapeType) {
|
||||||
|
@@ -2,6 +2,7 @@ package pc.exam.pp.module.judgement.utils.wps_word.docx4j.paragraph;
|
|||||||
|
|
||||||
import jakarta.xml.bind.JAXBElement;
|
import jakarta.xml.bind.JAXBElement;
|
||||||
import org.docx4j.XmlUtils;
|
import org.docx4j.XmlUtils;
|
||||||
|
import org.docx4j.model.structure.SectionWrapper;
|
||||||
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
|
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
|
||||||
import org.docx4j.openpackaging.parts.WordprocessingML.NumberingDefinitionsPart;
|
import org.docx4j.openpackaging.parts.WordprocessingML.NumberingDefinitionsPart;
|
||||||
import org.docx4j.openpackaging.parts.WordprocessingML.StyleDefinitionsPart;
|
import org.docx4j.openpackaging.parts.WordprocessingML.StyleDefinitionsPart;
|
||||||
@@ -10,6 +11,7 @@ import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTextAlignment;
|
|||||||
import pc.exam.pp.module.judgement.utils.wps_word.utils.ColorUtils;
|
import pc.exam.pp.module.judgement.utils.wps_word.utils.ColorUtils;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author REN
|
* @author REN
|
||||||
@@ -790,59 +792,90 @@ public class Paragraphs {
|
|||||||
|
|
||||||
// 分栏 - 分隔线
|
// 分栏 - 分隔线
|
||||||
public static String getParagraphColIsSep(P paragraph, StyleDefinitionsPart stylePart, WordprocessingMLPackage wordMLPackage, NumberingDefinitionsPart ndp) {
|
public static String getParagraphColIsSep(P paragraph, StyleDefinitionsPart stylePart, WordprocessingMLPackage wordMLPackage, NumberingDefinitionsPart ndp) {
|
||||||
PPr pPr = paragraph.getPPr();
|
if (paragraph == null) return "无";
|
||||||
SectPr sectPr = null;
|
|
||||||
sectPr = pPr.getSectPr();
|
|
||||||
// 优先取段落自身的节属性
|
|
||||||
if (pPr != null && pPr.getSectPr() != null) {
|
|
||||||
sectPr = pPr.getSectPr();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 或最后一个段落中会有一个节结束的SectPr
|
List<Object> allParagraphs = wordMLPackage.getMainDocumentPart().getContent();
|
||||||
if (sectPr == null && paragraph.getContent().size() > 0) {
|
if (allParagraphs == null || allParagraphs.isEmpty()) return "无";
|
||||||
Object lastObj = paragraph.getContent().get(paragraph.getContent().size() - 1);
|
|
||||||
if (lastObj instanceof JAXBElement && ((JAXBElement<?>) lastObj).getValue() instanceof SectPr) {
|
SectPr currentSectPr = null;
|
||||||
sectPr = (SectPr) ((JAXBElement<?>) lastObj).getValue();
|
|
||||||
|
for (Object obj : allParagraphs) {
|
||||||
|
P p = null;
|
||||||
|
if (obj instanceof P) {
|
||||||
|
p = (P) obj;
|
||||||
|
} else if (obj instanceof JAXBElement && ((JAXBElement<?>) obj).getValue() instanceof P) {
|
||||||
|
p = (P) ((JAXBElement<?>) obj).getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p == null) continue;
|
||||||
|
|
||||||
|
// 每遇到一个段落的 SectPr 就更新当前节
|
||||||
|
PPr pPr = p.getPPr();
|
||||||
|
if (pPr != null && pPr.getSectPr() != null) {
|
||||||
|
currentSectPr = pPr.getSectPr();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果当前段落就是目标段落,返回该节分栏信息
|
||||||
|
if (p == paragraph) {
|
||||||
|
if (currentSectPr != null && currentSectPr.getCols() != null) {
|
||||||
|
CTColumns cols = currentSectPr.getCols();
|
||||||
|
Boolean sep = cols.isSep();
|
||||||
|
return sep != null && sep ? "是" : "否";
|
||||||
|
} else {
|
||||||
|
return "无";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sectPr != null && sectPr.getCols() != null) {
|
|
||||||
CTColumns cols = sectPr.getCols();
|
|
||||||
return cols.isSep() ? "是" : "否";
|
|
||||||
}
|
|
||||||
return "无";
|
return "无";
|
||||||
}
|
}
|
||||||
|
|
||||||
// 分栏 - 各栏间距
|
// 分栏 - 各栏间距
|
||||||
public static String getParagraphColSpace(P paragraph, StyleDefinitionsPart stylePart, WordprocessingMLPackage wordMLPackage, NumberingDefinitionsPart ndp) {
|
public static String getParagraphColSpace(P paragraph, StyleDefinitionsPart stylePart, WordprocessingMLPackage wordMLPackage, NumberingDefinitionsPart ndp) {
|
||||||
PPr pPr = paragraph.getPPr();
|
if (paragraph == null) return "无";
|
||||||
SectPr sectPr = null;
|
|
||||||
sectPr = pPr.getSectPr();
|
|
||||||
// 优先取段落自身的节属性
|
|
||||||
if (pPr != null && pPr.getSectPr() != null) {
|
|
||||||
sectPr = pPr.getSectPr();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 或最后一个段落中会有一个节结束的SectPr
|
List<Object> allParagraphs = wordMLPackage.getMainDocumentPart().getContent();
|
||||||
if (sectPr == null && paragraph.getContent().size() > 0) {
|
if (allParagraphs == null || allParagraphs.isEmpty()) return "无";
|
||||||
Object lastObj = paragraph.getContent().get(paragraph.getContent().size() - 1);
|
|
||||||
if (lastObj instanceof JAXBElement && ((JAXBElement<?>) lastObj).getValue() instanceof SectPr) {
|
SectPr currentSectPr = null;
|
||||||
sectPr = (SectPr) ((JAXBElement<?>) lastObj).getValue();
|
|
||||||
|
for (Object obj : allParagraphs) {
|
||||||
|
P p = null;
|
||||||
|
if (obj instanceof P) {
|
||||||
|
p = (P) obj;
|
||||||
|
} else if (obj instanceof JAXBElement && ((JAXBElement<?>) obj).getValue() instanceof P) {
|
||||||
|
p = (P) ((JAXBElement<?>) obj).getValue();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (sectPr != null && sectPr.getCols() != null) {
|
if (p == null) continue;
|
||||||
CTColumns cols = sectPr.getCols();
|
|
||||||
if (cols.getCol() != null && !cols.getCol().isEmpty()) {
|
// 遇到段落中有SectPr则更新当前节
|
||||||
int index = 1;
|
PPr pPr = p.getPPr();
|
||||||
String value = "";
|
if (pPr != null && pPr.getSectPr() != null) {
|
||||||
for (CTColumn col : cols.getCol()) {
|
currentSectPr = pPr.getSectPr();
|
||||||
value += "第 " + index + " 栏间距 (twips): " + col.getSpace() + " ";
|
}
|
||||||
index++;
|
|
||||||
|
// 如果是目标段落,返回分栏间距
|
||||||
|
if (p == paragraph) {
|
||||||
|
if (currentSectPr != null && currentSectPr.getCols() != null) {
|
||||||
|
CTColumns cols = currentSectPr.getCols();
|
||||||
|
if (cols.getCol() != null && !cols.getCol().isEmpty()) {
|
||||||
|
StringBuilder value = new StringBuilder();
|
||||||
|
int index = 1;
|
||||||
|
for (CTColumn col : cols.getCol()) {
|
||||||
|
value.append("第 ").append(index).append(" 栏间距 (twips): ").append(col.getSpace()).append(" ");
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
return value.toString();
|
||||||
|
} else if (cols.getSpace() != null) {
|
||||||
|
// 如果没有单独列配置,使用总栏间距
|
||||||
|
return "栏间距 (twips): " + cols.getSpace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return value;
|
return "无";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "无";
|
return "无";
|
||||||
}
|
}
|
||||||
// 分栏 - 各栏宽度
|
// 分栏 - 各栏宽度
|
||||||
|
@@ -29,6 +29,7 @@ import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
|
|||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
|
import pc.exam.pp.module.judgement.utils.wps_word.utils.ColorUtils;
|
||||||
|
|
||||||
import javax.xml.namespace.QName;
|
import javax.xml.namespace.QName;
|
||||||
import javax.xml.xpath.XPath;
|
import javax.xml.xpath.XPath;
|
||||||
@@ -1729,7 +1730,7 @@ public class SectionPage {
|
|||||||
// 以 Top 为例获取颜色
|
// 以 Top 为例获取颜色
|
||||||
CTBorder top = borders.getTop();
|
CTBorder top = borders.getTop();
|
||||||
if (top != null && top.getColor() != null) {
|
if (top != null && top.getColor() != null) {
|
||||||
return top.getColor();
|
return ColorUtils.getChineseColorName(top.getColor());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "无";
|
return "无";
|
||||||
|
@@ -123,7 +123,28 @@ public class TableIng {
|
|||||||
tblCursor.selectPath(path);
|
tblCursor.selectPath(path);
|
||||||
if (tblCursor.toNextSelection()) {
|
if (tblCursor.toNextSelection()) {
|
||||||
String val = tblCursor.getAttributeText(new QName(W_NAMESPACE, "val"));
|
String val = tblCursor.getAttributeText(new QName(W_NAMESPACE, "val"));
|
||||||
return val != null ? val : null;
|
if (val == null) return null;
|
||||||
|
// 汉化
|
||||||
|
switch (val) {
|
||||||
|
case "single":
|
||||||
|
return "单实线";
|
||||||
|
case "dashed":
|
||||||
|
return "虚线";
|
||||||
|
case "dotted":
|
||||||
|
return "点线";
|
||||||
|
case "double":
|
||||||
|
return "双实线";
|
||||||
|
case "thick":
|
||||||
|
return "粗线";
|
||||||
|
case "thinThickSmallGap":
|
||||||
|
return "细粗小间隔线";
|
||||||
|
case "thickThinSmallGap":
|
||||||
|
return "粗细小间隔线";
|
||||||
|
case "nil":
|
||||||
|
return "无边框";
|
||||||
|
default:
|
||||||
|
return val; // 保留原值
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
} finally {
|
} finally {
|
||||||
|
@@ -13,6 +13,7 @@ import org.docx4j.dml.*;
|
|||||||
import org.docx4j.dml.CTColor;
|
import org.docx4j.dml.CTColor;
|
||||||
import org.docx4j.dml.picture.Pic;
|
import org.docx4j.dml.picture.Pic;
|
||||||
import org.docx4j.dml.wordprocessingDrawing.Anchor;
|
import org.docx4j.dml.wordprocessingDrawing.Anchor;
|
||||||
|
import org.docx4j.dml.wordprocessingDrawing.Inline;
|
||||||
import org.docx4j.jaxb.Context;
|
import org.docx4j.jaxb.Context;
|
||||||
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
|
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
|
||||||
import org.docx4j.vml.CTTextbox;
|
import org.docx4j.vml.CTTextbox;
|
||||||
@@ -1360,22 +1361,75 @@ public class TextInfo {
|
|||||||
|
|
||||||
//填充方式
|
//填充方式
|
||||||
public static String getTianChongValue(List<JudgementWordsVO> judgementWordsVOS, Anchor anchor, int betoLong, WordprocessingMLPackage wordMLPackage) {
|
public static String getTianChongValue(List<JudgementWordsVO> judgementWordsVOS, Anchor anchor, int betoLong, WordprocessingMLPackage wordMLPackage) {
|
||||||
|
if (anchor == null || anchor.getGraphic() == null) return "无填充";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// 1. 获取 anchor 的 graphicData
|
||||||
Object graphicData = anchor.getGraphic().getGraphicData().getAny().get(0);
|
Object graphicData = anchor.getGraphic().getGraphicData().getAny().get(0);
|
||||||
if (graphicData instanceof JAXBElement) {
|
if (!(graphicData instanceof JAXBElement)) return "无填充";
|
||||||
JAXBElement<?> jaxbElement = (JAXBElement<?>) graphicData;
|
|
||||||
Object value = jaxbElement.getValue();
|
JAXBElement<?> jaxbElement = (JAXBElement<?>) graphicData;
|
||||||
if (value instanceof CTWordprocessingShape) {
|
Object value = jaxbElement.getValue();
|
||||||
CTWordprocessingShape textInfo = (CTWordprocessingShape) value;
|
|
||||||
if (textInfo.getSpPr() != null) {
|
// 2. 确认是文本框形状
|
||||||
if (textInfo.getSpPr().getSolidFill() != null) {
|
if (!(value instanceof CTWordprocessingShape)) return "无填充";
|
||||||
return "纯色填充";
|
CTWordprocessingShape textShape = (CTWordprocessingShape) value;
|
||||||
} else if (textInfo.getSpPr().getBlipFill() != null) {
|
|
||||||
return "图片填充";
|
// 3. 解析 <w:txbxContent> 中的段落和文字
|
||||||
} else if (textInfo.getSpPr().getGradFill() != null) {
|
if (textShape.getTxbx() != null && textShape.getTxbx().getTxbxContent() != null) {
|
||||||
return "渐变填充";
|
List<Object> blockLevelElts = textShape.getTxbx().getTxbxContent().getEGBlockLevelElts();
|
||||||
} else {
|
|
||||||
return "无填充";
|
for (Object block : blockLevelElts) {
|
||||||
|
if (block instanceof P) {
|
||||||
|
P paragraph = (P) block;
|
||||||
|
for (Object runObj : paragraph.getContent()) {
|
||||||
|
if (runObj instanceof R) {
|
||||||
|
R run = (R) runObj;
|
||||||
|
|
||||||
|
// 4. 检查 run 的 rPr 中的颜色
|
||||||
|
if (run.getRPr() != null) {
|
||||||
|
RPr rPr = run.getRPr();
|
||||||
|
|
||||||
|
// 4.1 直接定义了颜色 -> 纯色填充
|
||||||
|
if (rPr.getColor() != null && rPr.getColor().getVal() != null) {
|
||||||
|
return "纯色填充";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4.2 检查 Drawing 中的 <a:solidFill> 或 <a:gradFill>
|
||||||
|
for (Object drawingObj : run.getContent()) {
|
||||||
|
if (drawingObj instanceof Drawing) {
|
||||||
|
Drawing drawing = (Drawing) drawingObj;
|
||||||
|
for (Object inlineObj : drawing.getAnchorOrInline()) {
|
||||||
|
if (inlineObj instanceof Inline) {
|
||||||
|
Inline inline = (Inline) inlineObj;
|
||||||
|
|
||||||
|
// 解析图形属性
|
||||||
|
if (inline.getGraphic() != null &&
|
||||||
|
inline.getGraphic().getGraphicData() != null) {
|
||||||
|
List<Object> anyList = inline.getGraphic().getGraphicData().getAny();
|
||||||
|
for (Object any : anyList) {
|
||||||
|
if (any instanceof JAXBElement) {
|
||||||
|
JAXBElement<?> innerElement = (JAXBElement<?>) any;
|
||||||
|
Object innerValue = innerElement.getValue();
|
||||||
|
|
||||||
|
// 解析 a:solidFill 或 a:gradFill
|
||||||
|
if (innerValue instanceof CTShapeProperties) {
|
||||||
|
CTShapeProperties shapeProps = (CTShapeProperties) innerValue;
|
||||||
|
if (shapeProps.getSolidFill() != null) {
|
||||||
|
return "纯色填充";
|
||||||
|
} else if (shapeProps.getGradFill() != null) {
|
||||||
|
return "渐变填充";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1383,78 +1437,177 @@ public class TextInfo {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 默认无填充
|
||||||
|
return "无填充";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 文本框 - 文字 - 纯色填充 → 颜色
|
||||||
|
public static String getTextBoxTextSolidFillColor(List<JudgementWordsVO> judgementWordsVOS,
|
||||||
|
Anchor anchor,
|
||||||
|
int betoLong,
|
||||||
|
WordprocessingMLPackage wordMLPackage) {
|
||||||
|
try {
|
||||||
|
// 1. 判空检查
|
||||||
|
if (anchor == null || anchor.getGraphic() == null || anchor.getGraphic().getGraphicData() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Object> anyList = anchor.getGraphic().getGraphicData().getAny();
|
||||||
|
if (anyList == null || anyList.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 遍历 GraphicData 下的内容
|
||||||
|
for (Object obj : anyList) {
|
||||||
|
Object value = (obj instanceof JAXBElement) ? ((JAXBElement<?>) obj).getValue() : obj;
|
||||||
|
|
||||||
|
// 只处理 CTWordprocessingShape
|
||||||
|
if (!value.getClass().getName().endsWith("CTWordprocessingShape")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 通过反射获取 getTxbx() 方法
|
||||||
|
Method getTxbxMethod;
|
||||||
|
try {
|
||||||
|
getTxbxMethod = value.getClass().getMethod("getTxbx");
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
System.out.println("当前 CTWordprocessingShape 没有 getTxbx() 方法");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object txbxObj = getTxbxMethod.invoke(value);
|
||||||
|
if (txbxObj == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 解析 wps:txbxContent
|
||||||
|
Method getTxbxContentMethod = txbxObj.getClass().getMethod("getTxbxContent");
|
||||||
|
Object txbxContent = getTxbxContentMethod.invoke(txbxObj);
|
||||||
|
|
||||||
|
if (txbxContent == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 获取段落 <w:p>
|
||||||
|
if (!(txbxContent instanceof ContentAccessor)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentAccessor contentAccessor = (ContentAccessor) txbxContent;
|
||||||
|
List<Object> paragraphs = contentAccessor.getContent();
|
||||||
|
if (paragraphs == null || paragraphs.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Object pObj : paragraphs) {
|
||||||
|
Object paragraph = (pObj instanceof JAXBElement) ? ((JAXBElement<?>) pObj).getValue() : pObj;
|
||||||
|
|
||||||
|
if (!(paragraph instanceof P)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. 获取段落中的 run
|
||||||
|
P p = (P) paragraph;
|
||||||
|
List<Object> runs = p.getContent();
|
||||||
|
for (Object rObj : runs) {
|
||||||
|
Object runVal = (rObj instanceof JAXBElement) ? ((JAXBElement<?>) rObj).getValue() : rObj;
|
||||||
|
if (!(runVal instanceof R)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
R run = (R) runVal;
|
||||||
|
RPr runPr = run.getRPr();
|
||||||
|
if (runPr != null && runPr.getColor() != null) {
|
||||||
|
String colorVal = runPr.getColor().getVal(); // 十六进制字符串,例如 "4874CB"
|
||||||
|
if (colorVal != null && colorVal.length() == 6) {
|
||||||
|
try {
|
||||||
|
int r = Integer.parseInt(colorVal.substring(0, 2), 16);
|
||||||
|
int g = Integer.parseInt(colorVal.substring(2, 4), 16);
|
||||||
|
int b = Integer.parseInt(colorVal.substring(4, 6), 16);
|
||||||
|
String rgb = "RGB(" + r + "," + g + "," + b + ")";
|
||||||
|
System.out.println("文本框文字颜色 = " + rgb);
|
||||||
|
return rgb;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("未找到文本框文字颜色");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 文本框-文字-纯色填充 → 透明度
|
||||||
|
public static String getTextBoxSolidFillTransparency(
|
||||||
|
List<JudgementWordsVO> judgementWordsVOS,
|
||||||
|
org.docx4j.dml.wordprocessingDrawing.Anchor anchor,
|
||||||
|
int betoLong,
|
||||||
|
WordprocessingMLPackage wordMLPackage) {
|
||||||
|
|
||||||
|
if (anchor == null) return "无纯色填充";
|
||||||
|
try {
|
||||||
|
// 1. 包装成 JAXBElement 打印调试 XML
|
||||||
|
JAXBElement<Anchor> jaxbElement = new JAXBElement<>(
|
||||||
|
new javax.xml.namespace.QName(
|
||||||
|
"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing",
|
||||||
|
"anchor"),
|
||||||
|
Anchor.class,
|
||||||
|
anchor
|
||||||
|
);
|
||||||
|
String xml = XmlUtils.marshaltoString(jaxbElement, true, true);
|
||||||
|
// System.out.println("Anchor XML:\n" + xml);
|
||||||
|
|
||||||
|
// 2. 直接解析 XML 字符串查找 w14:textFill/solidFill/schemeClr/alpha
|
||||||
//纯色填充→透明度
|
String alpha = "无纯色填充";
|
||||||
public static String getTextBoxSolidFillTransparency(List<JudgementWordsVO> judgementWordsVOS, Anchor anchor, int betoLong, WordprocessingMLPackage wordMLPackage) {
|
// 正则匹配 w14:solidFill 下的 w14:alpha
|
||||||
if (anchor == null || anchor.getGraphic() == null || anchor.getGraphic().getGraphicData() == null) {
|
java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(
|
||||||
System.out.println("Anchor 或 Graphic 为空");
|
"<w14:textFill>\\s*<w14:solidFill>.*?<w14:alpha\\s+w14:val=\"(\\d+)\"\\s*/>.*?</w14:solidFill>",
|
||||||
return "无纯色填充";
|
java.util.regex.Pattern.DOTALL
|
||||||
}
|
);
|
||||||
|
java.util.regex.Matcher matcher = pattern.matcher(xml);
|
||||||
List<Object> anyList = anchor.getGraphic().getGraphicData().getAny();
|
if (matcher.find()) {
|
||||||
if (anyList == null || anyList.isEmpty()) {
|
String alphaVal = matcher.group(1);
|
||||||
System.out.println("GraphicData 中没有任何对象");
|
// Word 中 alpha 取值范围 0~100000,对应 0~100%
|
||||||
return "无纯色填充";
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Object obj : anyList) {
|
|
||||||
Object value = obj instanceof JAXBElement ? ((JAXBElement<?>) obj).getValue() : obj;
|
|
||||||
|
|
||||||
// 文本框一般是 CTWordprocessingShape 类型
|
|
||||||
if (value.getClass().getName().endsWith("CTWordprocessingShape")) {
|
|
||||||
try {
|
try {
|
||||||
// 反射调用 getSpPr()
|
int alphaInt = Integer.parseInt(alphaVal);
|
||||||
Method getSpPrMethod = value.getClass().getMethod("getSpPr");
|
int percent = Math.round(alphaInt / 1000.0f); // 四舍五入取整百分比
|
||||||
Object spPrObj = getSpPrMethod.invoke(value);
|
alpha = percent + "%";
|
||||||
|
} catch (NumberFormatException ignored) {}
|
||||||
if (spPrObj == null) {
|
|
||||||
System.out.println("文本框 spPr 为 null");
|
|
||||||
return "无纯色填充";
|
|
||||||
}
|
|
||||||
|
|
||||||
// 反射调用 getSolidFill()
|
|
||||||
Method getSolidFillMethod = spPrObj.getClass().getMethod("getSolidFill");
|
|
||||||
Object solidFillObj = getSolidFillMethod.invoke(spPrObj);
|
|
||||||
|
|
||||||
if (solidFillObj == null) {
|
|
||||||
System.out.println("spPr 中无纯色填充");
|
|
||||||
return "无纯色填充";
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取 srgbClr 或 schemeClr
|
|
||||||
Method getSrgbClrMethod = solidFillObj.getClass().getMethod("getSrgbClr");
|
|
||||||
Object srgbClrObj = getSrgbClrMethod.invoke(solidFillObj);
|
|
||||||
|
|
||||||
Method getSchemeClrMethod = solidFillObj.getClass().getMethod("getSchemeClr");
|
|
||||||
Object schemeClrObj = getSchemeClrMethod.invoke(solidFillObj);
|
|
||||||
|
|
||||||
// 透明度提取逻辑
|
|
||||||
String transparency = "0%"; // 默认完全不透明
|
|
||||||
|
|
||||||
if (srgbClrObj != null) {
|
|
||||||
transparency = extractAlphaTransparency(srgbClrObj);
|
|
||||||
return transparency;
|
|
||||||
} else if (schemeClrObj != null) {
|
|
||||||
transparency = extractAlphaTransparency(schemeClrObj);
|
|
||||||
return transparency;
|
|
||||||
} else {
|
|
||||||
System.out.println("无srgbClr和schemeClr颜色");
|
|
||||||
return transparency;
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
System.out.println("未识别的类型: " + value.getClass().getName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return alpha;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
|
return "无纯色填充";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取透明度方法(0-100%)
|
||||||
|
private static int getAlphaFromColor(Object colorObj) {
|
||||||
|
try {
|
||||||
|
Method getAlpha = colorObj.getClass().getMethod("getAlpha");
|
||||||
|
Object alpha = getAlpha.invoke(colorObj);
|
||||||
|
if (alpha != null) {
|
||||||
|
// alpha 为 CTPositiveFixedPercentage 或类似类型
|
||||||
|
Method getVal = alpha.getClass().getMethod("getVal");
|
||||||
|
Long val = (Long) getVal.invoke(alpha); // 0-100000
|
||||||
|
return 100 - (int)(val / 1000); // 转换为百分比
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 如果没有 alpha,默认不透明
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user