计算机系统应用教程网站

网站首页 > 技术文章 正文

记一次后端生成图片返回前端预演 后端动态生成前端页面

btikc 2024-10-16 08:18:10 技术文章 7 ℃ 0 评论

一、背景

在之前的文章中有提到过说前端生成图片返回到后端:链接如下:

(html2canvas简明使用教程、脚本打印页面指定区域内容、Java条形码标签生成并打印示例)。

除此之外最近有需求可能会用到后端生成图片返回前端,于是写一个demo先记录,等正式使用时再进行完善。


二、整体实现

2.1、实现思路

① 创建图片缓冲区

② 使用Graphics2D来绘制图形

③ 使用ImageIO来保存为图片(可以时临时文件,也可以是保存到本地)

④ 转成文件为Base64数据返回给前端


2.2、附上核心代码部分


     import sun.misc.BASE64Encoder;
     import javax.imageio.ImageIO;
     import java.awt.*;
     import java.awt.image.BufferedImage;
     import java.io.File;
     import java.io.FileInputStream;
     import java.io.FileOutputStream;
     import java.io.IOException;
     /**  
     * @author XA  
     * date 2020/12/30 20:20 
     * description:  后端生成图片返回给前端Base64
     */
 
        public class BuildImg {
 
            public static void main(String[] args) {
                /* 图片宽 */
                int width = 820;
                /* 图片高 */
                int height = 600;
                String titleStr = "导出表格图片测试";
                String zhangdanzhouqiStr = "2020年12月30日20:00:35";
                String zhangdantianshuStr = "666";
                String bengedinggonglvStr = "200";
                String bengbianpingjienengyunxingyongdianliangStr = "100";
                String dianjiaStr = "24";
                String pingjunjienenglvStr = "50%";
                String daizhifujingeStr = "1000元";
                String bengyunxingzongshichangStr = "656";
                String benggongpingyongdianliangStr = "13";
                String jieshengdianliangStr = "77";
                String jieshengjineStr = "1000元";
 
                /* 得到图片缓冲区 */
                /* INT精确度达到一定,RGB三原色,高度70,宽度150 */
                BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
 
                /* 得到它的绘制环境(这张图片的笔) */
                Graphics2D g2 = (Graphics2D) bi.getGraphics();
                /* 设置背景颜色 */
                g2.setColor(Color.WHITE);
                /* 填充整张图片(其实就是设置背景颜色) */
                g2.fillRect(0, 0, width, height);
                /* 设置字体颜色 */
                g2.setColor(Color.black);
                /* 边框加粗 */
                g2.setStroke(new BasicStroke(2.0f));
                /* 画边框就是黑边框 */
                g2.drawRect(1, 1, width - 2, height - 2);
 
                /* 从上到下第二个横线 */
                g2.drawLine(0, 80, 820, 80);
                /* 边框不需要加粗 */
                g2.setStroke(new BasicStroke(0.0f));
                /* 从上到下第三个横线 */
                g2.drawLine(0, 154, 820, 154);
                /* 从上到下第四个横线 */
                g2.drawLine(0, 228, 820, 228);
                /* 从上到下第5个横线 */
                g2.drawLine(0, 302, 820, 302);
                /* 从上到下第6个横线 */
                g2.drawLine(0, 376, 820, 376);
                /* 从上到下第7个横线 */
                g2.drawLine(0, 451, 820, 451);
                /* 从上到下第8个横线 */
                g2.drawLine(0, 525, 820, 525);
 
                /* 从左到右第二个竖线 */
                g2.drawLine(180, 80, 180, 600);
                /* 从左到右第三个竖线 */
                g2.drawLine(390, 154, 390, 451);
                /* 从左到右第四个竖线 */
                g2.drawLine(574, 154, 574, 451);
 
                /* 设置标题的字体,字号,大小 */
                Font titleFont = new Font("宋体", Font.BOLD, 30);
                g2.setFont(titleFont);
                String markNameStr = titleStr;
                /* 抗锯齿 */
                g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                /* 计算文字长度,计算居中的X点坐标 */
                FontMetrics fm = g2.getFontMetrics(titleFont);
                int titleWidth = fm.stringWidth(markNameStr);
                /* 向左移动35个单位以居中 */
                int titleWidthX = (width - titleWidth) / 2 - 35;
                g2.drawString(markNameStr, titleWidthX, 45);
 
                g2.setFont(new Font("宋体", Font.BOLD, 20));
                g2.drawString("时间", 33, 125);                
                g2.drawString(zhangdanzhouqiStr, 230, 125);
 
                g2.drawString("数量", 33, 200);                
                g2.drawString(zhangdantianshuStr, 230, 200);
                g2.drawString("效能", 33, 274);            
                g2.drawString(bengedinggonglvStr, 230, 274);
 
                g2.drawString("用量", 33, 338);
                g2.drawString("重量", 33, 360);       
                g2.drawString(bengbianpingjienengyunxingyongdianliangStr, 230, 345);
 
                g2.drawString("单价", 33, 423);                
                g2.drawString(dianjiaStr, 230, 423);    
 
                g2.drawString("平均值", 33, 496);      
                g2.drawString(pingjunjienenglvStr, 230, 496);
 
                /* 待支付金额 */
                g2.drawString("金额", 33, 568);
                /* 待支付金额的值 */
                g2.drawString(daizhifujingeStr, 230, 568);
 
                g2.drawString("总时长", 420, 200);                
                g2.drawString(bengyunxingzongshichangStr, 630, 200);
 
                g2.drawString("数值", 420, 265);
                g2.drawString("数量", 420, 287);            
                g2.drawString(benggongpingyongdianliangStr, 630, 274);
 
                g2.drawString("量", 420, 348);        
                g2.drawString(jieshengdianliangStr, 630, 345);
 
                g2.drawString("费用", 420, 423);        
                g2.drawString(jieshengjineStr, 630, 423);
 
                /* 释放对象 */
                g2.dispose();
                try {
                    /* 创建临时文件用以保存图片数据 */
                    File file1 = null;
                    file1 = File.createTempFile("temp", null);
 
                    /* 保存图片 JPEG表示保存格式 */
                    ImageIO.write(bi, "JPEG", file1);
                    /* 也可以保存为本地文件 */
                    /* ImageIO.write(bi, "JPEG", new FileOutputStream("D:/a.jpg")); */
                    String imgBase64 = getBase64(file1);
                    System.out.println(imgBase64);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
 
            /**
         * 功能描述: 获取文件的Base64编码
         * Param: [file] 
         * Return: java.lang.String
         */
 
            private static String getBase64(File file){
                String imgStr = "";
                try {
                    FileInputStream fis = new FileInputStream(file);
                    byte[] buffer = new byte[(int) file.length()];
                    int offset = 0;
                    int numRead = 0;
                    while (offset < buffer.length && (numRead = fis.read(buffer, offset, buffer.length - offset)) >= 0) {
                        offset += numRead;
                    }
 
                    if (offset != buffer.length) {
                        throw new IOException("Could not completely read file "
                                + file.getName());
                    }
                    fis.close();
                    BASE64Encoder encoder = new BASE64Encoder();
                    imgStr = encoder.encode(buffer);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return "data:image/jpeg;base64,"+imgStr;
            }
 
        }

Java


PS: 如果想要插入图片也可以使用下面的方式


        /* 写入图片 */
        List<String> ossList = new ArrayList<>();
        ossList.add("http://XXXX623133213081.jpg");
        ossList.add("http://XXX23133220123.jpg");
        ossList.add("http://XXX0210623143822891.jpg");
        ossList.add("http://XXX213081.jpg");
        ossList.add("http://XXX33220123.jpg");
        ossList.add("http://XXX23143822891.jpg");

        for(int i=0;i<ossList.size();i++){
            /* 可以读取磁盘文件 */
            /* InputStream inputStream = new FileInputStream(new File("D:/" + (ii+1) + ".jpg")); */
            /* 也可以是一个网络路径 */
            InputStream inputStream = getImageStream(ossList.get(i));
            BufferedImage bufferedImage = ImageIO.read(inputStream);
            g2.drawImage(bufferedImage,5,i * 810 + 5,590,800,null);
        }

Java

 
   /**
     * 功能描述: 根据图片的在线地址获取InputStream
     * Param: [url]
     * Return: java.io.InputStream
     */
    private static InputStream getImageStream(String url) {
        try {
            HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
            connection.setReadTimeout(5000);
            connection.setConnectTimeout(5000);
            connection.setRequestMethod("GET");
            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                InputStream inputStream = connection.getInputStream();
                return inputStream;
            }
        } catch (IOException e) {
            System.out.println("获取网络图片出现异常,图片路径为:" + url);
            e.printStackTrace();
        }
        return null;
    }

Java


三、效果展示


3.1、拿到Base64数据

大致如下:data:image/jpeg;base64,/9j/4AAQSkZJRgABAgAAAQABAAD/2wBDAAgGBXXX...


3.2、在前端中显示效果如下




四、后记

① 这只是一个雏形记录,不代表最终实现

② 这之中会有很多坏味道,比如Base64的传输数据量大的问题

③ 临时记录一下,如果最终使用,或有更好的方式持续更新


五、写在最后面的话


5.1、数据传输方案的考量

正式上线之后,考虑到传输性能和存储等因素,并没有使用base64作为数据媒介

5.2、最终处理方案

最终的处理方式为:上传到oss,然后返回路径给到前端处理

5.3、外文兼容性问题

在地址的部分因为我们有泰文,所以遇到了不能泰文的问题,

检查之后发现是定义字体时选了宋体导致的。最终解决是在设置字体时不明确定义,

使用jdk的默认字体即可!

附:JDK在声明字体时的部分源码

     public Font(String name, int style, int size) {
        this.name = (name != null) ? name : "Default";
        this.style = (style & ~0x03) == 0 ? style : 0;
        this.size = size;
        this.pointSize = size;
    }

Java

5.4、部署到Centos上字体问题

① 在确认文件格式无误后,部署到线上环境,发现及时使用了默认字体也会出现:

泰文无法解析出来!!!

不用想也是字体库的问题,下面附解决方案。

② 打包window上的字体并上传

文件位于:C:\Windows\Fonts

把它打包成zip文件,上传到:/usr/share/fonts/

③ 建立字体索引并更新字体缓存

mkfontscale
mkfontdir
fc-cache

④ 使用 fc-list查询字体库列表,确认无误后重启服务即可

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表