【修改】word、excel补全,判分修改,超级管理员可以直接删除试卷任务

This commit is contained in:
huababa1
2025-08-17 23:24:09 +08:00
parent 0175ccef67
commit dfefc08fd6
21 changed files with 4040 additions and 525 deletions

View File

@@ -158,4 +158,8 @@ public interface EducationPaperTaskMapper extends BaseMapperX<EducationPaperTask
//查询该试卷涉及的所有课程课程ID + 名称)
List<CourseInVo> selectPaperCountBypaperId(@Param("paperId") String paperId);
List<String> selectUserRoleId(Long loginUserId);
List<String> selectUserRole(List<String> roleIds);
}

View File

@@ -201,7 +201,25 @@ public class EducationPaperTaskServiceImpl implements IEducationPaperTaskService
if (taskIds == null || taskIds.length == 0) {
return "请选择删除数据!";
}
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
List<String>roleIds= educationPaperTaskMapper.selectUserRoleId(loginUserId);
if (roleIds!=null&&roleIds.size()>0){
List<String> userRole= educationPaperTaskMapper.selectUserRole(roleIds);
if (userRole!=null&&userRole.size()>0) {
boolean flag = false;
for (String s : userRole) {
if ("超级管理员".equals(s) || "租户管理员".equals(s)) {
flag = true;
}
}
if (flag) {
// 3. 执行删除操作
educationPaperTaskMapper.deleteEducationPaperTaskByTaskIds(taskIds);
monitorMapper.deleteByTaskIds(taskIds);
return "删除成功";
}
}
}
// 1. 找出没有关联试卷的任务ID
List<String> canDeleteTaskIds = new ArrayList<>();
List<String> cannotDeleteTaskIds = new ArrayList<>();
@@ -250,6 +268,25 @@ public class EducationPaperTaskServiceImpl implements IEducationPaperTaskService
public String deleteEducationPaperTaskByTaskId(String taskId) {
EducationPaperTask educationPaperTask = educationPaperTaskMapper.selectById(taskId);
if (educationPaperTask.getTaskType().equals("0") || educationPaperTask.getTaskType().equals("1") || educationPaperTask.getTaskType().equals("3")) {
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
List<String>roleIds= educationPaperTaskMapper.selectUserRoleId(loginUserId);
if (roleIds!=null&&roleIds.size()>0){
List<String> userRole= educationPaperTaskMapper.selectUserRole(roleIds);
if (userRole!=null&&userRole.size()>0) {
boolean flag = false;
for (String s : userRole) {
if ("超级管理员".equals(s) || "租户管理员".equals(s)) {
flag = true;
}
}
if (flag) {
// 3. 执行删除操作
educationPaperTaskMapper.deleteEducationPaperTaskByTaskId(taskId);
monitorMapper.deleteByTaskId(taskId);
return "删除成功";
}
}
}
// 1. 找出没有关联试卷的任务ID
List<String> canDeleteTaskIds = new ArrayList<>();
List<String> cannotDeleteTaskIds = new ArrayList<>();

View File

@@ -43,6 +43,7 @@
LEFT JOIN education_paper_person pp ON s.id = pp.person_id
WHERE
s.user_type = #{userType}
and s.deleted = 0
AND s.id IN (
SELECT person_id FROM education_paper_person WHERE
session_id ='' and
@@ -83,6 +84,7 @@
LEFT JOIN education_paper_person pp ON s.id = pp.person_id
WHERE
s.user_type = #{userType}
and s.deleted = 0
AND s.id NOT IN (
SELECT person_id FROM education_paper_person WHERE task_id =#{taskId}
)
@@ -138,6 +140,7 @@
LEFT JOIN education_paper_person pp ON s.id = pp.person_id
WHERE
s.user_type = #{userType}
and s.deleted = 0
AND s.id IN (
SELECT person_id FROM education_paper_person WHERE
session_id ='' and
@@ -164,6 +167,7 @@
LEFT JOIN education_paper_person pp ON s.id = pp.person_id
WHERE
s.user_type = #{userType}
and s.deleted = 0
AND s.id NOT IN (
SELECT person_id FROM education_paper_person WHERE task_id =#{taskId}
)

View File

@@ -40,12 +40,17 @@
LIMIT 1;
</select>
<select id="selectUsedQuestionIds" resultType="java.lang.String">
SELECT DISTINCT qu_id
FROM education_paper_qu
WHERE qu_id IN
SELECT DISTINCT epq.qu_id
FROM education_paper_qu epq
JOIN education_paper ep ON ep.paper_id = epq.paper_id
JOIN education_paper_task ept ON ept.task_id = ep.task_id
WHERE epq.qu_id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
AND ept.task_type IN ('0','1','3')
and ep.deleted ='0'
and ept.deleted ='0';
</select>
<select id="selectByPaperIdAndType" resultType="java.lang.String">
SELECT epq.qu_id

View File

@@ -192,6 +192,17 @@
and course.deleted ='0'
GROUP BY course.sp_id, course.sp_name, major.sp_name
</select>
<select id="selectUserRoleId" resultType="java.lang.String">
select role_id from system_user_role where user_id =#{loginUserId}
</select>
<select id="selectUserRole" resultType="java.lang.String">
select name
from system_role
where id in
<foreach collection="list" item="roleId" open="(" separator="," close=")">
#{roleId}
</foreach>
</select>
<insert id="insertEducationPaperTask" parameterType="EducationPaperTask">

View File

@@ -208,7 +208,7 @@ public class XlsxMaster {
if (value != null) {
judgementXlsxVOS = setJudgementXlsx(
judgementXlsxVOS,
"" + sheetName + "" + docxFunction + "@" + value,
"" + sheetName + "" + docxFunction + "@" + value,
"" + sheetName + "" + firstName + examName + value
);
}
@@ -240,7 +240,7 @@ public class XlsxMaster {
if (value != null) {
judgementXlsxVOS = setJudgementXlsx(
judgementXlsxVOS,
"" + sheetName + "" + docxFunction + "@" + value,
"" + sheetName + "" + docxFunction + "@" + value,
"" + sheetName + "" + firstName + examName + value
);
}
@@ -263,7 +263,7 @@ public class XlsxMaster {
if (value != null) {
judgementXlsxVOS = setJudgementXlsx(
judgementXlsxVOS,
"" + sheetName + "" + docxFunction + "@" + value,
"" + sheetName + "" + docxFunction + "@" + value,
"" + sheetName + "" + firstName + examName + value
);
}
@@ -305,7 +305,7 @@ public class XlsxMaster {
if (value != null) {
judgementXlsxVOS = setJudgementXlsx(
judgementXlsxVOS,
"" + sheetName + "" + docxFunction + "@" + value,
"" + sheetName + "" + docxFunction + "@" + value,
"" + sheetName + "" + firstName + examName + value
);
}
@@ -351,7 +351,7 @@ public class XlsxMaster {
if (value != null) {
judgementXlsxVOS = setJudgementXlsx(
judgementXlsxVOS,
"" + sheetName + "" + docxFunction + "@" + value,
"" + sheetName + "" + docxFunction + "@" + value,
"" + sheetName + "" + firstName + examName + value
);
}
@@ -375,7 +375,7 @@ public class XlsxMaster {
if (value != null) {
judgementXlsxVOS = setJudgementXlsx(
judgementXlsxVOS,
"" + sheetName + "" + docxFunction + "@" + value,
"" + sheetName + "" + docxFunction + "@" + value,
"" + sheetName + "" + firstName + examName + value
);
}

View File

@@ -1,15 +1,21 @@
package pc.exam.pp.module.judgement.utils.wps_excel.xlsx4j.cell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFPalette;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.*;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBorder;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBorderPr;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTXf;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STBorderStyle;
import pc.exam.pp.module.judgement.utils.wps_word.utils.ColorUtils;
import java.lang.reflect.Method;
public class CellIng {
// 获取左框线样式
@@ -23,7 +29,8 @@ public class CellIng {
CellStyle style = cell.getCellStyle();
if (style instanceof XSSFCellStyle) {
XSSFCellStyle xssfStyle = (XSSFCellStyle) style;
return getColorNameOrRGB(xssfStyle.getLeftBorderXSSFColor());
return ColorUtils.getChineseColorName(getColorNameOrRGB(xssfStyle.getLeftBorderXSSFColor()));
}
return "";
}
@@ -40,7 +47,7 @@ public class CellIng {
CellStyle style = cell.getCellStyle();
if (style instanceof XSSFCellStyle) {
XSSFCellStyle xssfStyle = (XSSFCellStyle) style;
return getColorNameOrRGB(xssfStyle.getTopBorderXSSFColor());
return ColorUtils.getChineseColorName(getColorNameOrRGB(xssfStyle.getTopBorderXSSFColor()));
}
return "";
}
@@ -57,7 +64,7 @@ public class CellIng {
CellStyle style = cell.getCellStyle();
if (style instanceof XSSFCellStyle) {
XSSFCellStyle xssfStyle = (XSSFCellStyle) style;
return getColorNameOrRGB(xssfStyle.getRightBorderXSSFColor());
return ColorUtils.getChineseColorName(getColorNameOrRGB(xssfStyle.getRightBorderXSSFColor()));
}
return "";
}
@@ -74,7 +81,7 @@ public class CellIng {
CellStyle style = cell.getCellStyle();
if (style instanceof XSSFCellStyle) {
XSSFCellStyle xssfStyle = (XSSFCellStyle) style;
return getColorNameOrRGB(xssfStyle.getBottomBorderXSSFColor());
return ColorUtils.getChineseColorName(getColorNameOrRGB(xssfStyle.getBottomBorderXSSFColor()));
}
return "";
}
@@ -217,6 +224,178 @@ public class CellIng {
return "";
}
// 删除线
public static String getCellStrikeThrough(Cell cell, Workbook wb) {
if (cell == null) return "";
CellStyle style = cell.getCellStyle();
if (style == null) return "";
return style.getFontIndexAsInt() >= 0 && wb.getFontAt(style.getFontIndexAsInt()).getStrikeout()
? "" : "";
}
// 上标
public static String getCellSuperScript(Cell cell, Workbook wb) {
if (cell == null) return "";
CellStyle style = cell.getCellStyle();
if (style == null) return "";
short typeOffset = wb.getFontAt(style.getFontIndexAsInt()).getTypeOffset();
return typeOffset == Font.SS_SUPER ? "" : "";
}
// 下标
public static String getCellSubScript(Cell cell, Workbook wb) {
if (cell == null) return "";
CellStyle style = cell.getCellStyle();
if (style == null) return "";
short typeOffset = wb.getFontAt(style.getFontIndexAsInt()).getTypeOffset();
return typeOffset == Font.SS_SUB ? "" : "";
}
// 获取斜下框线样式
public static String getDiagonalDownBorderStyle(Cell cell, Workbook wb) {
if (cell == null || !(cell instanceof XSSFCell)) return "";
XSSFCellStyle style = (XSSFCellStyle) cell.getCellStyle();
try {
// 通过反射获取私有方法 getCTBorder
Method method = XSSFCellStyle.class.getDeclaredMethod("getCTBorder");
method.setAccessible(true);
CTBorder ctBorder = (CTBorder) method.invoke(style);
if (ctBorder != null && ctBorder.isSetDiagonal()) {
// 判断斜线方向是否向下
if (ctBorder.getDiagonalDown()) {
CTBorderPr borderPr = ctBorder.getDiagonal(); // 斜线的边框属性
if (borderPr != null && borderPr.getStyle() != null) {
return borderPr.getStyle().toString();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
// 斜下框线→颜色
public static String getDiagonalDownBorderColor(Cell cell, Workbook wb) {
if (cell == null || !(cell instanceof XSSFCell)) return "";
XSSFCellStyle style = (XSSFCellStyle) cell.getCellStyle();
try {
Method method = XSSFCellStyle.class.getDeclaredMethod("getCTBorder");
method.setAccessible(true);
CTBorder ctBorder = (CTBorder) method.invoke(style);
if (ctBorder != null && ctBorder.isSetDiagonal() && ctBorder.getDiagonalDown()) {
CTBorderPr borderPr = ctBorder.getDiagonal();
if (borderPr != null && borderPr.isSetColor()) {
String color = borderPr.getColor().getRgb().toString(); // 返回 RGB 字符串
return color != null ? ColorUtils.getChineseColorName(color) : "";
}
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
// 斜上框线→样式
public static String getDiagonalUpBorderStyle(Cell cell, Workbook wb) {
if (cell == null || !(cell instanceof XSSFCell)) return "";
XSSFCellStyle style = (XSSFCellStyle) cell.getCellStyle();
try {
Method method = XSSFCellStyle.class.getDeclaredMethod("getCTBorder");
method.setAccessible(true);
CTBorder ctBorder = (CTBorder) method.invoke(style);
if (ctBorder != null && ctBorder.isSetDiagonal() && ctBorder.getDiagonalUp()) {
CTBorderPr borderPr = ctBorder.getDiagonal();
if (borderPr != null && borderPr.getStyle() != null) {
return borderPr.getStyle().toString();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
// 斜上框线→颜色
public static String getDiagonalUpBorderColor(Cell cell, Workbook wb) {
if (cell == null || !(cell instanceof XSSFCell)) return "";
XSSFCellStyle style = (XSSFCellStyle) cell.getCellStyle();
try {
Method method = XSSFCellStyle.class.getDeclaredMethod("getCTBorder");
method.setAccessible(true);
CTBorder ctBorder = (CTBorder) method.invoke(style);
if (ctBorder != null && ctBorder.isSetDiagonal() && ctBorder.getDiagonalUp()) {
CTBorderPr borderPr = ctBorder.getDiagonal();
if (borderPr != null && borderPr.isSetColor()) {
String color = borderPr.getColor().getRgb().toString();
return color != null ? ColorUtils.getChineseColorName(color) : "";
}
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
// ===== 获取单元格文本String =====
public String getCellText(Cell cell, Workbook wb) {
if (cell == null) return "";
DataFormatter formatter = new DataFormatter();
return formatter.formatCellValue(cell);
}
// ===== 获取单元格值
public String getCellValue(Cell cell, Workbook wb) {
if (cell == null) return "";
switch (cell.getCellType()) {
case STRING:
return cell.getStringCellValue();
case NUMERIC:
if (DateUtil.isCellDateFormatted(cell)) {
return cell.getDateCellValue().toString();
} else {
return String.valueOf((long) cell.getNumericCellValue());
}
case BOOLEAN:
return String.valueOf(cell.getBooleanCellValue());
case FORMULA:
return cell.getCellFormula(); // 返回公式原文,例如 "A1+B1"
case BLANK:
case _NONE:
case ERROR:
default:
return "";
}
}
@@ -238,4 +417,121 @@ public class CellIng {
}
return String.format("%02X%02X%02X", rgb[0] & 0xFF, rgb[1] & 0xFF, rgb[2] & 0xFF);
}
// 数字格式
public static String getCellDataFormat(Cell cell, Workbook wb) {
if (cell == null) return "";
CellStyle style = cell.getCellStyle();
if (style == null) return "";
return style.getDataFormatString();
}
// 水平对齐
public static String getCellHorizontalAlignment(Cell cell, Workbook wb) {
if (cell == null) return "";
CellStyle style = cell.getCellStyle();
if (style == null) return "";
HorizontalAlignment alignment = style.getAlignment();
return alignment != null ? alignment.name() : "";
}
// 垂直对齐
public static String getCellVerticalAlignment(Cell cell, Workbook wb) {
if (cell == null) return "";
CellStyle style = cell.getCellStyle();
if (style == null) return "";
VerticalAlignment alignment = style.getVerticalAlignment();
return alignment != null ? alignment.name() : "";
}
// 缩进
public static String getCellIndent(Cell cell, Workbook wb) {
if (cell == null) return "0";
CellStyle style = cell.getCellStyle();
if (style == null) return "0";
return String.valueOf(style.getIndention());
}
// 自动换行
public static String getCellWrapText(Cell cell, Workbook wb) {
if (cell == null) return "";
CellStyle style = cell.getCellStyle();
if (style == null) return "";
return style.getWrapText() ? "" : "";
}
// 缩小字体填充ShrinkToFit
public static String getCellShrinkToFit(Cell cell, Workbook wb) {
if (cell == null) return "";
CellStyle style = cell.getCellStyle();
if (style == null) return "";
return style.getShrinkToFit() ? "" : "";
}
// 合并单元格
public static String getCellMerged(Cell cell, Workbook wb) {
if (cell == null || wb == null) return "";
Sheet sheet = cell.getSheet();
if (sheet == null) return "";
int row = cell.getRowIndex();
int col = cell.getColumnIndex();
for (int i = 0; i < sheet.getNumMergedRegions(); i++) {
CellRangeAddress range = sheet.getMergedRegion(i);
if (range.isInRange(row, col)) {
return "";
}
}
return "";
}
// 文本方向rotation
public static String getCellTextRotation(Cell cell, Workbook wb) {
if (cell == null) return "0";
CellStyle style = cell.getCellStyle();
if (style == null) return "0";
return String.valueOf(style.getRotation()); // 旋转角度
}
// 文本样式(加粗/斜体/下划线等)
public static String getCellFontStyle(Cell cell, Workbook wb) {
if (cell == null) return "";
CellStyle style = cell.getCellStyle();
if (style == null) return "";
Font font;
if (wb instanceof XSSFWorkbook) {
font = wb.getFontAt(style.getFontIndexAsInt());
} else if (wb instanceof HSSFWorkbook) {
font = wb.getFontAt(style.getFontIndexAsInt());
} else {
return "";
}
StringBuilder sb = new StringBuilder();
if (font.getBold()) sb.append("加粗 ");
if (font.getItalic()) sb.append("斜体 ");
if (font.getUnderline() != Font.U_NONE) sb.append("下划线 ");
if (sb.length() == 0) sb.append("常规");
return sb.toString().trim();
}
// 高度(行高)
public static String getCellRowHeight(Cell cell, Workbook wb) {
if (cell == null || cell.getSheet() == null) return "默认";
Row row = cell.getRow();
if (row == null) return "默认";
return String.valueOf(row.getHeight() / 20.0) + " pt"; // row.getHeight() 单位为 twips (1/20 pt)
}
// 宽度(列宽)
public static String getCellColumnWidth(Cell cell, Workbook wb) {
if (cell == null || cell.getSheet() == null) return "默认";
int colWidth = cell.getSheet().getColumnWidth(cell.getColumnIndex()); // 单位 1/256字符
return String.format("%.2f pt", colWidth / 256.0 * 7); // 约 7pt/字符宽,可根据字体调整
}
}

View File

@@ -45,23 +45,93 @@ public class ChartHandler {
if (chart == null) return "无图表";
CTChart ctChart = chart.getCTChart();
if (ctChart == null) return "无图表定义";
if (ctChart == null || ctChart.getPlotArea() == null) return "无图表定义";
// 这里尝试获取第一种图表类型
if (ctChart.getPlotArea() != null) {
if (ctChart.getPlotArea().getBarChartList().size() > 0) return "条形图";
if (ctChart.getPlotArea().getLineChartList().size() > 0) return "折线图";
if (ctChart.getPlotArea().getPieChartList().size() > 0) return "饼图";
if (ctChart.getPlotArea().getAreaChartList().size() > 0) return "面积图";
if (ctChart.getPlotArea().getScatterChartList().size() > 0) return "散点图";
// 可根据需求继续扩展
CTPlotArea plotArea = ctChart.getPlotArea();
// ===== 柱形 / 条形图 =====
if (!plotArea.getBarChartList().isEmpty()) {
CTBarChart barChart = plotArea.getBarChartArray(0);
STBarDir.Enum dir = barChart.getBarDir().getVal();
STBarGrouping.Enum grouping = barChart.getGrouping().getVal();
String baseName = (dir == STBarDir.COL) ? "柱形图" :
(dir == STBarDir.BAR) ? "条形图" : "柱形/条形图";
if (grouping == STBarGrouping.CLUSTERED) {
return "簇状" + baseName;
} else if (grouping == STBarGrouping.STACKED) {
return "堆积" + baseName;
} else if (grouping == STBarGrouping.PERCENT_STACKED) {
return "百分比堆积" + baseName;
} else {
return baseName;
}
}
if (!plotArea.getBar3DChartList().isEmpty()) {
return "三维柱形/条形图";
}
// ===== 折线图 =====
if (!plotArea.getLineChartList().isEmpty()) {
return "折线图";
}
if (!plotArea.getLine3DChartList().isEmpty()) {
return "三维折线图";
}
// ===== 饼图 =====
if (!plotArea.getPieChartList().isEmpty()) {
return "饼图";
}
if (!plotArea.getPie3DChartList().isEmpty()) {
return "三维饼图";
}
// ===== 面积图 =====
if (!plotArea.getAreaChartList().isEmpty()) {
return "面积图";
}
if (!plotArea.getArea3DChartList().isEmpty()) {
return "三维面积图";
}
// ===== 散点图 =====
if (!plotArea.getScatterChartList().isEmpty()) {
return "散点图";
}
// ===== 雷达图 =====
if (!plotArea.getRadarChartList().isEmpty()) {
return "雷达图";
}
// ===== 气泡图 =====
if (!plotArea.getBubbleChartList().isEmpty()) {
return "气泡图";
}
// ===== 组合图(多个 chart 类型) =====
int chartTypeCount = 0;
if (!plotArea.getBarChartList().isEmpty() || !plotArea.getBar3DChartList().isEmpty()) chartTypeCount++;
if (!plotArea.getLineChartList().isEmpty() || !plotArea.getLine3DChartList().isEmpty()) chartTypeCount++;
if (!plotArea.getPieChartList().isEmpty() || !plotArea.getPie3DChartList().isEmpty()) chartTypeCount++;
if (!plotArea.getAreaChartList().isEmpty() || !plotArea.getArea3DChartList().isEmpty()) chartTypeCount++;
if (!plotArea.getScatterChartList().isEmpty()) chartTypeCount++;
if (!plotArea.getRadarChartList().isEmpty()) chartTypeCount++;
if (!plotArea.getBubbleChartList().isEmpty()) chartTypeCount++;
if (chartTypeCount > 1) return "组合图";
return "未知图表类型";
}
/** 图表-数据-数据系列 - 产生方式 */
public String getDataSeriesGeneration(XSSFChart chart, XSSFSheet sheet) {
if (chart == null) return "无图表";

View File

@@ -7,6 +7,7 @@ import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.usermodel.*;
import pc.exam.pp.module.judgement.utils.wps_word.utils.ColorUtils;
import java.math.BigDecimal;
import java.util.ArrayList;
@@ -177,31 +178,50 @@ public class RangIng {
CellStyle style = cell.getCellStyle();
short dataFormatIndex = style.getDataFormat();
String dataFormatString = style.getDataFormatString();
System.out.println("数字格式索引: " + dataFormatIndex + ", 格式: " + dataFormatString);
if(dataFormatString!=null){
return dataFormatString;
}
return "";
}
//格式-合并单元格 (返回是否)
// 只有当 cellRefs 所有单元格都在同一个合并区域里时,才返回 "是"
public String isMergedRegion(String cellRef, Workbook workbook, int sheetIndex) {
List<String> cellRefs = getCellRefsInRange(cellRef);
String cellref = cellRefs.get(0);
CellReference cr = new CellReference(cellref);
int rowIndex = cr.getRow();
int colIndex = cr.getCol();
if (cellRefs == null || cellRefs.isEmpty()) return "";
Sheet sheet = workbook.getSheetAt(sheetIndex - 1);
if (sheet == null) return "";
int mergedRegionsCount = sheet.getNumMergedRegions();
if (mergedRegionsCount == 0) return "";
// 第一个单元格所在的合并区域
CellReference firstCr = new CellReference(cellRefs.get(0));
CellRangeAddress targetRange = null;
for (int i = 0; i < mergedRegionsCount; i++) {
CellRangeAddress range = sheet.getMergedRegion(i);
if (range.isInRange(rowIndex, colIndex)) {
return "";
if (range.isInRange(firstCr.getRow(), firstCr.getCol())) {
targetRange = range;
break;
}
}
// 如果第一个单元格不在任何合并区域,直接否
if (targetRange == null) return "";
// 检查所有 cellRefs 是否都在同一个合并区域内
for (String ref : cellRefs) {
CellReference cr = new CellReference(ref);
if (!targetRange.isInRange(cr.getRow(), cr.getCol())) {
return "";
}
}
return "";
}
@@ -234,19 +254,23 @@ public class RangIng {
// ===== 填充颜色 =====
if (rule.getPatternFormatting() != null) {
XSSFPatternFormatting pf = rule.getPatternFormatting();
Color bgColor = pf.getFillBackgroundColorColor();
XSSFColor xssfColor = (XSSFColor) bgColor;
XSSFColor xssfColor = pf.getFillBackgroundColorColor();
if (xssfColor != null) {
byte[] argb = xssfColor.getARGB();
if (argb != null) {
if (argb != null && argb.length == 4) {
String hex = String.format("%02X%02X%02X", argb[1], argb[2], argb[3]);
return pc.exam.pp.module.judgement.utils.wps_word.utils.ColorUtils.getChineseColorName(hex);
} else {
String chineseColorName = ColorUtils.getChineseColorName(hex);
// 转成十进制 RGB
int r = argb[1] & 0xFF;
int g = argb[2] & 0xFF;
int b = argb[3] & 0xFF;
String rgb = String.format(chineseColorName+",RGB(%d,%d,%d)", r, g, b);
return rgb;
}
}
return "";
}
}
}
}
}
@@ -277,18 +301,22 @@ public class RangIng {
// ===== 字体颜色 =====
if (rule.getFontFormatting() != null) {
XSSFFontFormatting ff = rule.getFontFormatting();
Color fontColor = ff.getFontColor();
XSSFColor xssfColor = (XSSFColor) fontColor;
XSSFColor xssfColor = ff.getFontColor();
if (xssfColor != null) {
byte[] argb = xssfColor.getARGB();
if (argb != null) {
if (argb != null && argb.length == 4) {
String hex = String.format("%02X%02X%02X", argb[1], argb[2], argb[3]);
return pc.exam.pp.module.judgement.utils.wps_word.utils.ColorUtils.getChineseColorName(hex);
} else {
String chineseColorName = ColorUtils.getChineseColorName(hex);
int r = argb[1] & 0xFF;
int g = argb[2] & 0xFF;
int b = argb[3] & 0xFF;
String rgb = String.format(chineseColorName+",RGB(%d,%d,%d)", r, g, b);
return rgb;
}
}
return "";
}
}
}
}
}
@@ -319,7 +347,16 @@ public class RangIng {
System.out.println("下边框颜色: " + (borderColorBottom != null ? borderColorBottom.getARGBHex() : ""));
System.out.println("左边框颜色: " + (borderColorLeft != null ? borderColorLeft.getARGBHex() : ""));
System.out.println("右边框颜色: " + (borderColorRight != null ? borderColorRight.getARGBHex() : ""));
return pc.exam.pp.module.judgement.utils.wps_word.utils.ColorUtils.getChineseColorName(borderColorTop.getARGBHex() );
if (borderColorTop != null && borderColorTop.getARGBHex() != null) {
String hex=borderColorTop.getARGBHex();
if (hex != null && hex.length() == 8) {
hex = hex.substring(2); // 去掉前两位 Alpha
}
if (hex != null) {
return ColorUtils.getChineseColorName(hex);
}
}
return "";
} else {
System.out.println("边框颜色索引(旧版HSSF): top=" + style.getTopBorderColor()
@@ -405,7 +442,13 @@ public class RangIng {
XSSFCellStyle xssfStyle = (XSSFCellStyle) style;
XSSFColor fillColor = xssfStyle.getFillForegroundXSSFColor();
if (fillColor != null && fillColor.getARGBHex() != null) {
return pc.exam.pp.module.judgement.utils.wps_word.utils.ColorUtils.getChineseColorName(fillColor.getARGBHex() );
String hex=fillColor.getARGBHex();
if (hex != null && hex.length() == 8) {
hex = hex.substring(2); // 去掉前两位 Alpha
}
if (hex != null) {
return ColorUtils.getChineseColorName(hex);
}
}
}
}

View File

@@ -9,6 +9,7 @@ import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTGraphical
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageBreak;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetProtection;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;
import pc.exam.pp.module.judgement.utils.wps_word.utils.ColorUtils;
public class Style {
@@ -33,7 +34,13 @@ public class Style {
Sheet sheet = workbook.getSheetAt(sheetNum);
if (sheet instanceof XSSFSheet) {
XSSFColor color = ((XSSFSheet) sheet).getTabColor();
if (color != null) return color.getARGBHex();
String hex=color.getARGBHex();
if (hex != null && hex.length() == 8) {
hex = hex.substring(2); // 去掉前两位 Alpha
}
if (hex != null) {
return ColorUtils.getChineseColorName(hex);
}
}
return "";
}

View File

@@ -65,7 +65,7 @@ public class DocxConversion {
String shortText = shorten(fullText); // 截断展示
setWordDataInfo(secondIdWp, firstIdWp, "段落" + wpIndex + ":" + shortText, "w:p", String.valueOf(wpIndex), true, dataInfoVOS);
String[] sentences = fullText.split("");
String[] sentences = fullText.split("[。!?.!?]");
int sentenceIndex = 0;
for (String sentence : sentences) {
sentence = sentence.trim();

View File

@@ -188,8 +188,8 @@ public class DocxMaster {
}
}
if (firstName.contains("句子")) {
// 修改的正则,支持非贪婪匹配到】结束,包括中间包含换行、点号等
Pattern pattern = Pattern.compile("【(句子\\d+):(.+?)】");
// 支持非贪婪匹配到】结束,包括中间包含换行、点号等
Pattern pattern = Pattern.compile("【(句子\\d+):(.+?)】", Pattern.DOTALL);
Matcher matcher = pattern.matcher(firstName);
if (!matcher.find()) continue;
@@ -201,39 +201,87 @@ public class DocxMaster {
for (Object obj : paragraphs) {
paragraphIndex++;
Object realObj = XmlUtils.unwrap(obj);
if (realObj instanceof P) {
if (!(realObj instanceof P)) continue;
P paragraph = (P) realObj;
List<Object> paragraphContent = paragraph.getContent();
// 构建整段文本并记录每个 Run 的位置
List<R> runList = new ArrayList<>();
List<int[]> runPositions = new ArrayList<>();
StringBuilder paragraphTextBuilder = new StringBuilder();
for (Object part : paragraphContent) {
Object contentObj = XmlUtils.unwrap(part);
if (contentObj instanceof R) {
int posCounter = 0;
for (Object part : paragraph.getContent()) {
Object unwrappedPart = XmlUtils.unwrap(part);
if (paragraphIndex == Integer.parseInt(indexParm)) {
R run = (R) contentObj;
if (unwrappedPart instanceof R) {
R run = (R) unwrappedPart;
runList.add(run);
// 提取 run 的纯文本
StringBuilder sb = new StringBuilder();
for (Object rc : run.getContent()) {
Object realRc = XmlUtils.unwrap(rc);
if (realRc instanceof Text) {
sb.append(((Text) realRc).getValue());
String runText = getRunText(run);
paragraphTextBuilder.append(runText);
runPositions.add(new int[]{posCounter, posCounter + runText.length()});
posCounter += runText.length();
} else if (unwrappedPart instanceof P.Hyperlink) {
P.Hyperlink link = (P.Hyperlink) unwrappedPart;
for (Object linkPart : link.getContent()) {
Object unwrappedLinkPart = XmlUtils.unwrap(linkPart);
if (unwrappedLinkPart instanceof R) {
R run = (R) unwrappedLinkPart;
runList.add(run);
String runText = getRunText(run); // 包含超链接文本
paragraphTextBuilder.append(runText);
runPositions.add(new int[]{posCounter, posCounter + runText.length()});
posCounter += runText.length();
}
}
}
}
String actualText = sb.toString().trim();
String fullText = paragraphTextBuilder.toString();
if (fullText.trim().isEmpty()) continue;
// 模糊匹配:实际文本包含期望文本,或期望文本包含实际文本
if (isFuzzyMatch(expectedText, actualText)) {
// 用正则匹配句子(保留句子分隔符)
Pattern sentencePattern = Pattern.compile("[^。!?.!?]+[。!?.!?]?");
Matcher sentenceMatcher = sentencePattern.matcher(fullText);
while (sentenceMatcher.find()) {
String sentence = sentenceMatcher.group().trim();
if (sentence.isEmpty()) continue;
int sentenceStart = sentenceMatcher.start();
int sentenceEnd = sentenceMatcher.end();
// 判断是否匹配期望文本 & 段落位置
if (!isFuzzyMatch(expectedText, sentence) || paragraphIndex != Integer.parseInt(indexParm)) {
continue;
}
// ⚡ 找到包含该句子的 Run 集合
List<R> sentenceRuns = new ArrayList<>();
for (int a = 0; a < runList.size(); a++) {
int[] pos = runPositions.get(a);
if (pos[1] > sentenceStart && pos[0] < sentenceEnd) {
sentenceRuns.add(runList.get(a));
}
}
if (sentenceRuns.isEmpty()) continue;
// ⚡ 一句话只调用一次方法
try {
Class<?> runTextClass = RunText.class;
Method method = runTextClass.getMethod(function, R.class, String.class);
String value = (String) method.invoke(null, run, actualText);
Method method = runTextClass.getMethod(
function, List.class, String.class, P.class, StyleDefinitionsPart.class
);
// 反射调用方法,处理整个 Run 集合
String value = (String) method.invoke(null, sentenceRuns, sentence,paragraph, stylePart);
if (value != null) {
System.out.println("期望: " + expectedText);
System.out.println("结果: " + value + " ======== " + sentence);
if (value!=null){
// 写入结果
judgementWordsVOS = setJudgementWord(
judgementWordsVOS,
docxFunction + "@" + value,
@@ -247,11 +295,11 @@ public class DocxMaster {
}
}
}
}
}
}
if (firstName.contains("图片")) {
// 从 firstName 中提取图形编号,例如 【图形1:图片2】
Pattern pattern = Pattern.compile("【图形(\\d+):(.+?)】");
@@ -721,7 +769,7 @@ public class DocxMaster {
// 提取 run 中的文本内容
private static String getRunText(R run) {
public static String getRunText(R run) {
StringBuilder sb = new StringBuilder();
for (Object content : run.getContent()) {
if (content instanceof Text) {
@@ -735,6 +783,11 @@ public class DocxMaster {
}
return sb.toString();
}
/**
* 将 expectedText 中的 ... 处理为正则表达式的模糊匹配,并判断 actualText 是否匹配
*/
@@ -777,5 +830,33 @@ public class DocxMaster {
return false;
}
/**
* 递归获取 R/Hyperlink 内文字,包括超链接里的文本
*/
public static String getRunTextIncludingHyperlink(Object obj) {
if (obj == null) return "";
StringBuilder sb = new StringBuilder();
Object unwrapped = XmlUtils.unwrap(obj);
if (unwrapped instanceof R) {
R run = (R) unwrapped;
for (Object rc : run.getContent()) {
sb.append(getRunTextIncludingHyperlink(rc));
}
} else if (unwrapped instanceof Text) {
sb.append(((Text) unwrapped).getValue());
} else if (unwrapped instanceof R.Tab) {
sb.append("\t");
} else if (unwrapped instanceof Br) {
sb.append("\n");
} else if (unwrapped instanceof P.Hyperlink) {
P.Hyperlink link = (P.Hyperlink) unwrapped;
for (Object linkPart : link.getContent()) {
sb.append(getRunTextIncludingHyperlink(linkPart));
}
}
return sb.toString();
}
}

View File

@@ -9,7 +9,6 @@ import org.docx4j.dml.picture.Pic;
import org.docx4j.dml.wordprocessingDrawing.Anchor;
import org.docx4j.dml.wordprocessingDrawing.Inline;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.dom4j.QName;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
@@ -20,6 +19,7 @@ import pc.exam.pp.module.judgement.utils.wps_word.utils.ColorUtils;
import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
@@ -33,6 +33,8 @@ import java.lang.reflect.Method;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Drawing {
@@ -87,11 +89,19 @@ public class Drawing {
//布局 环绕方式
public static String getLayoutHuanRao(List<JudgementWordsVO> judgementWordsVOS, Anchor anchor, int betoLong, WordprocessingMLPackage wordMLPackage) {
String layoutHuanRaoValue = anchor.getWrapSquare().getWrapText().value();
layoutHuanRaoValue = getLayoutHuanRaoName(layoutHuanRaoValue);
return layoutHuanRaoValue;
}
if (anchor == null) return "未知";
// 是否衬于文字下方
boolean behindDoc = anchor.isBehindDoc();
if (behindDoc) return "衬于文字下方型";
// 浮于文字上方型
if (anchor.getWrapNone() != null) return "浮于文字上方型";
if (anchor.getWrapSquare() != null) return "四周型";
if (anchor.getWrapTight() != null) return "紧密型";
if (anchor.getWrapThrough() != null) return "穿越型";
if (anchor.getWrapTopAndBottom() != null) return "上下型";
return "";
}
// 形状和样式
public static List<JudgementWordsVO> getStyles(List<JudgementWordsVO> judgementWordsVOS, Anchor anchor, int betoLong, WordprocessingMLPackage wordMLPackage) {
@@ -230,9 +240,9 @@ public class Drawing {
CTLineProperties outline = pic.getSpPr().getLn();
if (outline.getSolidFill() != null) {
if (outline.getSolidFill().getSrgbClr() != null) {
return outline.getSolidFill().getSrgbClr().getVal();
return ColorUtils.getChineseColorName(outline.getSolidFill().getSrgbClr().getVal());
} else if (outline.getSolidFill().getSchemeClr() != null) {
return outline.getSolidFill().getSchemeClr().getVal().value();
return ColorUtils.getChineseColorName(outline.getSolidFill().getSchemeClr().getVal().value());
}
}
}
@@ -552,7 +562,9 @@ public class Drawing {
String name = "【第" + betoLong + "个图形】【图片】" + huiZhiName;
CTOuterShadowEffect shadow = getOuterShadow(anchor);
if (shadow == null) {
CTInnerShadowEffect innerShadow= getInnerShadow(anchor);
CTPresetShadowEffect presetShadow = getPresetShadow(anchor);
if (shadow == null&&innerShadow==null&&presetShadow==null) {
return "";
}
return "";
@@ -561,8 +573,9 @@ public class Drawing {
// 获取“颜色”属性(阴影颜色)
public static String getShadowColor(List<JudgementWordsVO> judgementWordsVOS, Anchor anchor, int betoLong, WordprocessingMLPackage wordMLPackage) {
CTOuterShadowEffect shadow = getOuterShadow(anchor);
if (shadow == null) return "";
CTInnerShadowEffect innerShadow= getInnerShadow(anchor);
CTPresetShadowEffect presetShadow = getPresetShadow(anchor);
if (shadow != null) {
if (shadow.getPrstClr() != null) {
return ColorUtils.getChineseColorName(shadow.getPrstClr().getVal().value());
@@ -570,7 +583,23 @@ public class Drawing {
if (shadow.getSrgbClr() != null) {
return ColorUtils.getChineseColorName(shadow.getSrgbClr().getVal());
}
}
if (innerShadow!=null){
if (innerShadow.getPrstClr() != null) {
return ColorUtils.getChineseColorName(shadow.getPrstClr().getVal().value());
}
if (innerShadow.getSrgbClr() != null) {
return ColorUtils.getChineseColorName(shadow.getSrgbClr().getVal());
}
}
if (presetShadow!=null){
if (presetShadow.getPrstClr() != null) {
return ColorUtils.getChineseColorName(presetShadow.getPrstClr().getVal().value());
}
if (presetShadow.getSrgbClr() != null) {
return ColorUtils.getChineseColorName(presetShadow.getSrgbClr().getVal());
}
}
return "未知";
}
@@ -578,40 +607,92 @@ public class Drawing {
//模糊
public static String getShadowBlur(List<JudgementWordsVO> judgementWordsVOS, Anchor anchor, int betoLong, WordprocessingMLPackage wordMLPackage) {
CTOuterShadowEffect shadow = getOuterShadow(anchor);
if (shadow == null) return "";
CTInnerShadowEffect innerShadow= getInnerShadow(anchor);
if (shadow != null){
// blurRad 单位是 EMUs转成磅(1磅=12700 EMUs)
double blurPts = shadow.getBlurRad() / 12700.0;
return String.format("%.2f 磅", blurPts);
}
if (innerShadow!=null){
// blurRad 单位是 EMUs转成磅(1磅=12700 EMUs)
double blurPts = innerShadow.getBlurRad() / 12700.0;
return String.format("%.2f 磅", blurPts);
}
return "";
}
//距离
public static String getShadowDistance(List<JudgementWordsVO> judgementWordsVOS, Anchor anchor, int betoLong, WordprocessingMLPackage wordMLPackage) {
CTOuterShadowEffect shadow = getOuterShadow(anchor);
if (shadow == null) return "";
CTInnerShadowEffect innerShadow= getInnerShadow(anchor);
CTPresetShadowEffect presetShadow = getPresetShadow(anchor);
if (shadow != null) {
// dist 单位 EMUs转成厘米
double distCm = shadow.getDist() / 12700.0;
return String.format("%.2f 磅", distCm);
}
if (innerShadow!=null){
// dist 单位 EMUs转成厘米
double distCm = innerShadow.getDist() / 12700.0;
return String.format("%.2f 磅", distCm);
}
if (presetShadow!=null){
// dist 单位 EMUs转成厘米
double distCm = presetShadow.getDist() / 12700.0;
return String.format("%.2f 磅", distCm);
}
return "";
}
//大小
public static String getShadowScaleX(List<JudgementWordsVO> judgementWordsVOS, Anchor anchor, int betoLong, WordprocessingMLPackage wordMLPackage) {
CTOuterShadowEffect shadow = getOuterShadow(anchor);
if (shadow == null) return "";
CTInnerShadowEffect innerShadow= getInnerShadow(anchor);
CTPresetShadowEffect presetShadow = getPresetShadow(anchor);
if (shadow != null) {
// sx 单位是 1/1000 百分比
double scaleXPercent = shadow.getSx() / 1000.0;
return String.format("%.1f%%", scaleXPercent);
}
if (innerShadow!=null){
// sx 单位是 1/1000 百分比
return "";
}
if (presetShadow!=null){
return "";
}
return "";
}
//角度
public static String getShadowDirection(List<JudgementWordsVO> judgementWordsVOS, Anchor anchor, int betoLong, WordprocessingMLPackage wordMLPackage) {
CTOuterShadowEffect shadow = getOuterShadow(anchor);
if (shadow == null) return "";
CTInnerShadowEffect innerShadow= getInnerShadow(anchor);
CTPresetShadowEffect presetShadow = getPresetShadow(anchor);
if (shadow != null) {
// dir 单位是 1/60000 度
double dirDegree = shadow.getDir() / 60000.0;
return String.format("%.1f°", dirDegree);
}
if (innerShadow!=null){
// dir 单位是 1/60000 度
double dirDegree = innerShadow.getDir() / 60000.0;
return String.format("%.1f°", dirDegree);
}
if (presetShadow!=null){
// dir 单位是 1/60000 度
double dirDegree = presetShadow.getDir() / 60000.0;
return String.format("%.1f°", dirDegree);
}
return "";
}
public static String getShadowAlpha(List<JudgementWordsVO> judgementWordsVOS, Anchor anchor, int betoLong, WordprocessingMLPackage wordMLPackage) {
if (anchor == null) return "";
@@ -713,8 +794,80 @@ public class Drawing {
// 获取“预设”
public static String getShadowPresetType(List<JudgementWordsVO> judgementWordsVOS, Anchor 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 "";
}
@@ -1199,6 +1352,50 @@ public static String getSolidFillColor(List<JudgementWordsVO> judgementWordsVOS,
return String.format("%.2f 磅", distPt);
}
// 图片-形状效果→柔化边缘→绘制(是否)
public static String isSoftEdgeEnabled(List<JudgementWordsVO> judgementWordsVOS, Anchor anchor, int betoLong, WordprocessingMLPackage wordMLPackage) {
if (anchor == null || anchor.getGraphic() == null || anchor.getGraphic().getGraphicData() == null)
return "";
Object anyObj = anchor.getGraphic().getGraphicData().getAny().get(0);
Object obj = (anyObj instanceof JAXBElement) ? ((JAXBElement<?>) anyObj).getValue() : anyObj;
try {
String xml = XmlUtils.marshaltoString(obj, true, true);
// 如果 XML 中存在 <a:softEdge ... /> 就表示启用
if( xml.contains("<a:softEdge")){
return "";
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
// 图片-形状效果→柔化边缘→大小(磅)
public static String getSoftEdgeSize(List<JudgementWordsVO> judgementWordsVOS, Anchor anchor, int betoLong, WordprocessingMLPackage wordMLPackage) {
if (anchor == null || anchor.getGraphic() == null || anchor.getGraphic().getGraphicData() == null)
return "无柔化";
Object anyObj = anchor.getGraphic().getGraphicData().getAny().get(0);
Object obj = (anyObj instanceof JAXBElement) ? ((JAXBElement<?>) anyObj).getValue() : anyObj;
try {
String xml = XmlUtils.marshaltoString(obj, true, true);
Pattern pattern = Pattern.compile("<a:softEdge\\s+rad=\"(\\d+)\"\\s*/>");
Matcher matcher = pattern.matcher(xml);
if (matcher.find()) {
int rad = Integer.parseInt(matcher.group(1));
// EMU 转磅
double sizePt = rad * 72.0 / 914400.0;
return String.format("%.2f 磅", sizePt);
}
} catch (Exception e) {
e.printStackTrace();
}
return "无柔化";
}
// ----- 辅助方法 -----
@@ -1385,12 +1582,41 @@ public static String getSolidFillColor(List<JudgementWordsVO> judgementWordsVOS,
CTShapeProperties spPr = anchor.getGraphic().getGraphicData().getPic().getSpPr();
if (spPr != null && spPr.getEffectLst() != null && spPr.getEffectLst().getOuterShdw() != null) {
return spPr.getEffectLst().getOuterShdw();
}
}
return null;
}
private static CTInnerShadowEffect getInnerShadow(Anchor 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(Anchor 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;
}

View File

@@ -203,7 +203,7 @@ public class DrawingInline {
}
}
}
return colorValue;
return ColorUtils.getChineseColorName(colorValue);
}

View File

@@ -1,11 +1,13 @@
package pc.exam.pp.module.judgement.utils.wps_word.docx4j.paragraph;
import jakarta.xml.bind.JAXBElement;
import org.docx4j.XmlUtils;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.NumberingDefinitionsPart;
import org.docx4j.openpackaging.parts.WordprocessingML.StyleDefinitionsPart;
import org.docx4j.wml.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTextAlignment;
import pc.exam.pp.module.judgement.utils.wps_word.utils.ColorUtils;
import java.math.BigInteger;
@@ -143,8 +145,10 @@ public class Paragraphs {
public static String getParagraphSpacingBeforeLines(P paragraph, StyleDefinitionsPart stylePart, WordprocessingMLPackage wordMLPackage, NumberingDefinitionsPart ndp) {
PPr pPr = paragraph.getPPr();
if (pPr != null && pPr.getSpacing() != null) {
if (pPr.getSpacing().getBeforeLines()!=null){
return pPr.getSpacing().getBeforeLines().toString();
}
}
if (pPr != null && pPr.getPStyle() != null && stylePart != null) {
String styleId = pPr.getPStyle().getVal();
Style style = stylePart.getStyleById(styleId);
@@ -159,8 +163,10 @@ public class Paragraphs {
public static String getParagraphSpacingBefore(P paragraph, StyleDefinitionsPart stylePart, WordprocessingMLPackage wordMLPackage, NumberingDefinitionsPart ndp) {
PPr pPr = paragraph.getPPr();
if (pPr != null && pPr.getSpacing() != null) {
if(pPr.getSpacing().getBefore()!=null){
return pPr.getSpacing().getBefore().toString();
}
}
if (pPr != null && pPr.getPStyle() != null && stylePart != null) {
String styleId = pPr.getPStyle().getVal();
Style style = stylePart.getStyleById(styleId);
@@ -175,8 +181,10 @@ public class Paragraphs {
public static String getParagraphSpacingAfter(P paragraph, StyleDefinitionsPart stylePart, WordprocessingMLPackage wordMLPackage, NumberingDefinitionsPart ndp) {
PPr pPr = paragraph.getPPr();
if (pPr != null && pPr.getSpacing() != null) {
if(pPr.getSpacing().getAfter()!=null){
return pPr.getSpacing().getAfter().toString();
}
}
if (pPr != null && pPr.getPStyle() != null && stylePart != null) {
String styleId = pPr.getPStyle().getVal();
Style style = stylePart.getStyleById(styleId);
@@ -192,8 +200,10 @@ public class Paragraphs {
public static String getParagraphSpacingAfterLines(P paragraph, StyleDefinitionsPart stylePart, WordprocessingMLPackage wordMLPackage, NumberingDefinitionsPart ndp) {
PPr pPr = paragraph.getPPr();
if (pPr != null && pPr.getSpacing() != null) {
if (pPr.getSpacing().getAfterLines()!=null){
return pPr.getSpacing().getAfterLines().toString();
}
}
if (pPr != null && pPr.getPStyle() != null && stylePart != null) {
String styleId = pPr.getPStyle().getVal();
Style style = stylePart.getStyleById(styleId);
@@ -205,39 +215,152 @@ public class Paragraphs {
return "";
}
/// 段落格式(间距) 间
public static String getParagraphSpacingLine(P paragraph, StyleDefinitionsPart stylePart, WordprocessingMLPackage wordMLPackage, NumberingDefinitionsPart ndp) {
// 段落
// 段落行距
public static String getParagraphSpacingLine(P paragraph, StyleDefinitionsPart stylePart,
WordprocessingMLPackage wordMLPackage, NumberingDefinitionsPart ndp) {
if (paragraph == null) return "";
PPr pPr = paragraph.getPPr();
if (pPr != null && pPr.getSpacing() != null) {
return pPr.getSpacing().getLine().toString();
try {
String xml = XmlUtils.marshaltoString(stylePart.getJaxbElement(), true, true);
System.out.println(xml);
} catch (Exception e) {
e.printStackTrace();
}
if (pPr != null && pPr.getPStyle() != null && stylePart != null) {
String styleId = pPr.getPStyle().getVal();
Style style = stylePart.getStyleById(styleId);
if (style != null && style.getPPr() != null && style.getPPr().getSpacing() != null) {
PPrBase.Spacing spacing = style.getPPr().getSpacing();
return spacing.getLine().toString();
// 1⃣ 段落自身行距
if (pPr != null && pPr.getSpacing() != null && pPr.getSpacing().getLine() != null) {
int lineVal = pPr.getSpacing().getLine().intValue();
// Word 中 line 属性值:单倍=240, 1.5倍=360, 双倍=480
switch (lineVal) {
case 240: return "单倍";
case 360: return "1.5 倍";
case 480: return "双倍";
default: return "多倍行距";
}
}
return "";
}
/// 段落格式(间距) 间距值
public static String getParagraphSpacingLines(P paragraph, StyleDefinitionsPart stylePart, WordprocessingMLPackage wordMLPackage, NumberingDefinitionsPart ndp) {
PPr pPr = paragraph.getPPr();
if (pPr != null && pPr.getSpacing() != null) {
return pPr.getSpacing().getLine().toString();
}
// 2⃣ 从段落样式继承
if (pPr != null && pPr.getPStyle() != null && stylePart != null) {
String styleId = pPr.getPStyle().getVal();
if (styleId != null) {
Style style = stylePart.getStyleById(styleId);
if (style != null && style.getPPr() != null && style.getPPr().getSpacing() != null) {
PPrBase.Spacing spacing = style.getPPr().getSpacing();
return spacing.getLine().toString();
if (style != null && style.getPPr() != null && style.getPPr().getSpacing() != null
&& style.getPPr().getSpacing().getLine() != null) {
int lineVal = style.getPPr().getSpacing().getLine().intValue();
switch (lineVal) {
case 240: return "单倍";
case 360: return "1.5 倍";
case 480: return "双倍";
default: return "多倍行距";
}
}
return "";
}
}
// 3⃣ 根据标题样式 Word 默认行距
if (pPr != null && pPr.getPStyle() != null) {
String styleId = pPr.getPStyle().getVal();
if (styleId != null ) {
switch (styleId) {
case "1":
case "2":
case "3":
case "4":
case "5":
case "6":
case "7":
case "8":
case "9":
return "1.5 倍";
default:
return "单倍";
}
}
}
// 4⃣ 没有信息返回默认
return "";
}
// 转换行距数值为磅数
// 段落行距
public static String getParagraphSpacingLines(P paragraph, StyleDefinitionsPart stylePart,
WordprocessingMLPackage wordMLPackage, NumberingDefinitionsPart ndp) {
if (paragraph == null) return "";
PPr pPr = paragraph.getPPr();
// 1⃣ 段落自身行距
if (pPr != null && pPr.getSpacing() != null && pPr.getSpacing().getLine() != null) {
int lineVal = pPr.getSpacing().getLine().intValue();
String lineRule = (pPr.getSpacing().getLineRule() != null) ? pPr.getSpacing().getLineRule().toString() : "auto";
return convertLineValueToReadable(lineVal, lineRule);
}
// 2⃣ 从段落样式继承
if (pPr != null && pPr.getPStyle() != null && stylePart != null) {
String styleId = pPr.getPStyle().getVal();
if (styleId != null) {
Style style = stylePart.getStyleById(styleId);
if (style != null && style.getPPr() != null && style.getPPr().getSpacing() != null
&& style.getPPr().getSpacing().getLine() != null) {
int lineVal = style.getPPr().getSpacing().getLine().intValue();
String lineRule = (style.getPPr().getSpacing().getLineRule() != null) ?
style.getPPr().getSpacing().getLineRule().toString() : "auto";
return convertLineValueToReadable(lineVal, lineRule);
}
}
}
// 3⃣ 根据标题样式 Word 默认行距(返回磅数)
if (pPr != null && pPr.getPStyle() != null) {
String styleId = pPr.getPStyle().getVal();
if (styleId != null ) {
switch (styleId) {
case "1":
case "2":
case "3":
case "4":
case "5":
case "6":
case "7":
case "8":
case "9":
return convertLineValueToReadable(360, "auto"); // 默认单倍
default:
return convertLineValueToReadable(240, "auto"); // 默认单倍
}
}
}
// 4⃣ 没有信息返回默认
return "";
}
// 转换行距数值为磅数
private static String convertLineValueToReadable(int lineTwips, String lineRule) {
// twips -> point
double points = lineTwips / 20.0; // 1 pt = 20 twips
switch (lineRule) {
case "auto":
case "exact":
case "atLeast":
return String.format("%.1f 磅", points); // 返回磅数,保留一位小数
default:
return String.format("%.1f 磅", points);
}
}
/// 段落 编号列表 存在
public static String getParagraphListIsTrue(P paragraph, StyleDefinitionsPart stylePart, WordprocessingMLPackage wordMLPackage, NumberingDefinitionsPart ndp) {
@@ -254,9 +377,9 @@ public class Paragraphs {
if (pPr != null && pPr.getNumPr() != null && pPr.getNumPr().getNumId() != null) {
PPrBase.NumPr numPr = pPr.getNumPr();
BigInteger ilvl = numPr.getIlvl() != null ? numPr.getIlvl().getVal() : null;
return (ilvl != null ? String.valueOf(ilvl.intValue()) : "未知");
return (ilvl != null ? String.valueOf(ilvl.intValue()) : "");
} else {
return "未知";
return "";
}
}
/// 段落 编号列表 编号样式
@@ -287,7 +410,7 @@ public class Paragraphs {
}
}
}
return "未知";
return "";
}
/// 段落 编号列表 编号格式
public static String getParagraphListLvlText(P paragraph, StyleDefinitionsPart stylePart, WordprocessingMLPackage wordMLPackage, NumberingDefinitionsPart ndp) {
@@ -317,7 +440,7 @@ public class Paragraphs {
}
}
}
return "未知";
return "";
}
/// 段落 编号列表 项目符号
public static String getParagraphListLvlFuHao(P paragraph, StyleDefinitionsPart stylePart, WordprocessingMLPackage wordMLPackage, NumberingDefinitionsPart ndp) {
@@ -346,7 +469,7 @@ public class Paragraphs {
}
}
}
return "未知";
return "";
}
/// 段落 编号列表 列表类型
public static String getParagraphListLvlType(P paragraph, StyleDefinitionsPart stylePart, WordprocessingMLPackage wordMLPackage, NumberingDefinitionsPart ndp) {
@@ -379,7 +502,7 @@ public class Paragraphs {
}
}
}
return "未知";
return "";
}
// 段落边框 样式
@@ -405,7 +528,7 @@ public class Paragraphs {
return top.getVal().value() + "-" + bottom.getVal().value() + "-" + left.getVal().value() + "-" + right.getVal().value();
}
}
return "未知";
return "";
}
// 段落边框 - 颜色
@@ -425,13 +548,13 @@ public class Paragraphs {
// 判断上下左右边框是否一致
if (top.getColor().equals(bottom.getColor()) && top.getColor().equals(left.getColor()) && top.getColor().equals(right.getColor())) {
// 说明样式一样
return top.getColor();
return ColorUtils.getChineseColorName(top.getColor());
} else {
// 说明样式不一样
return top.getColor() + "-" + bottom.getColor() + "-" + left.getColor() + "-" + right.getColor();
}
}
return "未知";
return "";
}
// 段落边框 - 宽度
@@ -457,7 +580,7 @@ public class Paragraphs {
return top.getSz().toString() + "-" + bottom.getSz().toString() + "-" + left.getSz().toString() + "-" + right.getSz().toString();
}
}
return "未知";
return "";
}
// 段落底纹 - 填充颜色
@@ -468,7 +591,7 @@ public class Paragraphs {
CTShd shd = pPr.getShd();
return shd.getFill();
}
return "未知";
return "";
}
// 段落底纹 - 图案样式
@@ -479,7 +602,7 @@ public class Paragraphs {
CTShd shd = pPr.getShd();
return shd.getVal().value();
}
return "未知";
return "";
}
// 段落底纹 - 图案颜色
@@ -490,7 +613,7 @@ public class Paragraphs {
CTShd shd = pPr.getShd();
return shd.getColor();
}
return "未知";
return "";
}
// 首字下沉 - 是否存在
@@ -513,7 +636,7 @@ public class Paragraphs {
return framePr.getDropCap().value(); // drop | none | margin
}
}
return "未知";
return "";
}
// 首字下沉 - 行数
@@ -525,21 +648,24 @@ public class Paragraphs {
return String.valueOf(framePr.getLines().intValue()); // twips
}
}
return "未知";
return "";
}
// 首字下沉 - 距正文
// 段落首字下沉水平间距(转换为磅)
public static String getParagraphDropCapHSpace(P paragraph, StyleDefinitionsPart stylePart, WordprocessingMLPackage wordMLPackage, NumberingDefinitionsPart ndp) {
PPr pPr = paragraph.getPPr();
if (pPr != null && pPr.getFramePr() != null) {
CTFramePr framePr = pPr.getFramePr();
if (framePr.getHSpace() != null) {
return String.valueOf(framePr.getHSpace().intValue()); // twips
double points = framePr.getHSpace().intValue() / 20.0; // twips -> pt
return String.format("%.1f磅", points);
}
}
return "未知";
return "";
}
// 首字下沉 - 字体
public static String getParagraphDropCapFont(P paragraph, StyleDefinitionsPart stylePart, WordprocessingMLPackage wordMLPackage, NumberingDefinitionsPart ndp) {
PPr pPr = paragraph.getPPr();
@@ -550,7 +676,7 @@ public class Paragraphs {
return fontName;
}
}
return "未知";
return "";
}
// 分栏 - 栏数
@@ -574,7 +700,7 @@ public class Paragraphs {
// return String.valueOf(cols.getNum().intValue());
// }
//
// return "未知";
// return "";
// }
public static String getParagraphCols(P paragraph, StyleDefinitionsPart stylePart, WordprocessingMLPackage wordMLPackage, NumberingDefinitionsPart ndp) {
@@ -664,7 +790,7 @@ public class Paragraphs {
CTColumns cols = sectPr.getCols();
return cols.isSep() ? "" : "";
}
return "未知";
return "";
}
// 分栏 - 各栏间距
@@ -697,7 +823,7 @@ public class Paragraphs {
return value;
}
}
return "未知";
return "";
}
// 分栏 - 各栏宽度
public static String getParagraphColW(P paragraph, StyleDefinitionsPart stylePart, WordprocessingMLPackage wordMLPackage, NumberingDefinitionsPart ndp) {
@@ -729,7 +855,7 @@ public class Paragraphs {
return value;
}
}
return "未知";
return "";
}
// 分栏 - 栏宽相等
@@ -752,7 +878,7 @@ public class Paragraphs {
CTColumns cols = sectPr.getCols();
return cols.isEqualWidth() ? "" : "";
}
return "未知";
return "";
}
// 中文版式 - 双行合一
@@ -768,4 +894,6 @@ public class Paragraphs {
return "";
}
//
}

View File

@@ -3,63 +3,162 @@ package pc.exam.pp.module.judgement.utils.wps_word.docx4j.paragraph;
import org.docx4j.XmlUtils;
import org.docx4j.openpackaging.parts.WordprocessingML.StyleDefinitionsPart;
import org.docx4j.wml.*;
import pc.exam.pp.module.judgement.utils.wps_word.utils.ColorUtils;
import java.math.BigInteger;
import java.util.List;
public class RunText {
// 句子-字号
public static String getParagraphAlignment(R run, String text) {
if (run == null) {
return null ;
}
// 句子-字号(返回第一个有效值)
public static String getParagraphAlignment(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
if (runs == null || runs.isEmpty()) return "";
// 1⃣ 优先检查 Run 本身
for (R run : runs) {
if (run == null) continue;
RPr rPr = run.getRPr();
String eastAsiaFont = null, asciiFont = null, hAnsiFont = null;
String fontSize = null;
if (rPr != null) {
// 字体
if (rPr.getRFonts() != null) {
RFonts fonts = rPr.getRFonts();
eastAsiaFont = fonts.getEastAsia();
asciiFont = fonts.getAscii();
hAnsiFont = fonts.getHAnsi();
// 直接定义的字号
if (rPr.getSz() != null && rPr.getSz().getVal() != null) {
return (rPr.getSz().getVal().intValue() / 2.0) + " pt";
}
// 有时字号在 szCs
if (rPr.getSzCs() != null && rPr.getSzCs().getVal() != null) {
return (rPr.getSzCs().getVal().intValue() / 2.0) + " pt";
}
// 字号单位是半磅20 = 10.0pt
if (rPr.getSz() != null) {
BigInteger sz = rPr.getSz().getVal();
fontSize = sz != null ? (sz.intValue() / 2.0) + " pt" : null;
}
}
System.out.println("文本内容: " + text);
System.out.println("中文字体: " + (eastAsiaFont != null ? eastAsiaFont : "未设置"));
System.out.println("西文字体(ASCII): " + (asciiFont != null ? asciiFont : "未设置"));
System.out.println("西文字体(HAnsi): " + (hAnsiFont != null ? hAnsiFont : "未设置"));
System.out.println("字号: " + (fontSize != null ? fontSize : "未设置"));
System.out.println("--------");
return fontSize != null ? fontSize : "未设置";
// 2⃣ 段落级别字号(直接在 <w:pPr><w:rPr> 里)
if (paragraph != null && paragraph.getPPr() != null && paragraph.getPPr().getRPr() != null) {
ParaRPr pRPr = paragraph.getPPr().getRPr();
if (pRPr.getSz() != null && pRPr.getSz().getVal() != null) {
return (pRPr.getSz().getVal().intValue() / 2.0) + " pt";
}
// 字体-字形 ( 加粗 + 倾斜)
public static String getParagraphEastAsiaFontAlignment(R run, String text) {
if (run == null) {
return null ;
if (pRPr.getSzCs() != null && pRPr.getSzCs().getVal() != null) {
return (pRPr.getSzCs().getVal().intValue() / 2.0) + " pt";
}
}
// 3⃣ 从样式表中继承(标题、正文等)
if (paragraph != null && stylePart != null && paragraph.getPPr() != null && paragraph.getPPr().getPStyle() != null) {
String styleId = paragraph.getPPr().getPStyle().getVal();
try {
Style style = stylePart.getStyleById(styleId);
if (style != null && style.getRPr() != null) {
RPr styleRPr = style.getRPr();
if (styleRPr.getSz() != null && styleRPr.getSz().getVal() != null) {
return (styleRPr.getSz().getVal().intValue() / 2.0) + " pt";
}
if (styleRPr.getSzCs() != null && styleRPr.getSzCs().getVal() != null) {
return (styleRPr.getSzCs().getVal().intValue() / 2.0) + " pt";
}
}
// 🔹 如果是标题样式Heading1, Heading2...),可设置默认字号
if (styleId.toLowerCase().startsWith("heading")) {
switch (styleId.toLowerCase()) {
case "heading1": return "24 pt"; // 默认大标题
case "heading2": return "18 pt";
case "heading3": return "14 pt";
default: return "12 pt"; // 兜底
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
// 4⃣ 全部没有 → 返回默认
return "";
}
// 字体 - 中文字体(返回第一个有效值)
public static String getParagraphEastAsiaFont(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
if (runs == null || runs.isEmpty()) return "";
// 1⃣ Run 级别字体
for (R run : runs) {
if (run == null) continue;
RPr rPr = run.getRPr();
String eastAsiaFont = null, asciiFont = null, hAnsiFont = null;
String fontSize = null;
if (rPr != null && rPr.getRFonts() != null && rPr.getRFonts().getEastAsia() != null) {
return rPr.getRFonts().getEastAsia();
}
}
if (rPr != null) {
// 字体
if (rPr.getRFonts() != null) {
RFonts fonts = rPr.getRFonts();
eastAsiaFont = fonts.getEastAsia();
asciiFont = fonts.getAscii();
hAnsiFont = fonts.getHAnsi();
// 2⃣ 段落级别字体
if (paragraph != null && paragraph.getPPr() != null && paragraph.getPPr().getRPr() != null) {
ParaRPr pRPr = paragraph.getPPr().getRPr();
if (pRPr.getRFonts() != null && pRPr.getRFonts().getEastAsia() != null) {
return pRPr.getRFonts().getEastAsia();
}
}
return eastAsiaFont != null ? eastAsiaFont : "未设置";
// 3⃣ 样式表字体(例如标题、正文)
if (paragraph != null && stylePart != null && paragraph.getPPr() != null && paragraph.getPPr().getPStyle() != null) {
String styleId = paragraph.getPPr().getPStyle().getVal();
try {
Style style = stylePart.getStyleById(styleId);
if (style != null && style.getRPr() != null && style.getRPr().getRFonts() != null
&& style.getRPr().getRFonts().getEastAsia() != null) {
return style.getRPr().getRFonts().getEastAsia();
}
} catch (Exception e) {
e.printStackTrace();
}
}
// 4⃣ 全部没有 → 返回默认
return "";
}
// 字体 - 英文字体
public static String getParagraphAsciiFont(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
if (runs == null || runs.isEmpty()) return "";
// 1⃣ Run 级别字体
for (R run : runs) {
if (run == null) continue;
RPr rPr = run.getRPr();
if (rPr != null && rPr.getRFonts() != null && rPr.getRFonts().getAscii() != null) {
return rPr.getRFonts().getAscii();
}
}
// 2⃣ 段落级别字体
if (paragraph != null && paragraph.getPPr() != null && paragraph.getPPr().getRPr() != null) {
ParaRPr pRPr = paragraph.getPPr().getRPr();
if (pRPr.getRFonts() != null && pRPr.getRFonts().getAscii() != null) {
return pRPr.getRFonts().getAscii();
}
}
// 3⃣ 样式表字体例如标题、正文、Normal
if (paragraph != null && stylePart != null && paragraph.getPPr() != null && paragraph.getPPr().getPStyle() != null) {
String styleId = paragraph.getPPr().getPStyle().getVal();
try {
Style style = stylePart.getStyleById(styleId);
if (style != null && style.getRPr() != null && style.getRPr().getRFonts() != null
&& style.getRPr().getRFonts().getAscii() != null) {
return style.getRPr().getRFonts().getAscii();
}
} catch (Exception e) {
e.printStackTrace();
}
}
// 4⃣ 全部没有 → 返回默认
return "";
}
// 字体-字形 ( 加粗 + 倾斜)
public static void getParagraphFontStyle(R run, String text) {
RPr rPr = run.getRPr();
@@ -83,80 +182,31 @@ public class RunText {
}
System.out.println("--------");
}
// 字体-字形 ( 加粗 + 倾斜)
public static String getParagraphFontStyleIsBoldAndIsItalic(R run, String text) {
RPr rPr = run.getRPr();
boolean isBold = false;
boolean isItalic = false;
if (rPr != null) {
isBold = rPr.getB() != null && rPr.getB().isVal();
isItalic = rPr.getI() != null && rPr.getI().isVal();
// 字体-字形 (加粗 + 倾斜)
public static String getParagraphFontStyleIsBoldAndIsItalic(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
boolean isBold = isBold(runs, paragraph, stylePart);
boolean isItalic = isItalic(runs, paragraph, stylePart);
return (isBold && isItalic) ? "" : "";
}
System.out.println("文本: " + text);
if (isBold && isItalic) {
return "";
}else {
return "";
}
}
// 字体-字形 (加粗)
public static String getParagraphFontStyleIsBold(R run, String text) {
RPr rPr = run.getRPr();
boolean isBold = false;
boolean isItalic = false;
if (rPr != null) {
isBold = rPr.getB() != null && rPr.getB().isVal();
isItalic = rPr.getI() != null && rPr.getI().isVal();
public static String getParagraphFontStyleIsBold(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
return isBold(runs, paragraph, stylePart) ? "" : "";
}
System.out.println("文本: " + text + " 是否加粗:" + isBold + " 是否斜体:" + isItalic);
if (isBold) {
return "";
}else {
return "";
}
}
// 字体-字形 (倾斜)
public static String getParagraphFontStyleIsItalic(R run, String text) {
RPr rPr = run.getRPr();
boolean isBold = false;
boolean isItalic = false;
if (rPr != null) {
isBold = rPr.getB() != null && rPr.getB().isVal();
isItalic = rPr.getI() != null && rPr.getI().isVal();
public static String getParagraphFontStyleIsItalic(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
return isItalic(runs, paragraph, stylePart) ? "" : "";
}
System.out.println("文本: " + text);
if (isItalic) {
return "";
}else {
return "";
}
}
// 字体-字形 (常规)
public static String getParagraphFontStyleIsNomral(R run, String text) {
RPr rPr = run.getRPr();
boolean isBold = false;
boolean isItalic = false;
if (rPr != null) {
isBold = rPr.getB() != null && rPr.getB().isVal();
isItalic = rPr.getI() != null && rPr.getI().isVal();
public static String getParagraphFontStyleIsNormal(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
boolean isBold = isBold(runs, paragraph, stylePart);
boolean isItalic = isItalic(runs, paragraph, stylePart);
return (!isBold && !isItalic) ? "" : "";
}
System.out.println("文本: " + text);
if (isBold || isItalic) {
return "";
}else {
return "";
}
}
// 字体-所有文字
// public static void getParagraphFontColor(R run, StyleDefinitionsPart stylePart, String text) {
@@ -188,55 +238,104 @@ public class RunText {
// System.out.println("--------");
// }
public static String getParagraphFontColor(R run, String text) {
// 字体颜色
public static String getParagraphFontColor(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
if (runs == null || runs.isEmpty()) return "默认";
for (R run : runs) {
if (run == null) continue;
RPr rPr = run.getRPr();
String color = "默认";
if (rPr != null) {
if (rPr.getColor() != null && rPr.getColor().getVal() != null) {
color = rPr.getColor().getVal(); // 如 "FF0000"
if (rPr != null && rPr.getColor() != null && rPr.getColor().getVal() != null) {
return ColorUtils.getChineseColorName(rPr.getColor().getVal());
}
}
System.out.println("文本: " + text);
System.out.println("字体颜色: " + color);
System.out.println("--------");
return color;
}
public static String getParagraphFontUnderlineVal(R run, String text) {
// 如果 run 里没有,检查段落样式继承
if (paragraph != null && stylePart != null) {
PPr pPr = paragraph.getPPr();
if (pPr != null && pPr.getPStyle() != null) {
String styleId = pPr.getPStyle().getVal();
try {
Style style = stylePart.getStyleById(styleId);
if (style != null && style.getRPr() != null && style.getRPr().getColor() != null) {
return ColorUtils.getChineseColorName(style.getRPr().getColor().getVal());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
return "默认";
}
// 下划线类型
public static String getParagraphFontUnderlineVal(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
if (runs == null || runs.isEmpty()) return null;
for (R run : runs) {
if (run == null) continue;
RPr rPr = run.getRPr();
String underlineVal = null;
if (rPr != null) {
if (rPr.getU() != null) {
if (rPr.getU().getVal() != null) {
underlineVal = rPr.getU().getVal().value(); // single, double, none 等
}
if (rPr != null && rPr.getU() != null && rPr.getU().getVal() != null) {
return rPr.getU().getVal().value(); // single, double, none 等
}
}
return underlineVal;
// 样式继承
if (paragraph != null && stylePart != null) {
PPr pPr = paragraph.getPPr();
if (pPr != null && pPr.getPStyle() != null) {
String styleId = pPr.getPStyle().getVal();
try {
Style style = stylePart.getStyleById(styleId);
if (style != null && style.getRPr() != null && style.getRPr().getU() != null) {
return style.getRPr().getU().getVal().value();
}
public static String getParagraphFontUnderlineColor(R run, String text) {
} catch (Exception e) {
e.printStackTrace();
}
}
}
return null;
}
// 下划线颜色
public static String getParagraphFontUnderlineColor(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
if (runs == null || runs.isEmpty()) return null;
for (R run : runs) {
if (run == null) continue;
RPr rPr = run.getRPr();
if (rPr != null && rPr.getU() != null && rPr.getU().getColor() != null) {
return ColorUtils.getChineseColorName(rPr.getU().getColor());
}
}
String underlineColor = null;
if (rPr != null) {
if (rPr.getU() != null) {
if (rPr.getU().getColor() != null) {
underlineColor = rPr.getU().getColor(); // 例如 "0000FF"
// 样式继承
if (paragraph != null && stylePart != null) {
PPr pPr = paragraph.getPPr();
if (pPr != null && pPr.getPStyle() != null) {
String styleId = pPr.getPStyle().getVal();
try {
Style style = stylePart.getStyleById(styleId);
if (style != null && style.getRPr() != null && style.getRPr().getU() != null
&& style.getRPr().getU().getColor() != null) {
return ColorUtils.getChineseColorName(style.getRPr().getU().getColor());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
return underlineColor;
return null;
}
// 字体-效果-删除线
public static void getParagraphStrike(R run, String text) {
public static void getParagraphStrike(R run, String text, P paragraph, StyleDefinitionsPart stylePart) {
RPr rPr = run.getRPr();
boolean isStrike = false;
@@ -296,80 +395,133 @@ public class RunText {
// System.out.println("--------");
// }
//缩放比例
public static String getParagraphFontSpacingScale(R run, String text) {
// 缩放比例
public static String getParagraphFontSpacingScale(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
// 1. run 级别
if (runs != null) {
for (R run : runs) {
if (run == null) continue;
RPr rPr = run.getRPr();
String scale = "100%";
if (rPr != null) {
if (rPr.getW() != null && rPr.getW().getVal() != null) {
scale = rPr.getW().getVal().toString() + "%";
if (rPr != null && rPr.getW() != null && rPr.getW().getVal() != null) {
return rPr.getW().getVal().toString() + "%";
}
}
System.out.println("缩放比例: " + scale);
return scale;
}
//字符间距
public static String getParagraphFontSpacing(R run, String text) {
// 2. style 级别
if (stylePart != null && paragraph.getPPr() != null && paragraph.getPPr().getPStyle() != null) {
String styleId = paragraph.getPPr().getPStyle().getVal();
Style style = stylePart.getStyleById(styleId);
if (style != null && style.getRPr() != null && style.getRPr().getW() != null) {
return style.getRPr().getW().getVal().toString() + "%";
}
}
// 3. 默认值
return "100%";
}
// 字符间距(转换为磅)
public static String getParagraphFontSpacing(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
if (runs != null) {
for (R run : runs) {
if (run == null) continue;
RPr rPr = run.getRPr();
String spacing = null;
if (rPr != null) {
if (rPr.getSpacing() != null && rPr.getSpacing().getVal() != null) {
spacing = rPr.getSpacing().getVal().toString() + " twips";
if (rPr != null && rPr.getSpacing() != null && rPr.getSpacing().getVal() != null) {
int twips = rPr.getSpacing().getVal().intValue();
double pt = twips / 20.0; // 1/20 pt
return pt + " ";
}
}
System.out.println("字符间距: " + spacing);
return spacing;
}
//字符位置
public static String getParagraphFontPosition(R run, String text) {
if (stylePart != null && paragraph.getPPr() != null && paragraph.getPPr().getPStyle() != null) {
String styleId = paragraph.getPPr().getPStyle().getVal();
Style style = stylePart.getStyleById(styleId);
if (style != null && style.getRPr() != null && style.getRPr().getSpacing() != null) {
int twips = style.getRPr().getSpacing().getVal().intValue();
double pt = twips / 20.0;
return pt + "";
}
}
return null; // 默认无间距
}
// 字符位置(上标下标,转换为磅)
public static String getParagraphFontPosition(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
if (runs != null) {
for (R run : runs) {
if (run == null) continue;
RPr rPr = run.getRPr();
String position = null;
if (rPr != null) {
if (rPr.getPosition() != null && rPr.getPosition().getVal() != null) {
position = rPr.getPosition().getVal().toString() + " pt(1/2)";
if (rPr != null && rPr.getPosition() != null && rPr.getPosition().getVal() != null) {
int halfPts = rPr.getPosition().getVal().intValue();
double pt = halfPts / 2.0; // 1/2 pt
return pt + "";
}
}
}
System.out.println("字符位置: " + position);
return position;
if (stylePart != null && paragraph.getPPr() != null && paragraph.getPPr().getPStyle() != null) {
String styleId = paragraph.getPPr().getPStyle().getVal();
Style style = stylePart.getStyleById(styleId);
if (style != null && style.getRPr() != null && style.getRPr().getPosition() != null) {
int halfPts = style.getRPr().getPosition().getVal().intValue();
double pt = halfPts / 2.0;
return pt + "";
}
//最小间距
public static String getParagraphFontKern(R run, String text) {
}
return null; // 默认正常位置
}
// 最小间距 (Kern) 转换为磅
public static String getParagraphFontKern(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
if (runs != null) {
for (R run : runs) {
if (run == null) continue;
RPr rPr = run.getRPr();
String kern = null;
if (rPr != null) {
if (rPr.getKern() != null && rPr.getKern().getVal() != null) {
kern = rPr.getKern().getVal().toString() + " (1/100 pt)";
if (rPr != null && rPr.getKern() != null && rPr.getKern().getVal() != null) {
int kernVal = rPr.getKern().getVal().intValue(); // 1/100 pt
double pt = kernVal / 100.0;
return pt + "";
}
}
}
if (stylePart != null && paragraph.getPPr() != null && paragraph.getPPr().getPStyle() != null) {
String styleId = paragraph.getPPr().getPStyle().getVal();
Style style = stylePart.getStyleById(styleId);
if (style != null && style.getRPr() != null && style.getRPr().getKern() != null) {
int kernVal = style.getRPr().getKern().getVal().intValue();
double pt = kernVal / 100.0;
return pt + "";
}
}
return null; // 默认无字距调整
}
System.out.println("最小间距 (Kern): " + kern);
return kern;
}
//对齐到网格
public static String getParagraphFontSnapToGrid(R run, String text) {
// 对齐到网格
public static String getParagraphFontSnapToGrid(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
if (runs != null) {
for (R run : runs) {
if (run == null) continue;
RPr rPr = run.getRPr();
String snapToGrid = "";
if (rPr != null) {
if (rPr.getSnapToGrid() != null) {
snapToGrid = rPr.getSnapToGrid().isVal() ? "" : "";
if (rPr != null && rPr.getSnapToGrid() != null) {
return rPr.getSnapToGrid().isVal() ? "" : "";
}
}
}
System.out.println("对齐到网格: " + snapToGrid);
return snapToGrid;
if (stylePart != null && paragraph.getPPr() != null && paragraph.getPPr().getPStyle() != null) {
String styleId = paragraph.getPPr().getPStyle().getVal();
Style style = stylePart.getStyleById(styleId);
if (style != null && style.getRPr() != null && style.getRPr().getSnapToGrid() != null) {
return style.getRPr().getSnapToGrid().isVal() ? "" : "";
}
}
return ""; // 默认不对齐
}
// 字体-文本效果
public static void getParagraphTextEffect(R run, String text) {
@@ -387,35 +539,319 @@ public class RunText {
System.out.println("--------");
}
//文本填充
public static String getParagraphTextFillEffect(R run, String text) {
// 转换为 XML 文本
// 文本填充效果
public static String getParagraphTextFillEffect(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
if (runs == null || runs.isEmpty()) return "";
for (R run : runs) {
if (run == null) continue;
String runXml = XmlUtils.marshaltoString(run, true);
return runXml.contains("w14:textFill") ? "" : "";
if (runXml.contains("w14:textFill")) return "";
}
return "";
}
}
//文本轮廓
public static String getParagraphTextOutline(R run, String text) {
// 转换为 XML 文本
// 文本轮廓
public static String getParagraphTextOutline(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
if (runs == null || runs.isEmpty()) return "";
for (R run : runs) {
if (run == null) continue;
String runXml = XmlUtils.marshaltoString(run, true);
return runXml.contains("w14:textOutline") ? "" : "";
if (runXml.contains("w14:textOutline")) return "";
}
//阴影
public static String getParagraphTextShadow(R run, String text) {
// 转换为 XML 文本
return "";
}
// 阴影
public static String getParagraphTextShadow(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
if (runs == null || runs.isEmpty()) return "";
for (R run : runs) {
if (run == null) continue;
String runXml = XmlUtils.marshaltoString(run, true);
return runXml.contains("w14:shadow") ? "" : "";
if (runXml.contains("w14:shadow")) return "";
}
//倒影
public static String getParagraphTextReflection(R run, String text) {
// 转换为 XML 文本
return "";
}
// 倒影
public static String getParagraphTextReflection(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
if (runs == null || runs.isEmpty()) return "";
for (R run : runs) {
if (run == null) continue;
String runXml = XmlUtils.marshaltoString(run, true);
return runXml.contains("w14:reflection") ? "" : "";
if (runXml.contains("w14:reflection")) return "";
}
//发光
public static String getParagraphTextGlow(R run, String text) {
// 转换为 XML 文本
return "";
}
// 发光
public static String getParagraphTextGlow(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
if (runs == null || runs.isEmpty()) return "";
for (R run : runs) {
if (run == null) continue;
String runXml = XmlUtils.marshaltoString(run, true);
return runXml.contains("w14:glow") ? "" : "";
if (runXml.contains("w14:glow")) return "";
}
return "";
}
// =====句子边框的样式=====
public static String getParagraphTextStyle(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
if (runs == null || runs.isEmpty()) return "";
for (R run : runs) {
if (run == null) continue;
String runXml = XmlUtils.marshaltoString(run, true);
int idx = runXml.indexOf("<w:bdr");
if (idx >= 0) {
int valStart = runXml.indexOf("w:val=\"", idx) + 7;
int valEnd = runXml.indexOf("\"", valStart);
if (valStart > 7 && valEnd > valStart) {
return runXml.substring(valStart, valEnd);
}
}
}
return ""; // 默认无边框
}
// =====句子边框的颜色=====
public static String getParagraphTextColor(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
if (runs == null || runs.isEmpty()) return "";
for (R run : runs) {
if (run == null) continue;
String runXml = XmlUtils.marshaltoString(run, true);
int idx = runXml.indexOf("<w:bdr");
if (idx >= 0) {
// 先取 w:color
int colorStart = runXml.indexOf("w:color=\"", idx);
if (colorStart >= 0) {
colorStart += 9;
int colorEnd = runXml.indexOf("\"", colorStart);
if (colorEnd > colorStart) {
String substring = runXml.substring(colorStart, colorEnd);
if ("auto".equalsIgnoreCase(substring)) {
return ColorUtils.getChineseColorName("000000");
}
return ColorUtils.getChineseColorName(substring);
}
}
// 如果没有 w:color再取 w:themeColor
int themeStart = runXml.indexOf("w:themeColor=\"", idx);
if (themeStart >= 0) {
themeStart += 14;
int themeEnd = runXml.indexOf("\"", themeStart);
if (themeEnd > themeStart) {
String theme = runXml.substring(themeStart, themeEnd);
if ("AUTO".equalsIgnoreCase(theme)) {
return ColorUtils.getChineseColorName("000000");
}
return ColorUtils.getChineseColorName(theme);
}
}
}
}
return ""; // 默认无边框颜色
}
// =====句子边框的宽度=====
public static String getParagraphTextWidth(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
if (runs == null || runs.isEmpty()) return "默认";
for (R run : runs) {
if (run == null) continue;
String runXml = XmlUtils.marshaltoString(run, true);
int idx = runXml.indexOf("<w:bdr");
if (idx >= 0) {
int sizeStart = runXml.indexOf("w:sz=\"", idx) + 6;
int sizeEnd = runXml.indexOf("\"", sizeStart);
if (sizeStart > 6 && sizeEnd > sizeStart) {
String val = runXml.substring(sizeStart, sizeEnd);
try {
int width = Integer.parseInt(val);
return width + "pt"; // Word XML 单位通常为 1/8 pt
} catch (NumberFormatException e) {
return val;
}
}
}
}
return "默认"; // 默认宽度
}
// =====句子-字体(效果)删除线=====
public static String getStrikeThrough(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
if (runs == null || runs.isEmpty()) return "";
for (R run : runs) {
if (run != null && run.getRPr() != null && run.getRPr().getStrike() != null) {
return "";
}
}
return "";
}
// =====句子-字体(效果)双删除线=====
public static String getDoubleStrikeThrough(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
if (runs == null || runs.isEmpty()) return "";
for (R run : runs) {
if (run != null && run.getRPr() != null && run.getRPr().getDstrike() != null) {
return "";
}
}
return "";
}
// 句子-字体(效果)上标
public static String getSuperScript(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
if (runs == null || runs.isEmpty()) return "";
for (R run : runs) {
if (run != null && run.getRPr() != null && run.getRPr().getVertAlign() != null) {
CTVerticalAlignRun vertAlign = run.getRPr().getVertAlign();
if (vertAlign.getVal() != null && vertAlign.getVal() == STVerticalAlignRun.SUPERSCRIPT) {
return "";
}
}
}
return "";
}
// 句子-字体(效果)下标
public static String getSubScript(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
if (runs == null || runs.isEmpty()) return "";
for (R run : runs) {
if (run != null && run.getRPr() != null && run.getRPr().getVertAlign() != null) {
CTVerticalAlignRun vertAlign = run.getRPr().getVertAlign();
if (vertAlign.getVal() != null && vertAlign.getVal() == STVerticalAlignRun.SUBSCRIPT) {
return "";
}
}
}
return "";
}
// 句子-字体(效果)小型大写字母
public static String getSmallCaps(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
if (runs == null || runs.isEmpty()) return "";
for (R run : runs) {
if (run != null && run.getRPr() != null && run.getRPr().getSmallCaps() != null) {
return "";
}
}
return "";
}
// 句子-字体(效果)全部大写字母
public static String getCaps(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
if (runs == null || runs.isEmpty()) return "";
for (R run : runs) {
if (run != null && run.getRPr() != null && run.getRPr().getCaps() != null) {
return "";
}
}
return "";
}
// 句子底纹-填充颜色
public static String getShadingFillColor(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
if (runs == null || runs.isEmpty()) return "";
for (R run : runs) {
if (run != null && run.getRPr() != null && run.getRPr().getShd() != null) {
CTShd shd = run.getRPr().getShd();
String fill = shd.getFill();
if (fill != null) {
return ColorUtils.getChineseColorName(fill);
}
}
}
return "";
}
// 句子底纹-图案样式
public static String getShadingPattern(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
if (runs == null || runs.isEmpty()) return "";
for (R run : runs) {
if (run != null && run.getRPr() != null && run.getRPr().getShd() != null) {
CTShd shd = run.getRPr().getShd();
STShd pattern = shd.getVal();
if (pattern != null) {
return pattern.toString();
}
}
}
return "";
}
// 句子底纹-图案颜色
public static String getShadingPatternColor(List<R> runs, String text, P paragraph, StyleDefinitionsPart stylePart) {
if (runs == null || runs.isEmpty()) return "";
for (R run : runs) {
if (run != null && run.getRPr() != null && run.getRPr().getShd() != null) {
CTShd shd = run.getRPr().getShd();
String color = shd.getColor();
if (color != null) {
return ColorUtils.getChineseColorName(color);
}
}
}
return "";
}
private static boolean isBold(List<R> runs, P paragraph, StyleDefinitionsPart stylePart) {
// 1⃣ Run 级别
for (R run : runs) {
if (run != null && run.getRPr() != null && run.getRPr().getB() != null && run.getRPr().getB().isVal()) {
return true;
}
}
// 2⃣ 段落级别
if (paragraph != null && paragraph.getPPr() != null && paragraph.getPPr().getRPr() != null) {
ParaRPr pRPr = paragraph.getPPr().getRPr();
if (pRPr.getB() != null && pRPr.getB().isVal()) {
return true;
}
}
// 3⃣ 样式表级别
if (paragraph != null && stylePart != null && paragraph.getPPr() != null && paragraph.getPPr().getPStyle() != null) {
String styleId = paragraph.getPPr().getPStyle().getVal();
try {
Style style = stylePart.getStyleById(styleId);
if (style != null && style.getRPr() != null && style.getRPr().getB() != null && style.getRPr().getB().isVal()) {
return true;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return false;
}
private static boolean isItalic(List<R> runs, P paragraph, StyleDefinitionsPart stylePart) {
// 1⃣ Run 级别
for (R run : runs) {
if (run != null && run.getRPr() != null && run.getRPr().getI() != null && run.getRPr().getI().isVal()) {
return true;
}
}
// 2⃣ 段落级别
if (paragraph != null && paragraph.getPPr() != null && paragraph.getPPr().getRPr() != null) {
ParaRPr pRPr = paragraph.getPPr().getRPr();
if (pRPr.getI() != null && pRPr.getI().isVal()) {
return true;
}
}
// 3⃣ 样式表级别
if (paragraph != null && stylePart != null && paragraph.getPPr() != null && paragraph.getPPr().getPStyle() != null) {
String styleId = paragraph.getPPr().getPStyle().getVal();
try {
Style style = stylePart.getStyleById(styleId);
if (style != null && style.getRPr() != null && style.getRPr().getI() != null && style.getRPr().getI().isVal()) {
return true;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return false;
}
}

View File

@@ -13,4 +13,6 @@ public class HeaderInfo {
public Double fontSizePt;
public String colorHex;
public String alignment;
public String bold;
public String italic;
}

View File

@@ -14,6 +14,7 @@ import org.docx4j.openpackaging.parts.Part;
import org.docx4j.openpackaging.parts.WordprocessingML.*;
import org.docx4j.wml.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHdrFtrRef;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPageBorders;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPageMar;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPageSz;
@@ -56,13 +57,16 @@ public class SectionPage {
SectPr sectPr = pPr.getSectPr();
SectPr.PgMar pgMar = sectPr.getPgMar();
if (pgMar != null) {
System.out.println("上边距 (twips): " + pgMar.getTop());
return pgMar.getTop().toString();
if (pgMar != null && pgMar.getTop() != null) {
long topTwips = pgMar.getTop().longValue(); // twips
double topPt = topTwips / 20.0; // 转换为磅
double topCm = topPt * 0.0352778; // 转换为厘米
return String.format("%.1f磅(%.2f厘米)", topPt, topCm);
}
}
return null;
}
//节页面设置-下边距
public static String getSectionPageSettingsBottom(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
PPr pPr = paragraph.getPPr();
@@ -70,13 +74,16 @@ public class SectionPage {
SectPr sectPr = pPr.getSectPr();
SectPr.PgMar pgMar = sectPr.getPgMar();
if (pgMar != null) {
System.out.println("下边距 (twips): " + pgMar.getBottom());
return pgMar.getBottom().toString();
if (pgMar != null && pgMar.getBottom() != null) {
long bottomTwips = pgMar.getBottom().longValue(); // twips
double bottomPt = bottomTwips / 20.0; // 磅
double bottomCm = bottomPt * 0.0352778; // 厘米
return String.format("%.1f磅(%.2f厘米)", bottomPt, bottomCm);
}
}
return null;
}
//节页面设置-左边距
public static String getSectionPageSettingsLeft(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
PPr pPr = paragraph.getPPr();
@@ -84,13 +91,16 @@ public class SectionPage {
SectPr sectPr = pPr.getSectPr();
SectPr.PgMar pgMar = sectPr.getPgMar();
if (pgMar != null) {
System.out.println("左边距 (twips): " + pgMar.getLeft());
return pgMar.getLeft().toString();
if (pgMar != null && pgMar.getLeft() != null) {
long leftTwips = pgMar.getLeft().longValue(); // twips
double leftPt = leftTwips / 20.0; // 转换为磅
double leftCm = leftPt * 0.0352778; // 转换为厘米
return String.format("%.1f磅(%.2f厘米)", leftPt, leftCm);
}
}
return null;
}
//节页面设置-右边距
public static String getSectionPageSettingsRight(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
PPr pPr = paragraph.getPPr();
@@ -98,13 +108,16 @@ public class SectionPage {
SectPr sectPr = pPr.getSectPr();
SectPr.PgMar pgMar = sectPr.getPgMar();
if (pgMar != null) {
System.out.println("右边距 (twips): " + pgMar.getRight());
return pgMar.getRight().toString();
if (pgMar != null && pgMar.getRight() != null) {
long rightTwips = pgMar.getRight().longValue(); // twips
double rightPt = rightTwips / 20.0; // 转换为磅
double rightCm = rightPt * 0.0352778; // 转换为厘米
return String.format("%.1f磅(%.2f厘米)", rightPt, rightCm);
}
}
return null;
}
//装订线边距
public static String getSectionPageSettingsGutter(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
PPr pPr = paragraph.getPPr();
@@ -112,13 +125,45 @@ public class SectionPage {
SectPr sectPr = pPr.getSectPr();
SectPr.PgMar pgMar = sectPr.getPgMar();
if (pgMar != null) {
System.out.println("上边距 (twips): " + pgMar.getGutter());
return pgMar.getGutter().toString();
if (pgMar != null && pgMar.getGutter() != null) {
long gutterTwips = pgMar.getGutter().longValue(); // twips
double gutterPt = gutterTwips / 20.0; // 转换为磅
double gutterCm = gutterPt * 0.0352778; // 转换为厘米
return String.format("%.1f磅(%.2f厘米)", gutterPt, gutterCm);
}
}
return null;
}
//每页行数
public static String getSectionPageLineNumber(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
if (paragraph == null || paragraph.getPPr() == null) return null;
SectPr sectPr = paragraph.getPPr().getSectPr();
if (sectPr == null) return null;
CTDocGrid docGrid = sectPr.getDocGrid();
if (docGrid == null || docGrid.getLinePitch() == null) return null;
// 每行高度twips
int linePitchTwips = docGrid.getLinePitch().intValue();
// 获取页面可用高度twips
SectPr.PgMar pgMar = sectPr.getPgMar();
int pageHeightTwips = 0;
if (pgMar != null) {
// 页面高度 = 页面总高 - 上下页边距
pageHeightTwips = (sectPr.getPgSz() != null && sectPr.getPgSz().getH() != null
? sectPr.getPgSz().getH().intValue() : 0)
- (pgMar.getTop() != null ? pgMar.getTop().intValue() : 0)
- (pgMar.getBottom() != null ? pgMar.getBottom().intValue() : 0);
}
if (pageHeightTwips <= 0 || linePitchTwips <= 0) return null;
int linesPerPage = pageHeightTwips / linePitchTwips;
return linesPerPage + "行/页";
}
// 节页面设置 - 纸张方向
public static String getSectionPageOrientation(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
@@ -268,6 +313,23 @@ public class SectionPage {
return convertAlignToChinese(align);
}
//加粗
public static String getOddHeaderBold(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
if (hfp.getDefaultHeader() == null) {
return null;
}
String bold = extractHeaderInfo(hfp.getDefaultHeader(),wordMLPackage).bold;
return bold;
}
//倾斜
public static String getOddHeaderItalic(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
if (hfp.getDefaultHeader() == null) {
return null;
}
String italic = extractHeaderInfo(hfp.getDefaultHeader(),wordMLPackage).italic;
return italic;
}
// ----- 偶数页眉 -----
//偶数页眉文本
public static String getEvenHeaderText(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
@@ -296,7 +358,22 @@ public class SectionPage {
String align = hfp.getEvenHeader() != null ? extractHeaderInfo(hfp.getEvenHeader(),wordMLPackage).alignment : null;
return convertAlignToChinese(align);
}
//加粗
public static String getEvenHeaderBold(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
if (hfp.getEvenHeader() == null) {
return null;
}
String bold = extractHeaderInfo(hfp.getEvenHeader(),wordMLPackage).bold;
return bold;
}
//倾斜
public static String getEvenHeaderItalic(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
if (hfp.getEvenHeader() == null) {
return null;
}
String italic = extractHeaderInfo(hfp.getEvenHeader(),wordMLPackage).italic;
return italic;
}
// ----- 首页眉 -----
//首页眉文本
public static String getFirstHeaderText(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
@@ -328,7 +405,22 @@ public class SectionPage {
String align = hfp.getFirstHeader() != null ? extractHeaderInfo(hfp.getFirstHeader(),wordMLPackage).alignment : null;
return convertAlignToChinese(align);
}
//加粗
public static String getFirstHeaderBold(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
if (hfp.getFirstHeader() == null) {
return null;
}
String bold = extractHeaderInfo(hfp.getFirstHeader(),wordMLPackage).bold;
return bold;
}
//倾斜
public static String getFirstHeaderItalic(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
if (hfp.getFirstHeader() == null) {
return null;
}
String italic = extractHeaderInfo(hfp.getFirstHeader(),wordMLPackage).italic;
return italic;
}
// 页脚
@@ -376,6 +468,42 @@ public class SectionPage {
HeaderInfo info = extractFooterInfo(hfp.getDefaultFooter(), wordMLPackage);
return convertAlignToChinese(info.alignment);
}
//颜色
public static String getOddFooterColor(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
if (hfp.getDefaultFooter() == null) return null;
String colorHex = extractFooterInfo(hfp.getDefaultFooter(),wordMLPackage).colorHex;
return pc.exam.pp.module.judgement.utils.wps_word.utils.ColorUtils.getChineseColorName(colorHex);
}
public static String getOddFooterText(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
if (hfp.getDefaultFooter() == null) return null;
String text = extractFooterInfo(hfp.getDefaultFooter(), wordMLPackage).text;
if (text==null){
return null;
}
return text;
}
//加粗
public static String getOddFooterBold(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
if (hfp.getDefaultFooter() == null) {
return null;
}
String bold = extractFooterInfo(hfp.getDefaultFooter(),wordMLPackage).bold;
return bold;
}
//倾斜
public static String getOddFooterItalic(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
if (hfp.getDefaultFooter() == null) {
return null;
}
String italic = extractFooterInfo(hfp.getDefaultFooter(),wordMLPackage).italic;
return italic;
}
// 偶数页
//字体
@@ -397,24 +525,75 @@ public class SectionPage {
HeaderInfo info = extractFooterInfo(hfp.getEvenFooter(), wordMLPackage);
return convertAlignToChinese(info.alignment);
}
public static String getEvenFooterText(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
return hfp.getEvenFooter() != null ? extractFooterInfo(hfp.getEvenFooter(),wordMLPackage).text : null;
}
//颜色
public static String getEvenFooterColor(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
if (hfp.getEvenFooter() == null) return null;
String colorHex = extractFooterInfo(hfp.getEvenFooter(),wordMLPackage).colorHex;
return pc.exam.pp.module.judgement.utils.wps_word.utils.ColorUtils.getChineseColorName(colorHex);
}
//加粗
public static String getEvenFooterBold(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
if (hfp.getEvenFooter() == null) {
return null;
}
String bold = extractFooterInfo(hfp.getEvenFooter(),wordMLPackage).bold;
return bold;
}
//倾斜
public static String getEvenFooterItalic(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
if (hfp.getEvenFooter() == null) {
return null;
}
String italic = extractFooterInfo(hfp.getEvenFooter(),wordMLPackage).italic;
return italic;
}
// ===== 首页页脚 =====
public static String getFirstFooterFont(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
if (hfp.getFirstFooter() == null) return null;
HeaderInfo info = extractFooterInfo(hfp.getFirstFooter(), wordMLPackage);
return info == null ? null : info.font;
}
public static String getFirstFooterFontSize(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
if (hfp.getFirstFooter() == null) return null;
HeaderInfo info = extractFooterInfo(hfp.getFirstFooter(), wordMLPackage);
return info == null ? null : String.valueOf(info.fontSizePt);
}
public static String getFirstFooterAlign(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
if (hfp.getFirstFooter() == null) return null;
HeaderInfo info = extractFooterInfo(hfp.getFirstFooter(), wordMLPackage);
return convertAlignToChinese(info.alignment);
}
public static String getFirstFooterColor(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
if (hfp.getFirstFooter() == null) return null;
String colorHex = extractFooterInfo(hfp.getFirstFooter(),wordMLPackage).colorHex;
return pc.exam.pp.module.judgement.utils.wps_word.utils.ColorUtils.getChineseColorName(colorHex);
}
public static String getFirstFooterText(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
return hfp.getFirstFooter() != null ? extractFooterInfo(hfp.getFirstFooter(),wordMLPackage).text : null;
}
//加粗
public static String getFirstFooterBold(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
if (hfp.getFirstFooter() == null) {
return null;
}
String bold = extractFooterInfo(hfp.getFirstFooter(),wordMLPackage).bold;
return bold;
}
//倾斜
public static String getFirstFooterItalic(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
if (hfp.getFirstFooter() == null) {
return null;
}
String italic = extractFooterInfo(hfp.getFirstFooter(),wordMLPackage).italic;
return italic;
}
private static FooterPart getFooterPartByParagraph(P targetParagraph, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections, boolean isOddPage) {
MainDocumentPart mainPart = wordMLPackage.getMainDocumentPart();
List<Object> allContent = mainPart.getContent();
@@ -479,8 +658,31 @@ public class SectionPage {
}
for (Object o : paragraph.getContent()) {
if (o instanceof R) {
R run = (R) o;
extractTextFromContent(o, textBuilder, info, styleId, wordMLPackage);
}
}
}
info.text = textBuilder.toString();
return info;
}
/**
* 递归解析内容,包括文本框里的段落
*/
private static void extractTextFromContent(Object o, StringBuilder builder,
HeaderInfo info, String styleId,
WordprocessingMLPackage wordMLPackage) {
Object unwrapped = XmlUtils.unwrap(o);
if (unwrapped instanceof P) {
P p = (P) unwrapped;
for (Object child : p.getContent()) {
extractTextFromContent(child, builder, info, styleId, wordMLPackage);
}
} else if (unwrapped instanceof R) {
R run = (R) unwrapped;
RPr rPr = run.getRPr();
if (rPr != null) {
if (info.font == null) {
@@ -493,23 +695,32 @@ public class SectionPage {
info.colorHex = rPr.getColor().getVal();
}
}
// 文字内容
for (Object rContent : run.getContent()) {
Object val = (rContent instanceof JAXBElement) ? ((JAXBElement<?>) rContent).getValue() : rContent;
if (val instanceof Text) {
textBuilder.append(((Text) val).getValue());
extractTextFromContent(val, builder, info, styleId, wordMLPackage);
}
} else if (unwrapped instanceof Text) {
builder.append(((Text) unwrapped).getValue());
} else if (unwrapped instanceof org.docx4j.dml.wordprocessingDrawing.Inline
|| unwrapped instanceof org.docx4j.dml.wordprocessingDrawing.Anchor) {
// drawing 对象,里面可能有文本框 <w:txbxContent>
try {
String xml = XmlUtils.marshaltoString(unwrapped, true, true);
if (xml.contains("txbxContent")) {
// 提取文本框内部内容
List<Object> innerPs = (List<Object>) XmlUtils.unwrap(((Inline) unwrapped)
.getGraphic().getGraphicData().getAny());
for (Object inner : innerPs) {
extractTextFromContent(inner, builder, info, styleId, wordMLPackage);
}
}
} catch (Exception e) {
e.printStackTrace();
}
} else if (unwrapped instanceof JAXBElement) {
extractTextFromContent(((JAXBElement<?>) unwrapped).getValue(), builder, info, styleId, wordMLPackage);
}
}
}
}
info.text = textBuilder.toString();
return info;
}
// 修改你的 getFooterInfo改为递归遍历拿到所有段落的格式
@@ -643,39 +854,42 @@ public class SectionPage {
// 页脚(元素) 包含页码 返回 是/否
public static String getHeaderContainsPageNumber(
P paragraph,
HeaderFooterPolicy hfp,
WordprocessingMLPackage wordMLPackage,
List<SectionWrapper> sections) {
if (sections == null || sections.isEmpty()) {
return null;
}
if (hfp == null) return "";
for (SectionWrapper section : sections) {
SectPr sectPr = section.getSectPr();
if (sectPr == null) continue;
// 获取页脚对象列表
FooterPart[] footerParts = new FooterPart[]{
hfp.getFirstFooter(),
hfp.getEvenFooter(),
hfp.getDefaultFooter()
};
if (sectPr.getPgNumType() != null) {
// 这里可以进一步获取格式,比如:
if (sectPr.getPgNumType().getFmt()!=null){
System.out.println("检测到页码格式: " + String.valueOf(sectPr.getPgNumType().getFmt()));
for (FooterPart fp : footerParts) {
if (fp == null) continue;
String xml = XmlUtils.marshaltoString(fp.getJaxbElement(), true, true);
System.out.println("Footer XML:\n" + xml);
// 判断是否包含页码域 (PAGE 或 NUMPAGES)
if (xml.contains("PAGE") || xml.contains("NUMPAGES")) {
return "";
}
}
}
return null;
return "";
}
// public static void readTextWatermark(
// P paragraph,
// HeaderFooterPolicy hfp,
@@ -947,21 +1161,20 @@ public class SectionPage {
SectPr.PgSz pgSz = currentSectPr.getPgSz();
BigInteger w = pgSz.getW();
BigInteger h = pgSz.getH();
// 常用纸张判断 (宽 x 高, 单位 twip)
if (w != null && h != null) {
if (w.equals(BigInteger.valueOf(11906)) && h.equals(BigInteger.valueOf(16838))) return "A4";
if (w.equals(BigInteger.valueOf(16838)) && h.equals(BigInteger.valueOf(23811))) return "A3";
if (w.equals(BigInteger.valueOf(8504)) && h.equals(BigInteger.valueOf(11906))) return "B5";
if (w.equals(BigInteger.valueOf(23811)) && h.equals(BigInteger.valueOf(33685))) return "A2";
if (w.equals(BigInteger.valueOf(11906)) && h.equals(BigInteger.valueOf(16838))) return "Letter"; // 可根据需要补充
if ((w.equals(BigInteger.valueOf(11906)) && h.equals(BigInteger.valueOf(16838)))||(h.equals(BigInteger.valueOf(11906)) && w.equals(BigInteger.valueOf(16838)))) return "A4";
if ((w.equals(BigInteger.valueOf(16838)) && h.equals(BigInteger.valueOf(23811))) ||((h.equals(BigInteger.valueOf(16838)) && w.equals(BigInteger.valueOf(23811))) )) return "A3";
if ((w.equals(BigInteger.valueOf(8504)) && h.equals(BigInteger.valueOf(11906)))||(h.equals(BigInteger.valueOf(8504)) && w.equals(BigInteger.valueOf(11906)))) return "B5";
if ((w.equals(BigInteger.valueOf(23811)) && h.equals(BigInteger.valueOf(33685)))||(h.equals(BigInteger.valueOf(23811)) && w.equals(BigInteger.valueOf(33685)))) return "A2";
if ((w.equals(BigInteger.valueOf(11906)) && h.equals(BigInteger.valueOf(16838)))||(h.equals(BigInteger.valueOf(11906)) && w.equals(BigInteger.valueOf(16838)))) return "Letter"; // 可根据需要补充
}
return "自定义纸张";
}
// 宽度
//宽度
public static String getPageSetWidth(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
MainDocumentPart mainPart = wordMLPackage.getMainDocumentPart();
List<Object> allContent = mainPart.getContent();
@@ -1062,8 +1275,83 @@ public class SectionPage {
return "";
}
// 页面背景(页面颜色)-填充方式
// 页面背景(页面颜色)-纯色填充→颜色
// 页面背景(页面颜色)-渐变填充→预设
// 页面背景(页面颜色)- 纹理填充→纹理
// 页面背景(页面颜色)-图案填充→图案
// 页面背景(页面边框)-样式
public static String getPageBorderStyle(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
SectPr sectPr = getSectPr(paragraph, wordMLPackage);
if (sectPr != null && sectPr.getPgBorders() != null) {
SectPr.PgBorders borders = sectPr.getPgBorders();
// 以 Top 边框为例获取样式
CTBorder top = borders.getTop();
if (top != null && top.getVal() != null) {
return top.getVal().toString();
}
}
return "";
}
// 页面背景(页面边框)-颜色
public static String getPageBorderColor(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
SectPr sectPr = getSectPr(paragraph, wordMLPackage);
if (sectPr != null && sectPr.getPgBorders() != null) {
SectPr.PgBorders borders = sectPr.getPgBorders();
// 以 Top 为例获取颜色
CTBorder top = borders.getTop();
if (top != null && top.getColor() != null) {
return top.getColor();
}
}
return "";
}
// 页面背景(页面边框)-宽度
public static String getPageBorderWidth(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) {
SectPr sectPr = getSectPr(paragraph, wordMLPackage);
if (sectPr != null && sectPr.getPgBorders() != null) {
SectPr.PgBorders borders = sectPr.getPgBorders();
CTBorder top = borders.getTop();
if (top != null && top.getSz() != null) {
// Word 中单位为 eighths of a point1/8 pt
return (top.getSz().intValue() / 8.0) + "";
}
}
return "";
}
// 辅助方法:获取段落所在节的 SectPr
private static SectPr getSectPr(P paragraph, WordprocessingMLPackage wordMLPackage) {
MainDocumentPart mainPart = wordMLPackage.getMainDocumentPart();
List<Object> allContent = mainPart.getContent();
SectPr currentSectPr = null;
for (Object obj : allContent) {
Object unwrapped = XmlUtils.unwrap(obj);
if (unwrapped instanceof P) {
P p = (P) unwrapped;
if (p.getPPr() != null && p.getPPr().getSectPr() != null) {
currentSectPr = p.getPPr().getSectPr();
}
if (p == paragraph) break;
}
}
// 如果段落没有 SectPr则使用 body 的 SectPr
if (currentSectPr == null) {
currentSectPr = mainPart.getJaxbElement().getBody().getSectPr();
}
return currentSectPr;
}
// -------------------------------------------
// 私有方法:从参数中找到 VML 水印 XML 字符串(只取第一个匹配)
private static String getVMLWatermarkXml(P paragraph, HeaderFooterPolicy hfp, WordprocessingMLPackage wordMLPackage, List<SectionWrapper> sections) throws Exception {
@@ -1268,6 +1556,12 @@ public class SectionPage {
if (rPr.getColor() != null) {
info.colorHex = rPr.getColor().getVal();
}
// 加粗
info.bold = (rPr.getB() != null && Boolean.TRUE.equals(rPr.getB().isVal())) ? "" : "";
// 倾斜
info.italic = (rPr.getI() != null && Boolean.TRUE.equals(rPr.getI().isVal())) ? "" : "";
}
// 取文字内容

View File

@@ -0,0 +1,81 @@
package pc.exam.pp.module.judgement.utils.wps_word.docx4j.text;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import jakarta.xml.bind.JAXBElement;
import org.docx4j.dml.wordprocessingDrawing.Anchor;
import org.docx4j.wml.P;
import org.docx4j.wml.R;
import org.docx4j.wml.RPr;
import org.docx4j.wml.U;
public class TextBoxFontUtils {
// 封装文字属性的类
public static class TextBoxFontInfo {
public String text;
public String font;
public String color;
public boolean bold;
public boolean italic;
public String underlineStyle;
public String underlineColor;
@Override
public String toString() {
return String.format("文字: %s, 字体: %s, 颜色: %s, 加粗: %b, 倾斜: %b, 下划线类型: %s, 下划线颜色: %s",
text, font, color, bold, italic, underlineStyle, underlineColor);
}
}
public static List<TextBoxFontInfo> getTextBoxFontInfoList(List<?> judgementWordsVOS, Anchor anchor, int betoLong, Object wordMLPackage) throws Exception {
List<TextBoxFontInfo> result = new ArrayList<>();
if (anchor == null || anchor.getGraphic() == null || anchor.getGraphic().getGraphicData() == null) return result;
Object graphicDataObj = anchor.getGraphic().getGraphicData().getAny().get(0);
Object graphicData = (graphicDataObj instanceof JAXBElement<?>) ? ((JAXBElement<?>) graphicDataObj).getValue() : graphicDataObj;
// 只处理文本框
if (!graphicData.getClass().getSimpleName().equals("CTWordprocessingShape")) return result;
Field txbxField = graphicData.getClass().getDeclaredField("txbx");
txbxField.setAccessible(true);
Object txbx = txbxField.get(graphicData);
if (txbx == null) return result;
Field contentField = txbx.getClass().getDeclaredField("txbxContent");
contentField.setAccessible(true);
List<Object> paras = (List<Object>) contentField.get(txbx);
for (Object pObj : paras) {
if (pObj instanceof P) {
P p = (P) pObj;
for (Object rObj : p.getContent()) {
if (rObj instanceof R) {
R r = (R) rObj;
RPr rPr = r.getRPr();
TextBoxFontInfo info = new TextBoxFontInfo();
info.text = r.toString();
if (rPr != null) {
info.font = rPr.getRFonts() != null ? rPr.getRFonts().getAscii() : "默认字体";
info.color = rPr.getColor() != null ? rPr.getColor().getVal() : "默认颜色";
info.bold = Boolean.TRUE.equals(rPr.getB());
info.italic = Boolean.TRUE.equals(rPr.getI());
info.underlineStyle = rPr.getU() != null ? rPr.getU().getVal().toString() : "";
info.underlineColor = rPr.getColor() != null ? rPr.getColor().getVal() : "默认颜色";
}
result.add(info);
}
}
}
}
return result;
}
}

View File

@@ -37,6 +37,7 @@ public class ColorUtils {
COLOR_MAP.put("006600", "深绿色");
COLOR_MAP.put("99cc99", "浅绿色");
COLOR_MAP.put("00b0f0", "浅蓝色");
COLOR_MAP.put("0070c0", "蓝色");
// 16进制颜色代码映射统一小写
@@ -60,6 +61,7 @@ public class ColorUtils {
COLOR_MAP.put("ffd700", "金色");
COLOR_MAP.put("e54c5e", "金色");
COLOR_MAP.put("00b050", "绿色");
COLOR_MAP.put("ffc000", "橙色");