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 13 import java.awt.*;
14 14 import java.awt.Color;
15 15 import java.awt.image.BufferedImage;
  16 +import java.io.ByteArrayInputStream;
16 17 import java.io.ByteArrayOutputStream;
17 18 import java.io.IOException;
18 19 import java.math.BigDecimal;
... ... @@ -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 82 public static byte[] latexToImageBytes(String latex, int fontSize) throws IOException {
87 83 try {
88   - // 1. 创建TeXFormula对象,解析LaTeX字符串
  84 + // 对于Excel,使用适中的缩放和RGB格式
  85 + double scale = 1.5; // 1.5倍缩放平衡质量和文件大小
89 86 TeXFormula formula = new TeXFormula(latex);
90   -
91   - // 2. 创建TeXIcon,指定样式和大小
92 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 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 101 Graphics2D g2 = image.createGraphics();
103 102
104   - // 设置最高质量的渲染提示
  103 + // 针对公式渲染优化的设置
105 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 106 g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
108 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 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 117 JLabel label = new JLabel();
120 118 label.setForeground(Color.BLACK);
121   -
122   - // 5. 将公式绘制到BufferedImage上
123 119 icon.paintIcon(label, g2, 0, 0);
  120 +
124 121 g2.dispose();
125 122
126   - // 6. 将BufferedImage转换为字节数组
  123 + // 使用标准PNG编码,确保Excel兼容性
127 124 ByteArrayOutputStream baos = new ByteArrayOutputStream();
128 125 ImageIO.write(image, "png", baos);
129 126
130 127 return baos.toByteArray();
131 128
132 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 135 * 将LaTeX公式作为图片插入到指定单元格
139 136 */
140 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 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 158 int pictureIdx = workbook.addPicture(imageBytes, Workbook.PICTURE_TYPE_PNG);
146   -
147   - // 3. 创建绘图对象
148 159 Drawing<?> drawing = sheet.createDrawingPatriarch();
149 160
150   - // 4. 创建锚点,确定图片位置
151 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 /**
... ...