excel 导出 base64 格式的图片(可显示多个图片)

1、需求描述

首先系统中有录入电子签章的功能,录入电子签章可以通过 web 端和 uniapp 端进行录入;录入后在业务表中需要导出,导出时有可能要在一个单元格显示多张图片。

2、实现思路

由于之前在 web 端和 app 端实现的电子签章不是一个人做的,导致两边存的数据格式不一样,web 端的存的是 svg 格式的base64 图片,而uniapp 里面存的是 png 格式,导致导出的时候出现了很多问题,我这里把web端的签章改成了 png 格式,这样导出方便许多


image.png

3、代码

 /**
     * 导出处理电子签章
     *
     * @param modelMap
     * @param templateExportParams
     * @param list
     * @param response
     */
    private void dealSign(ModelMap modelMap, TemplateExportParams templateExportParams, List<Entity> list, HttpServletResponse response) {
        OutputStream out = null;
        try {
            // 拿到模板文件
            String filePath = "your_excel_file";
            FileInputStream tps = new FileInputStream(new File(filePath));
            final HSSFWorkbook workbook = new HSSFWorkbook(tps);
            out = response.getOutputStream();
            response.reset();
            String fileName = "数据";
            fileName = new String(fileName.getBytes("UTF-8"), "ISO-8859-1");
            response.setHeader("content-disposition", "attachment;filename=" + fileName + ".xls");
            response.setContentType("APPLICATION/msexcel");
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

            HSSFSheet sheet = workbook.getSheetAt(0);
            HSSFCellStyle style = workbook.createCellStyle();
            style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
            style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
            //Font font = workbook.createFont();
            //font.setFontHeightInPoints((short) 12);
            //style.setFont(font);
            style.setWrapText(true);// 设置自动换行
            // 全局唯一
            Drawing drawing = sheet.createDrawingPatriarch();
            for (int i = 0; i < list.size(); i++) {
                TbHiddenDangerHandleEntity t = list.get(i);
                Row row = sheet.createRow(i + 2); // 前两行被标题和字段占用
                // 自己获取到 要用的电子签章
                String[] signs= t.getSigns();

                if (signs != null) {
                    
                    // 在最后一列插入图片
                    Cell rowCell = row.createCell(1);
                    rowCell.setCellStyle(style);

                    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

                    BufferedImage bufferedImage = ImageUtil.base64ToBufferedImage(signs);

                    int width = bufferedImage.getWidth();
                    int height = bufferedImage.getHeight();
                    // 这里调整的宽高是自己测试的结果,可能和我们的模板有关
                    sheet.setColumnWidth(1, width * 8 );
                    row.setHeightInPoints((short) height / 6);

                    ImageIO.write(bufferedImage, "png", outputStream);
                    anchor = new HSSFClientAnchor(0, 0, 1023, 255, (short) 1, i + 2, (short) 2, i + 3);
                    anchor.setAnchorType(ClientAnchor.DONT_MOVE_AND_RESIZE);
                    //画图的顶级管理器,一个sheet只能获取一个(一定要注意这点)
                    Picture picture = drawing.createPicture(anchor, workbook.addPicture(outputStream.toByteArray(), Workbook.PICTURE_TYPE_PNG));

                    picture.resize(0.2);
                    //sheet.autoSizeColumn(25);

                }

            }
            HSSFWorkbook realWorkbook = workbook;
            realWorkbook.write(out);
        } catch (final Exception e) {
            e.printStackTrace();
            logger.error(e);
        } finally {
            try {
                response.flushBuffer();
                if (out != null) {
                    out.flush();
                    out.close();
                }
            } catch (final IOException e) {
                logger.error(e);
            }
        }
    }
  • 图片处理工具类
import sun.misc.BASE64Encoder;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Base64;

/**
 * @author lucien
 * @date 2023/7/22
 * @dec 描述
 */
public class ImageUtil {
    /**
     * BufferedImage 编码转换为 base64
     * @param bufferedImage
     * @return
     */
    public static String BufferedImageToBase64(BufferedImage bufferedImage) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();//io流
        //String imageFormat = getImageFormat(bufferedImage);
        try {
            ImageIO.write(bufferedImage, "png", baos);//写入流中
        } catch (IOException e) {
            e.printStackTrace();
        }
        byte[] bytes = baos.toByteArray();//转换成字节

        return "data:image/png;base64," + Base64.getEncoder().encodeToString(bytes);
    }

    // Method to get the image format (e.g., "png", "jpeg", "jpg") from a BufferedImage
    private static String getImageFormat(BufferedImage image) {
        for (String format : ImageIO.getWriterFormatNames()) {
            if (format.equalsIgnoreCase("png") || format.equalsIgnoreCase("jpeg") || format.equalsIgnoreCase("jpg")) {
                if (ImageIO.getImageWritersByFormatName(format).next().getDefaultWriteParam().canWriteCompressed()) {
                    return format;
                }
            }
        }
        return "png"; // Default to PNG format if no suitable format is found
    }



    /**
     * base64 编码转换为 BufferedImage
     * @param base64
     * @return
     */
    public  static BufferedImage base64ToBufferedImage(String base64) {
        String base64Image = "";
        try {
            // 弃用 svg
            //if(base64.contains("svg")){
            //    base64Image = base64.replace("image/svg+xml;base64,", "");
            //    //Base64.Decoder decoder = Base64.getDecoder();
            //    byte[] svgBytes = java.util.Base64.getDecoder().decode(base64Image);
            //    // Use Apache Batik to convert SVG to BufferedImage
            //    Transcoder transcoder = new PNGTranscoder();
            //    TranscoderInput transcoderInput = new TranscoderInput(new ByteArrayInputStream(svgBytes));
            //    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            //    TranscoderOutput transcoderOutput = new TranscoderOutput(outputStream);
            //    transcoder.transcode(transcoderInput, transcoderOutput);
            //
            //    // Convert the output stream to a BufferedImage
            //    ByteArrayInputStream imageInputStream = new ByteArrayInputStream(outputStream.toByteArray());
            //    return ImageIO.read(imageInputStream);
            //} else if(base64.contains("image/png;base64,")){
                base64Image = base64.replace("data:image/png;base64,", "").replace("image/png;base64,", "");
                // 这是从 app 录入的签章,先缩小
                byte[] bytes1 = java.util.Base64.getDecoder().decode(base64Image);
                ByteArrayInputStream bais = new ByteArrayInputStream(bytes1);
                BufferedImage read = ImageIO.read(bais);
                //return scale(read,0.3f);
                return read;
            //}


        } catch (IOException e) {
            e.printStackTrace();
        }
        //catch (TranscoderException e) {
        //    e.printStackTrace();
        //}
        return null;
    }

    /**
     * 将多个 base64 图片合并转换为 BufferedImage
     * @param base64Str
     * @return
     */
    public  static BufferedImage base64ToBufferedImage(ArrayList<String> base64Str) {
        if(base64Str.size() == 0){
            return null;
        }else if(base64Str.size() == 1){
            return base64ToBufferedImage(base64Str.get(0));
        } else {
            try {
                return combineImages(base64Str);
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            }
        }

    }

    // Method to combine multiple images into a single image
    private static BufferedImage combineImages(ArrayList<String> base64Str) throws IOException {
        int totalWidth = 0;
        int maxHeight = 0;

        // Find the total width and maximum height of the images
        for (String imageBase64 : base64Str) {
            BufferedImage image = base64ToBufferedImage(imageBase64);
            totalWidth += image.getWidth();
            maxHeight = Math.max(maxHeight, image.getHeight());
        }

        // Create a new combined image with the calculated dimensions
        BufferedImage combinedImage = new BufferedImage(totalWidth, maxHeight, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = combinedImage.createGraphics();

        int xOffset = 0;
        for (String imageBase64 : base64Str) {
            BufferedImage image = base64ToBufferedImage(imageBase64);
            g.drawImage(image, xOffset, 0, null);
            xOffset += image.getWidth();
        }

        g.dispose();
        // 缩放一半
        //return scale(combinedImage,0.1f);
        return combinedImage;
    }

    // 缩放图片,经过测试,有bug
    //public static BufferedImage scale(BufferedImage srcImageBuffer, float scale){
    //    //获取缩放后的宽高
    //    int width = (int) (srcImageBuffer.getWidth()*scale);
    //    int height = (int) (srcImageBuffer.getHeight()*scale);
    //    //调用缩放方法获取缩放后的图片
    //    Image img = srcImageBuffer.getScaledInstance(width , height, Image.SCALE_DEFAULT);
    //    //创建一个新的缓存图片
    //    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    //    //获取画笔
    //    Graphics2D graphics = image.createGraphics();
    //    graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
    //    //将Image对象画在画布上,最后一个参数,ImageObserver:接收有关 Image 信息通知的异步更新接口,没用到直接传空
    //    graphics.drawImage(img, 0, 0,width,height,null);
    //
    //    //一定要释放资源
    //    graphics.dispose();
    //    //获取到文件的后缀名
    //    return image;
    //
    //}

}

  • 注意:如果一定要用 svg 格式的图片,要用到 下面的 依赖来处理
            <dependency>
            <groupId>org.apache.xmlgraphics</groupId>
            <artifactId>batik-transcoder</artifactId>
            <version>1.7</version>
        </dependency>
  • 最后的效果图:


    image.png

4、总结

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容