From 607db65e357d9b796f95ff9b89b857e803311afc Mon Sep 17 00:00:00 2001 From: huababa1 <2037205722@qq.com> Date: Wed, 10 Sep 2025 21:51:57 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E4=BF=AE=E6=94=B9=E3=80=91=E6=96=87?= =?UTF-8?q?=E5=AD=97=E8=80=83=E7=82=B9=E6=AE=B5=E8=90=BD=EF=BC=8C=E7=BA=BF?= =?UTF-8?q?=E6=80=A7=E6=B1=89=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wps_word/docx4j/drawing/Drawing.java | 6 +- .../docx4j/drawing/DrawingInline.java | 102 +++++- .../wps_word/docx4j/paragraph/Paragraphs.java | 109 +++--- .../wps_word/docx4j/section/SectionPage.java | 3 +- .../utils/wps_word/docx4j/table/TableIng.java | 23 +- .../utils/wps_word/docx4j/text/TextInfo.java | 309 +++++++++++++----- 6 files changed, 431 insertions(+), 121 deletions(-) diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/drawing/Drawing.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/drawing/Drawing.java index 873c8dd9..c8858ab6 100644 --- a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/drawing/Drawing.java +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/drawing/Drawing.java @@ -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 judgementWordsVOS, return "是"; } - // 2. 预设类型(shadow preset) + // 2. 预设类型 public static String getShadowPreset(List 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()); diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/drawing/DrawingInline.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/drawing/DrawingInline.java index 359a39b2..9c310109 100644 --- a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/drawing/DrawingInline.java +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/drawing/DrawingInline.java @@ -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 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 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) { diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/paragraph/Paragraphs.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/paragraph/Paragraphs.java index 2c56cc7d..61ea2683 100644 --- a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/paragraph/Paragraphs.java +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/paragraph/Paragraphs.java @@ -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 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 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 "无"; } // 分栏 - 各栏宽度 diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/section/SectionPage.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/section/SectionPage.java index f1534224..789a9fc9 100644 --- a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/section/SectionPage.java +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/section/SectionPage.java @@ -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 "无"; diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/table/TableIng.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/table/TableIng.java index 9d17416e..0b475c13 100644 --- a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/table/TableIng.java +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/table/TableIng.java @@ -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 { diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/text/TextInfo.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/text/TextInfo.java index 4424f61e..4fe0cead 100644 --- a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/text/TextInfo.java +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/text/TextInfo.java @@ -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 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. 解析 中的段落和文字 + if (textShape.getTxbx() != null && textShape.getTxbx().getTxbxContent() != null) { + List 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 中的 + 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 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 judgementWordsVOS, + Anchor anchor, + int betoLong, + WordprocessingMLPackage wordMLPackage) { + try { + // 1. 判空检查 + if (anchor == null || anchor.getGraphic() == null || anchor.getGraphic().getGraphicData() == null) { + return null; + } + + List 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. 获取段落 + if (!(txbxContent instanceof ContentAccessor)) { + continue; + } + + ContentAccessor contentAccessor = (ContentAccessor) txbxContent; + List 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 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 judgementWordsVOS, + org.docx4j.dml.wordprocessingDrawing.Anchor anchor, + int betoLong, + WordprocessingMLPackage wordMLPackage) { + if (anchor == null) return "无纯色填充"; + try { + // 1. 包装成 JAXBElement 打印调试 XML + JAXBElement 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 judgementWordsVOS, Anchor anchor, int betoLong, WordprocessingMLPackage wordMLPackage) { - if (anchor == null || anchor.getGraphic() == null || anchor.getGraphic().getGraphicData() == null) { - System.out.println("Anchor 或 Graphic 为空"); - return "无纯色填充"; - } - - List 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( + "\\s*.*?.*?", + 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; }