网站首页 > 技术文章 正文
一、背景
在之前的文章中有提到过说前端生成图片返回到后端:链接如下:
(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查询字体库列表,确认无误后重启服务即可
猜你喜欢
- 2024-10-16 【验证码逆向专栏】百某网数字九宫格验证码逆向分析
- 2024-10-16 jquery-利用canvas让图片旋转角度
- 2024-10-16 一文带你搞懂JS实现压缩图片 js压缩上传图片
- 2024-10-16 前端性能优化之请求优化 前端性能优化问题
- 2024-10-16 Serverless 实战:如何为你的头像增加点装饰?
- 2024-10-16 谈谈图片上传及canvas压缩的流程 js 图片压缩后上传
- 2024-10-16 妹子委婉地和男友说没钱了,结果差点换来一张luo照?
- 2024-10-16 Blob-对象介绍 对象object
- 2024-10-16 《小白HTML5成长之路51》canvas压缩图片上传功能的原理
- 2024-10-16 Dom-to-image截图将html生成图片 html2canvas截图
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- oraclesql优化 (66)
- 类的加载机制 (75)
- feignclient (62)
- 一致性hash算法 (71)
- dockfile (66)
- 锁机制 (57)
- javaresponse (60)
- 查看hive版本 (59)
- phpworkerman (57)
- spark算子 (58)
- vue双向绑定的原理 (68)
- springbootget请求 (58)
- docker网络三种模式 (67)
- spring控制反转 (71)
- data:image/jpeg (69)
- base64 (69)
- java分页 (64)
- kibanadocker (60)
- qabstracttablemodel (62)
- java生成pdf文件 (69)
- deletelater (62)
- com.aspose.words (58)
- android.mk (62)
- qopengl (73)
- epoch_millis (61)
本文暂时没有评论,来添加一个吧(●'◡'●)