Commit 453af234430ea0302725f95683e38c8d66af2e13

Authored by 房远帅
1 parent cbb0a39f

导出:规格大小时大时小问题修改

@@ -820,7 +820,7 @@ public class ContractDistributorStandardController extends DefaultBaseController @@ -820,7 +820,7 @@ public class ContractDistributorStandardController extends DefaultBaseController
820 formulaComponentList.add(formulaComponent); 820 formulaComponentList.add(formulaComponent);
821 } 821 }
822 822
823 - String latex = LatexFormulaExcelExporterUtil.convertToLatex(formulaComponentList); 823 + String latex = LatexFormulaExcelExporterUtil.convertToContractSpecLatex(formulaComponentList);
824 if (StringUtils.isNotBlank(latex)) { 824 if (StringUtils.isNotBlank(latex)) {
825 LatexFormulaExcelExporterUtil.insertLatexImageToCell(workbook, sheet, latex, startRow, 5);// E列 825 LatexFormulaExcelExporterUtil.insertLatexImageToCell(workbook, sheet, latex, startRow, 5);// E列
826 } 826 }
@@ -879,7 +879,7 @@ public class ContractDistributorStandardController extends DefaultBaseController @@ -879,7 +879,7 @@ public class ContractDistributorStandardController extends DefaultBaseController
879 formulaComponentList.add(formulaComponent); 879 formulaComponentList.add(formulaComponent);
880 } 880 }
881 881
882 - String latex = LatexFormulaExcelExporterUtil.convertToLatex(formulaComponentList); 882 + String latex = LatexFormulaExcelExporterUtil.convertToContractSpecLatex(formulaComponentList);
883 if (StringUtils.isNotBlank(latex)) { 883 if (StringUtils.isNotBlank(latex)) {
884 LatexFormulaExcelExporterUtil.insertLatexImageToCell(workbook, sheet, latex, startRow, 9);// E列 884 LatexFormulaExcelExporterUtil.insertLatexImageToCell(workbook, sheet, latex, startRow, 9);// E列
885 } 885 }
@@ -1067,6 +1067,7 @@ public class ContractDistributorStandardController extends DefaultBaseController @@ -1067,6 +1067,7 @@ public class ContractDistributorStandardController extends DefaultBaseController
1067 1067
1068 try { 1068 try {
1069 Sheet sheet = workbook.getSheetAt(0); 1069 Sheet sheet = workbook.getSheetAt(0);
  1070 + List<SpecImageCell> specImageCells = new ArrayList<>();
1070 DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); 1071 DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
1071 int startRow = 6; 1072 int startRow = 6;
1072 String contractTitle = "销售订单(经销)"; 1073 String contractTitle = "销售订单(经销)";
@@ -1099,9 +1100,9 @@ public class ContractDistributorStandardController extends DefaultBaseController @@ -1099,9 +1100,9 @@ public class ContractDistributorStandardController extends DefaultBaseController
1099 addFormulaComponent(formulaComponentList, line.getWidth(), line.getWidthTolPos(), line.getWidthTolNeg()); 1100 addFormulaComponent(formulaComponentList, line.getWidth(), line.getWidthTolPos(), line.getWidthTolNeg());
1100 addFormulaComponent(formulaComponentList, line.getLength(), line.getLengthTolPos(), line.getLengthTolNeg()); 1101 addFormulaComponent(formulaComponentList, line.getLength(), line.getLengthTolPos(), line.getLengthTolNeg());
1101 1102
1102 - String latex = LatexFormulaExcelExporterUtil.convertToLatex(formulaComponentList); 1103 + String latex = LatexFormulaExcelExporterUtil.convertToContractSpecLatexSingleLineFixed3(formulaComponentList);
1103 if (StringUtils.isNotBlank(latex)) { 1104 if (StringUtils.isNotBlank(latex)) {
1104 - LatexFormulaExcelExporterUtil.insertLatexImageToCell(workbook, sheet, latex, startRow, 5); 1105 + specImageCells.add(new SpecImageCell(startRow, 5, latex));
1105 } 1106 }
1106 1107
1107 setCellValue(sheet, startRow, 6, line.getMaterialCode()); 1108 setCellValue(sheet, startRow, 6, line.getMaterialCode());
@@ -1143,9 +1144,9 @@ public class ContractDistributorStandardController extends DefaultBaseController @@ -1143,9 +1144,9 @@ public class ContractDistributorStandardController extends DefaultBaseController
1143 addFormulaComponent(formulaComponentList, line.getWidth(), line.getWidthTolPos(), line.getWidthTolNeg()); 1144 addFormulaComponent(formulaComponentList, line.getWidth(), line.getWidthTolPos(), line.getWidthTolNeg());
1144 addFormulaComponent(formulaComponentList, line.getLength(), line.getLengthTolPos(), line.getLengthTolNeg()); 1145 addFormulaComponent(formulaComponentList, line.getLength(), line.getLengthTolPos(), line.getLengthTolNeg());
1145 1146
1146 - String latex = LatexFormulaExcelExporterUtil.convertToLatex(formulaComponentList); 1147 + String latex = LatexFormulaExcelExporterUtil.convertToContractSpecLatexSingleLineFixed3(formulaComponentList);
1147 if (StringUtils.isNotBlank(latex)) { 1148 if (StringUtils.isNotBlank(latex)) {
1148 - LatexFormulaExcelExporterUtil.insertLatexImageToCell(workbook, sheet, latex, startRow, 9); 1149 + specImageCells.add(new SpecImageCell(startRow, 9, latex));
1149 } 1150 }
1150 setCellValue(sheet, startRow, 10, line.getMaterialCode()); 1151 setCellValue(sheet, startRow, 10, line.getMaterialCode());
1151 setCellValue(sheet, startRow, 11, line.getProductStatus()); 1152 setCellValue(sheet, startRow, 11, line.getProductStatus());
@@ -1158,6 +1159,15 @@ public class ContractDistributorStandardController extends DefaultBaseController @@ -1158,6 +1159,15 @@ public class ContractDistributorStandardController extends DefaultBaseController
1158 } 1159 }
1159 } 1160 }
1160 1161
  1162 + double specMinScale = 1.0;
  1163 + for (SpecImageCell specCell : specImageCells) {
  1164 + double scale = LatexFormulaExcelExporterUtil.calculateFitScale(workbook, sheet, specCell.latex, specCell.rowIndex, specCell.colIndex);
  1165 + specMinScale = Math.min(specMinScale, scale);
  1166 + }
  1167 + for (SpecImageCell specCell : specImageCells) {
  1168 + LatexFormulaExcelExporterUtil.insertLatexImageToCellWithMaxScale(workbook, sheet, specCell.latex, specCell.rowIndex, specCell.colIndex, specMinScale);
  1169 + }
  1170 +
1161 // --- 填充全局变量 --- 1171 // --- 填充全局变量 ---
1162 Map<String, Object> dataMap = buildDataMap(data, contractTitle, dateFormatter); 1172 Map<String, Object> dataMap = buildDataMap(data, contractTitle, dateFormatter);
1163 processTemplate(workbook, dataMap); 1173 processTemplate(workbook, dataMap);
@@ -1210,6 +1220,18 @@ public class ContractDistributorStandardController extends DefaultBaseController @@ -1210,6 +1220,18 @@ public class ContractDistributorStandardController extends DefaultBaseController
1210 } 1220 }
1211 } 1221 }
1212 1222
  1223 + private static class SpecImageCell {
  1224 + private final int rowIndex;
  1225 + private final int colIndex;
  1226 + private final String latex;
  1227 +
  1228 + private SpecImageCell(int rowIndex, int colIndex, String latex) {
  1229 + this.rowIndex = rowIndex;
  1230 + this.colIndex = colIndex;
  1231 + this.latex = latex;
  1232 + }
  1233 + }
  1234 +
1213 private void addFormulaComponent(List<LatexFormulaExcelExporterUtil.FormulaComponent> list, 1235 private void addFormulaComponent(List<LatexFormulaExcelExporterUtil.FormulaComponent> list,
1214 BigDecimal base, BigDecimal sup, BigDecimal sub) { 1236 BigDecimal base, BigDecimal sup, BigDecimal sub) {
1215 if (base != null) { 1237 if (base != null) {
@@ -4,6 +4,8 @@ import lombok.Data; @@ -4,6 +4,8 @@ import lombok.Data;
4 import lombok.extern.slf4j.Slf4j; 4 import lombok.extern.slf4j.Slf4j;
5 import org.apache.commons.collections4.CollectionUtils; 5 import org.apache.commons.collections4.CollectionUtils;
6 import org.apache.poi.ss.usermodel.*; 6 import org.apache.poi.ss.usermodel.*;
  7 +import org.apache.poi.ss.usermodel.Font;
  8 +import org.apache.poi.ss.util.CellRangeAddress;
7 import org.scilab.forge.jlatexmath.TeXConstants; 9 import org.scilab.forge.jlatexmath.TeXConstants;
8 import org.scilab.forge.jlatexmath.TeXFormula; 10 import org.scilab.forge.jlatexmath.TeXFormula;
9 import org.scilab.forge.jlatexmath.TeXIcon; 11 import org.scilab.forge.jlatexmath.TeXIcon;
@@ -60,6 +62,85 @@ public class LatexFormulaExcelExporterUtil { @@ -60,6 +62,85 @@ public class LatexFormulaExcelExporterUtil {
60 return latex.toString(); 62 return latex.toString();
61 } 63 }
62 64
  65 + public static String convertToContractSpecLatex(List<FormulaComponent> componentList) {
  66 + if (CollectionUtils.isEmpty(componentList)) {
  67 + return "";
  68 + }
  69 + if (componentList.size() <= 2) {
  70 + return convertToLatex(componentList);
  71 + }
  72 + String line1 = buildLatexLine(componentList, 0, 2);
  73 + String line2 = buildLatexLine(componentList, 2, componentList.size());
  74 + if (line2.isEmpty()) {
  75 + return "\\mathbf{" + line1 + "}";
  76 + }
  77 + return "\\begin{array}{c}\\mathbf{" + line1 + "}\\\\\\mathbf{" + line2 + "}\\end{array}";
  78 + }
  79 +
  80 + public static String convertToContractSpecLatexSingleLineFixed3(List<FormulaComponent> componentList) {
  81 + if (CollectionUtils.isEmpty(componentList)) {
  82 + return "";
  83 + }
  84 +
  85 + int nonNullCount = 0;
  86 + for (FormulaComponent comp : componentList) {
  87 + if (comp != null && comp.getBase() != null) {
  88 + nonNullCount++;
  89 + }
  90 + }
  91 + if (nonNullCount <= 0) {
  92 + return "";
  93 + }
  94 +
  95 + String actual = buildLatexLine(componentList, 0, componentList.size());
  96 + if (actual.isEmpty()) {
  97 + return "";
  98 + }
  99 +
  100 + int missing = Math.max(0, 3 - nonNullCount);
  101 + if (missing > 0) {
  102 + StringBuilder phantom = new StringBuilder();
  103 + for (int i = 0; i < missing; i++) {
  104 + phantom.append(" \\times 000^{+00}_{+00}");
  105 + }
  106 + actual = actual + "\\phantom{" + phantom + "}";
  107 + }
  108 +
  109 + return "\\mathbf{" + actual + "}";
  110 + }
  111 +
  112 + private static String buildLatexLine(List<FormulaComponent> componentList, int startIndex, int endIndexExclusive) {
  113 + StringBuilder latex = new StringBuilder();
  114 + boolean first = true;
  115 + int end = Math.min(componentList.size(), endIndexExclusive);
  116 + for (int i = startIndex; i < end; i++) {
  117 + FormulaComponent comp = componentList.get(i);
  118 + if (comp == null || comp.getBase() == null) {
  119 + continue;
  120 + }
  121 + if (!first) {
  122 + latex.append(" \\times ");
  123 + }
  124 + first = false;
  125 +
  126 + latex.append(formatScientificNotation(comp.getBase()));
  127 + if (comp.getSup() != null && comp.getSup().compareTo(BigDecimal.ZERO) >= 0) {
  128 + latex.append("^{+").append(formatScientificNotation(comp.getSup())).append("}");
  129 + }
  130 + if (comp.getSup() != null && comp.getSup().compareTo(BigDecimal.ZERO) < 0) {
  131 + latex.append("^{").append(formatScientificNotation(comp.getSup())).append("}");
  132 + }
  133 +
  134 + if (comp.getSub() != null && comp.getSub().compareTo(BigDecimal.ZERO) >= 0) {
  135 + latex.append("_{+").append(formatScientificNotation(comp.getSub())).append("}");
  136 + }
  137 + if (comp.getSub() != null && comp.getSub().compareTo(BigDecimal.ZERO) < 0) {
  138 + latex.append("_{").append(formatScientificNotation(comp.getSub())).append("}");
  139 + }
  140 + }
  141 + return latex.toString();
  142 + }
  143 +
63 144
64 /** 145 /**
65 * 处理科学计数法表示的大数字 146 * 处理科学计数法表示的大数字
@@ -141,25 +222,142 @@ public class LatexFormulaExcelExporterUtil { @@ -141,25 +222,142 @@ public class LatexFormulaExcelExporterUtil {
141 * 将LaTeX公式作为图片插入到指定单元格 222 * 将LaTeX公式作为图片插入到指定单元格
142 */ 223 */
143 public static void insertLatexImageToCell(Workbook workbook, Sheet sheet, String latex, int rowIndex, int colIndex) throws IOException { 224 public static void insertLatexImageToCell(Workbook workbook, Sheet sheet, String latex, int rowIndex, int colIndex) throws IOException {
144 - // 设置固定30像素行高  
145 - Row row = sheet.getRow(rowIndex);  
146 - if (row == null) {  
147 - row = sheet.createRow(rowIndex); 225 + int fontSize = resolveCellFontSize(workbook, sheet, rowIndex, colIndex);
  226 +
  227 + CellRangeAddress mergedRegion = findMergedRegion(sheet, rowIndex, colIndex);
  228 + if (mergedRegion != null) {
  229 + insertLatexImageToRegion(
  230 + workbook,
  231 + sheet,
  232 + latex,
  233 + mergedRegion.getFirstRow(),
  234 + mergedRegion.getFirstColumn(),
  235 + mergedRegion.getLastRow() - mergedRegion.getFirstRow() + 1,
  236 + mergedRegion.getLastColumn() - mergedRegion.getFirstColumn() + 1,
  237 + fontSize,
  238 + null
  239 + );
  240 + return;
148 } 241 }
149 242
150 - row.setHeightInPoints(22.5f); // 30像素 243 + insertLatexImageToRegion(workbook, sheet, latex, rowIndex, colIndex, 1, 1, fontSize, null);
  244 + }
151 245
152 - byte[] imageBytes = latexToImageBytes(latex, 48);  
153 - ByteArrayInputStream bais = new ByteArrayInputStream(imageBytes);  
154 - BufferedImage image = ImageIO.read(bais);  
155 - bais.close(); 246 + /**
  247 + * 将LaTeX公式作为图片插入到指定单元格
  248 + */
  249 + public static void insertLatexImageToCell(Workbook workbook, Sheet sheet, String latex, int rowIndex, int colIndex, int rowRange, int colRange) throws IOException {
  250 + insertLatexImageToRegion(workbook, sheet, latex, rowIndex, colIndex, rowRange, colRange, 16, null);
  251 + }
156 252
157 - // 如果图片高度超过30像素,按比例缩小  
158 - double scale = 1.0;  
159 - if (image.getHeight() > 30) {  
160 - scale = 30.0 / image.getHeight();  
161 - System.out.println("图片需要缩放: " + scale); 253 + private static final int EMU_PER_PX = 9525;
  254 +
  255 + public static void insertLatexImageToCellWithMaxScale(Workbook workbook, Sheet sheet, String latex, int rowIndex, int colIndex,
  256 + double maxScale) throws IOException {
  257 + int fontSize = resolveCellFontSize(workbook, sheet, rowIndex, colIndex);
  258 + CellRangeAddress mergedRegion = findMergedRegion(sheet, rowIndex, colIndex);
  259 + if (mergedRegion != null) {
  260 + insertLatexImageToRegion(
  261 + workbook,
  262 + sheet,
  263 + latex,
  264 + mergedRegion.getFirstRow(),
  265 + mergedRegion.getFirstColumn(),
  266 + mergedRegion.getLastRow() - mergedRegion.getFirstRow() + 1,
  267 + mergedRegion.getLastColumn() - mergedRegion.getFirstColumn() + 1,
  268 + fontSize,
  269 + maxScale
  270 + );
  271 + return;
162 } 272 }
  273 + insertLatexImageToRegion(workbook, sheet, latex, rowIndex, colIndex, 1, 1, fontSize, maxScale);
  274 + }
  275 +
  276 + public static double calculateFitScale(Workbook workbook, Sheet sheet, String latex, int rowIndex, int colIndex) throws IOException {
  277 + int fontSize = resolveCellFontSize(workbook, sheet, rowIndex, colIndex);
  278 + CellRangeAddress mergedRegion = findMergedRegion(sheet, rowIndex, colIndex);
  279 + if (mergedRegion != null) {
  280 + return calculateFitScaleForRegion(
  281 + sheet,
  282 + latex,
  283 + mergedRegion.getFirstRow(),
  284 + mergedRegion.getFirstColumn(),
  285 + mergedRegion.getLastRow() - mergedRegion.getFirstRow() + 1,
  286 + mergedRegion.getLastColumn() - mergedRegion.getFirstColumn() + 1,
  287 + fontSize
  288 + );
  289 + }
  290 + return calculateFitScaleForRegion(sheet, latex, rowIndex, colIndex, 1, 1, fontSize);
  291 + }
  292 +
  293 + private static double calculateFitScaleForRegion(Sheet sheet, String latex,
  294 + int rowIndex, int colIndex, int rowRange, int colRange,
  295 + int fontSize) throws IOException {
  296 + byte[] imageBytes = latexToImageBytes(latex, fontSize);
  297 + BufferedImage image;
  298 + try (ByteArrayInputStream in = new ByteArrayInputStream(imageBytes)) {
  299 + image = ImageIO.read(in);
  300 + }
  301 + if (image == null) {
  302 + return 1.0;
  303 + }
  304 +
  305 + int regionWidthPx = 0;
  306 + for (int c = colIndex; c < colIndex + colRange; c++) {
  307 + regionWidthPx += getColumnWidthPx(sheet, c);
  308 + }
  309 + int regionHeightPx = 0;
  310 + for (int r = rowIndex; r < rowIndex + rowRange; r++) {
  311 + regionHeightPx += getRowHeightPx(sheet, r);
  312 + }
  313 +
  314 + int paddingXPx = 6;
  315 + int paddingYPx = 2;
  316 + double scale = Math.min(
  317 + (double) (regionWidthPx - paddingXPx * 2) / Math.max(1, image.getWidth()),
  318 + (double) (regionHeightPx - paddingYPx * 2) / Math.max(1, image.getHeight())
  319 + );
  320 + return Math.min(scale, 1.0);
  321 + }
  322 +
  323 + private static void insertLatexImageToRegion(Workbook workbook, Sheet sheet, String latex,
  324 + int rowIndex, int colIndex, int rowRange, int colRange,
  325 + int fontSize, Double maxScale) throws IOException {
  326 + byte[] imageBytes = latexToImageBytes(latex, fontSize);
  327 + BufferedImage image;
  328 + try (ByteArrayInputStream in = new ByteArrayInputStream(imageBytes)) {
  329 + image = ImageIO.read(in);
  330 + }
  331 +
  332 + if (image == null) {
  333 + return;
  334 + }
  335 +
  336 + int regionWidthPx = 0;
  337 + for (int c = colIndex; c < colIndex + colRange; c++) {
  338 + regionWidthPx += getColumnWidthPx(sheet, c);
  339 + }
  340 + int regionHeightPx = 0;
  341 + for (int r = rowIndex; r < rowIndex + rowRange; r++) {
  342 + regionHeightPx += getRowHeightPx(sheet, r);
  343 + }
  344 +
  345 + int paddingXPx = 6;
  346 + int paddingYPx = 2;
  347 + double scale = Math.min(
  348 + (double) (regionWidthPx - paddingXPx * 2) / Math.max(1, image.getWidth()),
  349 + (double) (regionHeightPx - paddingYPx * 2) / Math.max(1, image.getHeight())
  350 + );
  351 + scale = Math.min(scale, 1.0);
  352 + if (maxScale != null) {
  353 + scale = Math.min(scale, maxScale);
  354 + }
  355 +
  356 + int scaledWidthPx = Math.max(1, (int) Math.round(image.getWidth() * scale));
  357 + int scaledHeightPx = Math.max(1, (int) Math.round(image.getHeight() * scale));
  358 +
  359 + int offsetXPx = Math.max(paddingXPx, (regionWidthPx - scaledWidthPx) / 2);
  360 + int offsetYPx = Math.max(paddingYPx, (regionHeightPx - scaledHeightPx) / 2);
163 361
164 int pictureIdx = workbook.addPicture(imageBytes, Workbook.PICTURE_TYPE_PNG); 362 int pictureIdx = workbook.addPicture(imageBytes, Workbook.PICTURE_TYPE_PNG);
165 Drawing<?> drawing = sheet.createDrawingPatriarch(); 363 Drawing<?> drawing = sheet.createDrawingPatriarch();
@@ -167,59 +365,142 @@ public class LatexFormulaExcelExporterUtil { @@ -167,59 +365,142 @@ public class LatexFormulaExcelExporterUtil {
167 ClientAnchor anchor = workbook.getCreationHelper().createClientAnchor(); 365 ClientAnchor anchor = workbook.getCreationHelper().createClientAnchor();
168 anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_DONT_RESIZE); 366 anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_DONT_RESIZE);
169 367
170 - anchor.setCol1(colIndex);  
171 - anchor.setRow1(rowIndex);  
172 - anchor.setCol2(colIndex);  
173 - anchor.setRow2(rowIndex); 368 + AnchorCoord x1 = resolveAnchorX(sheet, colIndex, colRange, offsetXPx);
  369 + AnchorCoord x2 = resolveAnchorX(sheet, colIndex, colRange, offsetXPx + scaledWidthPx);
  370 + AnchorCoord y1 = resolveAnchorY(sheet, rowIndex, rowRange, offsetYPx);
  371 + AnchorCoord y2 = resolveAnchorY(sheet, rowIndex, rowRange, offsetYPx + scaledHeightPx);
174 372
175 - int scaledWidth = (int) (image.getWidth() * scale);  
176 - int rate = 1;  
177 - if (scaledWidth >= 60 && scaledWidth <= 150) {  
178 - rate = 2;  
179 - } else if (scaledWidth > 150) {  
180 - rate = 3;  
181 - } 373 + anchor.setCol1(x1.index);
  374 + anchor.setCol2(x2.index);
  375 + anchor.setRow1(y1.index);
  376 + anchor.setRow2(y2.index);
182 377
183 - anchor.setDx1(25);  
184 - anchor.setDy1(25);  
185 - anchor.setDx2(330 * rate);  
186 - anchor.setDy2(235); 378 + if (anchor instanceof org.apache.poi.hssf.usermodel.HSSFClientAnchor) {
  379 + int dx1 = pxToHssfDx(sheet, x1.index, x1.offsetPx);
  380 + int dx2 = pxToHssfDx(sheet, x2.index, x2.offsetPx);
  381 + int dy1 = pxToHssfDy(sheet, y1.index, y1.offsetPx);
  382 + int dy2 = pxToHssfDy(sheet, y2.index, y2.offsetPx);
  383 +
  384 + if (x2.index == x1.index && dx2 <= dx1) {
  385 + dx2 = Math.min(1023, dx1 + 1);
  386 + }
  387 + if (y2.index == y1.index && dy2 <= dy1) {
  388 + dy2 = Math.min(255, dy1 + 1);
  389 + }
  390 +
  391 + anchor.setDx1(dx1);
  392 + anchor.setDx2(dx2);
  393 + anchor.setDy1(dy1);
  394 + anchor.setDy2(dy2);
  395 + } else {
  396 + int dx1 = x1.offsetPx * EMU_PER_PX;
  397 + int dx2 = x2.offsetPx * EMU_PER_PX;
  398 + int dy1 = y1.offsetPx * EMU_PER_PX;
  399 + int dy2 = y2.offsetPx * EMU_PER_PX;
  400 +
  401 + if (x2.index == x1.index && dx2 <= dx1) {
  402 + dx2 = dx1 + 1;
  403 + }
  404 + if (y2.index == y1.index && dy2 <= dy1) {
  405 + dy2 = dy1 + 1;
  406 + }
  407 +
  408 + anchor.setDx1(dx1);
  409 + anchor.setDx2(dx2);
  410 + anchor.setDy1(dy1);
  411 + anchor.setDy2(dy2);
  412 + }
187 413
188 drawing.createPicture(anchor, pictureIdx); 414 drawing.createPicture(anchor, pictureIdx);
189 } 415 }
190 416
191 - /**  
192 - * 将LaTeX公式作为图片插入到指定单元格  
193 - */  
194 - public static void insertLatexImageToCell(Workbook workbook, Sheet sheet, String latex, int rowIndex, int colIndex, int rowRange, int colRange) throws IOException {  
195 - // 1. 将LaTeX渲染为图片字节  
196 - byte[] imageBytes = latexToImageBytes(latex, 36); 417 + private static int getColumnWidthPx(Sheet sheet, int colIndex) {
  418 + int widthUnits = sheet.getColumnWidth(colIndex);
  419 + return Math.max(1, (int) Math.round(widthUnits / 256.0 * 7.0 + 5));
  420 + }
197 421
198 - // 2. 将图片添加到工作簿  
199 - int pictureIdx = workbook.addPicture(imageBytes, Workbook.PICTURE_TYPE_PNG); 422 + private static int getRowHeightPx(Sheet sheet, int rowIndex) {
  423 + Row row = sheet.getRow(rowIndex);
  424 + float points = row == null ? sheet.getDefaultRowHeightInPoints() : row.getHeightInPoints();
  425 + return Math.max(1, (int) Math.round(points * 96.0 / 72.0));
  426 + }
200 427
201 - // 3. 创建绘图对象  
202 - Drawing<?> drawing = sheet.createDrawingPatriarch(); 428 + private static class AnchorCoord {
  429 + final int index;
  430 + final int offsetPx;
203 431
204 - // 4. 创建锚点,确定图片位置  
205 - ClientAnchor anchor = workbook.getCreationHelper().createClientAnchor();  
206 - anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE);  
207 - anchor.setCol1(colIndex); // C列 (从0开始计数)  
208 - anchor.setRow1(rowIndex); // 当前数据行 (表头在第0行)  
209 - anchor.setCol2(colIndex + colRange); // 结束于D列  
210 - anchor.setRow2(rowIndex + rowRange); // 结束于下一行 432 + private AnchorCoord(int index, int offsetPx) {
  433 + this.index = index;
  434 + this.offsetPx = offsetPx;
  435 + }
  436 + }
211 437
212 - // 设置较小的起始偏移  
213 - anchor.setDx1(10000); // 水平偏移(建议值:10-100)  
214 - anchor.setDy1(10000); // 垂直偏移(建议值:10-50) 438 + private static AnchorCoord resolveAnchorX(Sheet sheet, int colIndex, int colRange, int offsetPx) {
  439 + int remaining = offsetPx;
  440 + for (int c = colIndex; c < colIndex + colRange; c++) {
  441 + int w = getColumnWidthPx(sheet, c);
  442 + if (remaining <= w) {
  443 + return new AnchorCoord(c, Math.max(0, remaining));
  444 + }
  445 + remaining -= w;
  446 + }
  447 + int lastCol = colIndex + colRange - 1;
  448 + return new AnchorCoord(lastCol, getColumnWidthPx(sheet, lastCol));
  449 + }
  450 +
  451 + private static AnchorCoord resolveAnchorY(Sheet sheet, int rowIndex, int rowRange, int offsetPx) {
  452 + int remaining = offsetPx;
  453 + for (int r = rowIndex; r < rowIndex + rowRange; r++) {
  454 + int h = getRowHeightPx(sheet, r);
  455 + if (remaining <= h) {
  456 + return new AnchorCoord(r, Math.max(0, remaining));
  457 + }
  458 + remaining -= h;
  459 + }
  460 + int lastRow = rowIndex + rowRange - 1;
  461 + return new AnchorCoord(lastRow, getRowHeightPx(sheet, lastRow));
  462 + }
  463 +
  464 + private static int pxToHssfDx(Sheet sheet, int colIndex, int offsetPx) {
  465 + int w = getColumnWidthPx(sheet, colIndex);
  466 + int px = Math.min(Math.max(offsetPx, 0), w);
  467 + return (int) Math.round(px * 1023.0 / Math.max(1, w));
  468 + }
215 469
  470 + private static int pxToHssfDy(Sheet sheet, int rowIndex, int offsetPx) {
  471 + int h = getRowHeightPx(sheet, rowIndex);
  472 + int px = Math.min(Math.max(offsetPx, 0), h);
  473 + return (int) Math.round(px * 255.0 / Math.max(1, h));
  474 + }
216 475
217 - // 5. 创建图片并插入  
218 - Picture pict = drawing.createPicture(anchor, pictureIdx); 476 + private static CellRangeAddress findMergedRegion(Sheet sheet, int rowIndex, int colIndex) {
  477 + for (int i = 0; i < sheet.getNumMergedRegions(); i++) {
  478 + CellRangeAddress region = sheet.getMergedRegion(i);
  479 + if (region == null) {
  480 + continue;
  481 + }
  482 + if (rowIndex >= region.getFirstRow()
  483 + && rowIndex <= region.getLastRow()
  484 + && colIndex >= region.getFirstColumn()
  485 + && colIndex <= region.getLastColumn()) {
  486 + return region;
  487 + }
  488 + }
  489 + return null;
  490 + }
219 491
220 - // 6. 自动调整图片大小以适应单元格 (可选)  
221 - // 取消注释此行使图片自动适应锚点区域  
222 - pict.resize(0.95); // 缩小到90%,自然产生边距 492 + private static int resolveCellFontSize(Workbook workbook, Sheet sheet, int rowIndex, int colIndex) {
  493 + Row row = sheet.getRow(rowIndex);
  494 + Cell cell = row == null ? null : row.getCell(colIndex);
  495 + CellStyle style = cell == null ? null : cell.getCellStyle();
  496 + short fontIndex = style == null ? 0 : style.getFontIndex();
  497 + Font font = workbook.getFontAt(fontIndex);
  498 + short cellFontSize = font == null ? 11 : font.getFontHeightInPoints();
  499 +
  500 + int latexFontSize = cellFontSize + 4;
  501 + latexFontSize = Math.max(14, latexFontSize);
  502 + latexFontSize = Math.min(20, latexFontSize);
  503 + return latexFontSize;
223 } 504 }
224 505
225 @Data 506 @Data