Commit fd4559e2353a7232dcad5c1d8a2c433199924032
Merge remote-tracking branch 'origin/master_0929' into master_0929
Showing
3 changed files
with
61 additions
and
47 deletions
| @@ -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 | /** |
No preview for this file type
No preview for this file type