Commit fd4559e2353a7232dcad5c1d8a2c433199924032

Authored by yeqianyong
2 parents 4c672999 94266e49

Merge remote-tracking branch 'origin/master_0929' into master_0929

@@ -13,6 +13,7 @@ import javax.swing.*; @@ -13,6 +13,7 @@ import javax.swing.*;
13 import java.awt.*; 13 import java.awt.*;
14 import java.awt.Color; 14 import java.awt.Color;
15 import java.awt.image.BufferedImage; 15 import java.awt.image.BufferedImage;
  16 +import java.io.ByteArrayInputStream;
16 import java.io.ByteArrayOutputStream; 17 import java.io.ByteArrayOutputStream;
17 import java.io.IOException; 18 import java.io.IOException;
18 import java.math.BigDecimal; 19 import java.math.BigDecimal;
@@ -76,61 +77,57 @@ public class LatexFormulaExcelExporterUtil { @@ -76,61 +77,57 @@ public class LatexFormulaExcelExporterUtil {
76 } 77 }
77 78
78 /** 79 /**
79 - * 将LaTeX公式字符串渲染为图片字节数组  
80 - *  
81 - * @param latex LaTeX公式字符串,如 "\\frac{-b \\pm \\sqrt{b^2-4ac}}{2a}"  
82 - * @param fontSize 渲染的字体大小  
83 - * @return 图片的字节数组 (PNG格式)  
84 - * @throws IOException 如果渲染或转换失败 80 + * 针对Excel优化的高质量渲染
85 */ 81 */
86 public static byte[] latexToImageBytes(String latex, int fontSize) throws IOException { 82 public static byte[] latexToImageBytes(String latex, int fontSize) throws IOException {
87 try { 83 try {
88 - // 1. 创建TeXFormula对象,解析LaTeX字符串 84 + // 对于Excel,使用适中的缩放和RGB格式
  85 + double scale = 1.5; // 1.5倍缩放平衡质量和文件大小
89 TeXFormula formula = new TeXFormula(latex); 86 TeXFormula formula = new TeXFormula(latex);
90 -  
91 - // 2. 创建TeXIcon,指定样式和大小  
92 TeXIcon icon = formula.createTeXIcon(TeXConstants.STYLE_DISPLAY, fontSize); 87 TeXIcon icon = formula.createTeXIcon(TeXConstants.STYLE_DISPLAY, fontSize);
93 88
94 - // 3. 创建一个BufferedImage,用于绘制公式 89 + int baseWidth = icon.getIconWidth();
  90 + int baseHeight = icon.getIconHeight();
  91 + int scaledWidth = (int) (baseWidth * scale);
  92 + int scaledHeight = (int) (baseHeight * scale);
  93 +
  94 + // 使用RGB类型,Excel兼容性更好
95 BufferedImage image = new BufferedImage( 95 BufferedImage image = new BufferedImage(
96 - icon.getIconWidth(),  
97 - icon.getIconHeight(),  
98 - BufferedImage.TYPE_INT_ARGB 96 + scaledWidth,
  97 + scaledHeight,
  98 + BufferedImage.TYPE_INT_RGB
99 ); 99 );
100 100
101 - // 4. 获取Graphics2D进行绘制  
102 Graphics2D g2 = image.createGraphics(); 101 Graphics2D g2 = image.createGraphics();
103 102
104 - // 设置最高质量的渲染提示 103 + // 针对公式渲染优化的设置
105 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 104 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
106 - g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB); 105 + g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
107 g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); 106 g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
108 g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); 107 g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
109 - g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);  
110 - g2.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);  
111 - g2.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);  
112 - g2.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);  
113 108
114 - // 设置背景为白色 109 + // 绘制白色背景
115 g2.setColor(Color.WHITE); 110 g2.setColor(Color.WHITE);
116 - g2.fillRect(0, 0, icon.getIconWidth(), icon.getIconHeight()); 111 + g2.fillRect(0, 0, scaledWidth, scaledHeight);
117 112
118 - // 设置公式颜色为黑色 113 + // 应用缩放
  114 + g2.scale(scale, scale);
  115 +
  116 + // 绘制公式
119 JLabel label = new JLabel(); 117 JLabel label = new JLabel();
120 label.setForeground(Color.BLACK); 118 label.setForeground(Color.BLACK);
121 -  
122 - // 5. 将公式绘制到BufferedImage上  
123 icon.paintIcon(label, g2, 0, 0); 119 icon.paintIcon(label, g2, 0, 0);
  120 +
124 g2.dispose(); 121 g2.dispose();
125 122
126 - // 6. 将BufferedImage转换为字节数组 123 + // 使用标准PNG编码,确保Excel兼容性
127 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 124 ByteArrayOutputStream baos = new ByteArrayOutputStream();
128 ImageIO.write(image, "png", baos); 125 ImageIO.write(image, "png", baos);
129 126
130 return baos.toByteArray(); 127 return baos.toByteArray();
131 128
132 } catch (Exception e) { 129 } catch (Exception e) {
133 - throw new IOException("LaTeX渲染失败: " + e.getMessage(), e); 130 + throw new IOException("LaTeX Excel优化渲染失败: " + e.getMessage(), e);
134 } 131 }
135 } 132 }
136 133
@@ -138,34 +135,51 @@ public class LatexFormulaExcelExporterUtil { @@ -138,34 +135,51 @@ public class LatexFormulaExcelExporterUtil {
138 * 将LaTeX公式作为图片插入到指定单元格 135 * 将LaTeX公式作为图片插入到指定单元格
139 */ 136 */
140 public static void insertLatexImageToCell(Workbook workbook, Sheet sheet, String latex, int rowIndex, int colIndex) throws IOException { 137 public static void insertLatexImageToCell(Workbook workbook, Sheet sheet, String latex, int rowIndex, int colIndex) throws IOException {
141 - // 1. 将LaTeX渲染为图片字节 138 + // 设置固定30像素行高
  139 + Row row = sheet.getRow(rowIndex);
  140 + if (row == null) {
  141 + row = sheet.createRow(rowIndex);
  142 + }
  143 +
  144 + row.setHeightInPoints(22.5f); // 30像素
  145 +
142 byte[] imageBytes = latexToImageBytes(latex, 48); 146 byte[] imageBytes = latexToImageBytes(latex, 48);
  147 + ByteArrayInputStream bais = new ByteArrayInputStream(imageBytes);
  148 + BufferedImage image = ImageIO.read(bais);
  149 + bais.close();
  150 +
  151 + // 如果图片高度超过30像素,按比例缩小
  152 + double scale = 1.0;
  153 + if (image.getHeight() > 30) {
  154 + scale = 30.0 / image.getHeight();
  155 + System.out.println("图片需要缩放: " + scale);
  156 + }
143 157
144 - // 2. 将图片添加到工作簿  
145 int pictureIdx = workbook.addPicture(imageBytes, Workbook.PICTURE_TYPE_PNG); 158 int pictureIdx = workbook.addPicture(imageBytes, Workbook.PICTURE_TYPE_PNG);
146 -  
147 - // 3. 创建绘图对象  
148 Drawing<?> drawing = sheet.createDrawingPatriarch(); 159 Drawing<?> drawing = sheet.createDrawingPatriarch();
149 160
150 - // 4. 创建锚点,确定图片位置  
151 ClientAnchor anchor = workbook.getCreationHelper().createClientAnchor(); 161 ClientAnchor anchor = workbook.getCreationHelper().createClientAnchor();
152 - anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE);  
153 - anchor.setCol1(colIndex); // C列 (从0开始计数)  
154 - anchor.setRow1(rowIndex); // 当前数据行 (表头在第0行)  
155 - anchor.setCol2(colIndex + 1); // 结束于D列  
156 - anchor.setRow2(rowIndex + 1); // 结束于下一行  
157 -  
158 - // 设置较小的起始偏移  
159 - anchor.setDx1(50); // 水平偏移(建议值:10-100)  
160 - anchor.setDy1(25); // 垂直偏移(建议值:10-50)  
161 - 162 + anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_DONT_RESIZE);
  163 +
  164 + anchor.setCol1(colIndex);
  165 + anchor.setRow1(rowIndex);
  166 + anchor.setCol2(colIndex);
  167 + anchor.setRow2(rowIndex);
  168 +
  169 + int scaledWidth = (int) (image.getWidth() * scale);
  170 + int rate = 1;
  171 + if (scaledWidth >= 60 && scaledWidth <= 150) {
  172 + rate = 2;
  173 + } else if (scaledWidth > 150) {
  174 + rate = 3;
  175 + }
162 176
163 - // 5. 创建图片并插入  
164 - Picture pict = drawing.createPicture(anchor, pictureIdx); 177 + anchor.setDx1(25);
  178 + anchor.setDy1(25);
  179 + anchor.setDx2(330 * rate);
  180 + anchor.setDy2(235);
165 181
166 - // 6. 自动调整图片大小以适应单元格 (可选)  
167 - // 取消注释此行使图片自动适应锚点区域  
168 -// pict.resize(0.95); // 缩小到90%,自然产生边距 182 + drawing.createPicture(anchor, pictureIdx);
169 } 183 }
170 184
171 /** 185 /**