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 lombok.val;
|
||||
import org.apache.xmlbeans.XmlCursor;
|
||||
import org.docx4j.XmlUtils;
|
||||
import org.docx4j.dml.*;
|
||||
import org.docx4j.dml.chartDrawing.CTPicture;
|
||||
@@ -24,6 +25,7 @@ import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathExpression;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.StringReader;
|
||||
@@ -1328,10 +1330,10 @@ public static String getSolidFillColor(List<JudgementWordsVO> judgementWordsVOS,
|
||||
return "是";
|
||||
}
|
||||
|
||||
// 2. 预设类型(shadow preset)
|
||||
// 2. 预设类型
|
||||
public static String getShadowPreset(List<JudgementWordsVO> judgementWordsVOS, Anchor anchor, int betoLong, WordprocessingMLPackage wordMLPackage) {
|
||||
CTReflectionEffect shadow = getReflectionEffect(anchor);
|
||||
if (shadow == null) return "无";
|
||||
if (shadow == null) return "无预设";
|
||||
|
||||
// 例如根据blurRad、dist、dir组合判断
|
||||
BigInteger blurRad = BigInteger.valueOf(shadow.getBlurRad());
|
||||
|
@@ -8,6 +8,7 @@ import org.docx4j.XmlUtils;
|
||||
import org.docx4j.dml.*;
|
||||
import org.docx4j.dml.chartDrawing.CTPicture;
|
||||
import org.docx4j.dml.picture.Pic;
|
||||
import org.docx4j.dml.wordprocessingDrawing.Anchor;
|
||||
import org.docx4j.dml.wordprocessingDrawing.CTWrapSquare;
|
||||
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) {
|
||||
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) {
|
||||
|
@@ -2,6 +2,7 @@ package pc.exam.pp.module.judgement.utils.wps_word.docx4j.paragraph;
|
||||
|
||||
import jakarta.xml.bind.JAXBElement;
|
||||
import org.docx4j.XmlUtils;
|
||||
import org.docx4j.model.structure.SectionWrapper;
|
||||
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
|
||||
import org.docx4j.openpackaging.parts.WordprocessingML.NumberingDefinitionsPart;
|
||||
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 java.math.BigInteger;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author REN
|
||||
@@ -790,59 +792,90 @@ public class Paragraphs {
|
||||
|
||||
// 分栏 - 分隔线
|
||||
public static String getParagraphColIsSep(P paragraph, StyleDefinitionsPart stylePart, WordprocessingMLPackage wordMLPackage, NumberingDefinitionsPart ndp) {
|
||||
PPr pPr = paragraph.getPPr();
|
||||
SectPr sectPr = null;
|
||||
sectPr = pPr.getSectPr();
|
||||
// 优先取段落自身的节属性
|
||||
if (pPr != null && pPr.getSectPr() != null) {
|
||||
sectPr = pPr.getSectPr();
|
||||
}
|
||||
if (paragraph == null) return "无";
|
||||
|
||||
// 或最后一个段落中会有一个节结束的SectPr
|
||||
if (sectPr == null && paragraph.getContent().size() > 0) {
|
||||
Object lastObj = paragraph.getContent().get(paragraph.getContent().size() - 1);
|
||||
if (lastObj instanceof JAXBElement && ((JAXBElement<?>) lastObj).getValue() instanceof SectPr) {
|
||||
sectPr = (SectPr) ((JAXBElement<?>) lastObj).getValue();
|
||||
List<Object> allParagraphs = wordMLPackage.getMainDocumentPart().getContent();
|
||||
if (allParagraphs == null || allParagraphs.isEmpty()) return "无";
|
||||
|
||||
SectPr currentSectPr = null;
|
||||
|
||||
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 "无";
|
||||
}
|
||||
|
||||
// 分栏 - 各栏间距
|
||||
public static String getParagraphColSpace(P paragraph, StyleDefinitionsPart stylePart, WordprocessingMLPackage wordMLPackage, NumberingDefinitionsPart ndp) {
|
||||
PPr pPr = paragraph.getPPr();
|
||||
SectPr sectPr = null;
|
||||
sectPr = pPr.getSectPr();
|
||||
// 优先取段落自身的节属性
|
||||
if (pPr != null && pPr.getSectPr() != null) {
|
||||
sectPr = pPr.getSectPr();
|
||||
}
|
||||
if (paragraph == null) return "无";
|
||||
|
||||
// 或最后一个段落中会有一个节结束的SectPr
|
||||
if (sectPr == null && paragraph.getContent().size() > 0) {
|
||||
Object lastObj = paragraph.getContent().get(paragraph.getContent().size() - 1);
|
||||
if (lastObj instanceof JAXBElement && ((JAXBElement<?>) lastObj).getValue() instanceof SectPr) {
|
||||
sectPr = (SectPr) ((JAXBElement<?>) lastObj).getValue();
|
||||
List<Object> allParagraphs = wordMLPackage.getMainDocumentPart().getContent();
|
||||
if (allParagraphs == null || allParagraphs.isEmpty()) return "无";
|
||||
|
||||
SectPr currentSectPr = null;
|
||||
|
||||
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) {
|
||||
CTColumns cols = sectPr.getCols();
|
||||
if (cols.getCol() != null && !cols.getCol().isEmpty()) {
|
||||
int index = 1;
|
||||
String value = "";
|
||||
for (CTColumn col : cols.getCol()) {
|
||||
value += "第 " + index + " 栏间距 (twips): " + col.getSpace() + " ";
|
||||
index++;
|
||||
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();
|
||||
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 "无";
|
||||
}
|
||||
// 分栏 - 各栏宽度
|
||||
|
@@ -29,6 +29,7 @@ import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import pc.exam.pp.module.judgement.utils.wps_word.utils.ColorUtils;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.xpath.XPath;
|
||||
@@ -1729,7 +1730,7 @@ public class SectionPage {
|
||||
// 以 Top 为例获取颜色
|
||||
CTBorder top = borders.getTop();
|
||||
if (top != null && top.getColor() != null) {
|
||||
return top.getColor();
|
||||
return ColorUtils.getChineseColorName(top.getColor());
|
||||
}
|
||||
}
|
||||
return "无";
|
||||
|
@@ -123,7 +123,28 @@ public class TableIng {
|
||||
tblCursor.selectPath(path);
|
||||
if (tblCursor.toNextSelection()) {
|
||||
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;
|
||||
} finally {
|
||||
|
@@ -13,6 +13,7 @@ import org.docx4j.dml.*;
|
||||
import org.docx4j.dml.CTColor;
|
||||
import org.docx4j.dml.picture.Pic;
|
||||
import org.docx4j.dml.wordprocessingDrawing.Anchor;
|
||||
import org.docx4j.dml.wordprocessingDrawing.Inline;
|
||||
import org.docx4j.jaxb.Context;
|
||||
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
|
||||
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) {
|
||||
if (anchor == null || anchor.getGraphic() == null) return "无填充";
|
||||
|
||||
try {
|
||||
// 1. 获取 anchor 的 graphicData
|
||||
Object graphicData = anchor.getGraphic().getGraphicData().getAny().get(0);
|
||||
if (graphicData instanceof JAXBElement) {
|
||||
JAXBElement<?> jaxbElement = (JAXBElement<?>) graphicData;
|
||||
Object value = jaxbElement.getValue();
|
||||
if (value instanceof CTWordprocessingShape) {
|
||||
CTWordprocessingShape textInfo = (CTWordprocessingShape) value;
|
||||
if (textInfo.getSpPr() != null) {
|
||||
if (textInfo.getSpPr().getSolidFill() != null) {
|
||||
return "纯色填充";
|
||||
} else if (textInfo.getSpPr().getBlipFill() != null) {
|
||||
return "图片填充";
|
||||
} else if (textInfo.getSpPr().getGradFill() != null) {
|
||||
return "渐变填充";
|
||||
} else {
|
||||
return "无填充";
|
||||
if (!(graphicData instanceof JAXBElement)) return "无填充";
|
||||
|
||||
JAXBElement<?> jaxbElement = (JAXBElement<?>) graphicData;
|
||||
Object value = jaxbElement.getValue();
|
||||
|
||||
// 2. 确认是文本框形状
|
||||
if (!(value instanceof CTWordprocessingShape)) return "无填充";
|
||||
CTWordprocessingShape textShape = (CTWordprocessingShape) value;
|
||||
|
||||
// 3. 解析 <w:txbxContent> 中的段落和文字
|
||||
if (textShape.getTxbx() != null && textShape.getTxbx().getTxbxContent() != null) {
|
||||
List<Object> blockLevelElts = textShape.getTxbx().getTxbxContent().getEGBlockLevelElts();
|
||||
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
// 文本框-文字-纯色填充 → 透明度
|
||||
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);
|
||||
|
||||
|
||||
//纯色填充→透明度
|
||||
public static String getTextBoxSolidFillTransparency(List<JudgementWordsVO> judgementWordsVOS, Anchor anchor, int betoLong, WordprocessingMLPackage wordMLPackage) {
|
||||
if (anchor == null || anchor.getGraphic() == null || anchor.getGraphic().getGraphicData() == null) {
|
||||
System.out.println("Anchor 或 Graphic 为空");
|
||||
return "无纯色填充";
|
||||
}
|
||||
|
||||
List<Object> anyList = anchor.getGraphic().getGraphicData().getAny();
|
||||
if (anyList == null || anyList.isEmpty()) {
|
||||
System.out.println("GraphicData 中没有任何对象");
|
||||
return "无纯色填充";
|
||||
}
|
||||
|
||||
for (Object obj : anyList) {
|
||||
Object value = obj instanceof JAXBElement ? ((JAXBElement<?>) obj).getValue() : obj;
|
||||
|
||||
// 文本框一般是 CTWordprocessingShape 类型
|
||||
if (value.getClass().getName().endsWith("CTWordprocessingShape")) {
|
||||
// 2. 直接解析 XML 字符串查找 w14:textFill/solidFill/schemeClr/alpha
|
||||
String alpha = "无纯色填充";
|
||||
// 正则匹配 w14:solidFill 下的 w14:alpha
|
||||
java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(
|
||||
"<w14:textFill>\\s*<w14:solidFill>.*?<w14:alpha\\s+w14:val=\"(\\d+)\"\\s*/>.*?</w14:solidFill>",
|
||||
java.util.regex.Pattern.DOTALL
|
||||
);
|
||||
java.util.regex.Matcher matcher = pattern.matcher(xml);
|
||||
if (matcher.find()) {
|
||||
String alphaVal = matcher.group(1);
|
||||
// Word 中 alpha 取值范围 0~100000,对应 0~100%
|
||||
try {
|
||||
// 反射调用 getSpPr()
|
||||
Method getSpPrMethod = value.getClass().getMethod("getSpPr");
|
||||
Object spPrObj = getSpPrMethod.invoke(value);
|
||||
|
||||
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());
|
||||
int alphaInt = Integer.parseInt(alphaVal);
|
||||
int percent = Math.round(alphaInt / 1000.0f); // 四舍五入取整百分比
|
||||
alpha = percent + "%";
|
||||
} catch (NumberFormatException ignored) {}
|
||||
}
|
||||
|
||||
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