公司出现一个业务,需要动态生成图片,并且要放到后端,不能前端生成。
在多个技术方案选型对比下,最终选择Graphics2D来画
使用上会复杂一点,但是可自定义程度会高一点,最开始有想过通过html页面来转化和浏览器截图模式,但是会增加额外的耦合,比如连接无头浏览器啥的。
Graphics2D是一个抽象类,并且由于Graphics2D它必须由子类针对不同的输出设备进行自定义,因此Graphics2D无法直接创建对象。相反,对象必须从另一个Graphics2D对象获取,由 创建, Graphics2D Component或从图像(如BufferedImage对象)获取
实现:
我定义好的工具类:
package com.solveyourworries.server.utils.posterUtil;
import com.solveyourworries.server.utils.posterUtil.bo.*;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public interface PosterUtils {
default void background(Graphics2D g2d, int width, int height) {
Color bg = new Color(255, 255, 255);
g2d.setColor(bg);
g2d.fillRect(0, 0, width, height);
}
default String saveImage(Graphics2D g2d, BufferedImage image) throws IOException {
//释放对象
g2d.dispose();
// 保存文件
File tempFile = File.createTempFile("share", "png");
ImageIO.write(image, "png", tempFile);
byte[] bytesArray = new byte[(int) tempFile.length()];
FileInputStream fis = new FileInputStream(tempFile);
fis.read(bytesArray);
fis.close();
tempFile.delete();
var res = Base64.encodeBase64String(bytesArray);
if (StringUtils.isNotBlank(res)) {
return "data:image/jpg;base64," + res.replaceAll("[\\s*\t\n\r]", "");
}
return null;
}
default void drawFont(Graphics2D g2d, FontBO fontBo) {
if (fontBo != null) {
g2d.setFont(fontBo.getFont());
g2d.setColor(fontBo.getColor());
g2d.drawString(fontBo.getMsgs(), fontBo.getX(), fontBo.getY());
}
}
default void drawImage(Graphics2D g2d, ImgBO imgBo) {
if (imgBo != null) {
g2d.drawImage(imgBo.getImage(), imgBo.getX(), imgBo.getY(), imgBo.getW(), imgBo.getH(), null);
}
}
default void drawLine(Graphics2D g2d, LineBO lineBO) {
if(lineBO == null) return;
g2d.setColor(lineBO.getColor());
if (lineBO.isDashed()) {
Stroke stroke = g2d.getStroke();
g2d.setStroke(LineBO.DEFAULT_STROKE);
g2d.drawLine(lineBO.getX1(), lineBO.getY1(), lineBO.getX2(), lineBO.getY2());
g2d.setStroke(stroke);
} else {
g2d.drawLine(lineBO.getX1(), lineBO.getY1(), lineBO.getX2(), lineBO.getY2());
}
}
default void drawRoundRect(Graphics2D g2d, RoundRectBO roundRectBO) {
if(roundRectBO == null) return;
g2d.setColor(roundRectBO.getColor());
if (!roundRectBO.isDashed()) {
g2d.drawRoundRect(roundRectBO.getX(), roundRectBO.getY(),
roundRectBO.getW(),
roundRectBO.getH(),
roundRectBO.getRadius(),
roundRectBO.getRadius());
} else {
Stroke stroke = g2d.getStroke();
g2d.setStroke(RoundRectBO.DEFAULT_DASH);
g2d.drawRoundRect(roundRectBO.getX(), roundRectBO.getY(),
roundRectBO.getW(),
roundRectBO.getH(),
roundRectBO.getRadius(),
roundRectBO.getRadius());
g2d.setStroke(stroke);
}
if (roundRectBO.getW() > 0) { // 上边距空白的宽度
int x = roundRectBO.getX();
int y = roundRectBO.getY() - 2;
int w = roundRectBO.getW();
int h = 4;
g2d.setColor(roundRectBO.getColor());
g2d.fillRect(x, y, w, h);
}
}
default void drawColorBG(Graphics2D g2d, ColorBgBO color) {
if(color == null) return;
g2d.setColor(color.getColor());
Composite composite = null;
if (color.isTransparence()) {
composite = g2d.getComposite();
g2d.setComposite(AlphaComposite.Src);
}
if (color.getRadius() == 0) {
g2d.fillRect(color.getX(), color.getY(), color.getW(), color.getH());
} else {
g2d.fill(new RoundRectangle2D.Float(color.getX(), color.getY(), color.getW(), color.getH(), color.getRadius(), color.getRadius()));
}
if (color.isTransparence()) {
g2d.setComposite(composite);
}
}
}
实体类:
package com.solveyourworries.server.utils.posterUtil.bo;
import lombok.Data;
import java.awt.*;
@Data
public class ColorBgBO implements IDrawBO {
private Color color;
private int w;
private int h;
private int x;
private int y;
private int radius;
private boolean transparence;
}
package com.solveyourworries.server.utils.posterUtil.bo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.awt.*;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FontBO implements IDrawBO {
private String msgs;
private Font font;
private Color color;
private int x;
private int y;
private boolean deleted = false;
}
package com.solveyourworries.server.utils.posterUtil.bo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.awt.*;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ImgBO implements IDrawBO {
private Image image;
private int x;
private int y;
private int w;
private int h;
}
package com.solveyourworries.server.utils.posterUtil.bo;
import lombok.Data;
import java.awt.*;
@Data
public class LineBO implements IDrawBO {
public static final Stroke DEFAULT_STROKE = new BasicStroke(2,
BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND,
3.5f,
new float[]{12, 6, 6, 6},
0f);
private Color color;
private int x1;
private int y1;
private int x2;
private int y2;
/**
* 是否是虚线
*/
private boolean dashed;
}
package com.solveyourworries.server.utils.posterUtil.bo;
import lombok.Data;
import java.awt.*;
@Data
public class RoundRectBO implements IDrawBO {
public static final Stroke DEFAULT_DASH = new BasicStroke(1,
BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND,
3.5f,
new float[]{4, 2,},
0f);
private int x;
private int y;
private int w;
private int h;
private Color color;
/**
* 是否为虚线
*/
private boolean dashed;
/**
* 圆角弧度
*/
private int radius;
}
最总效果:

Comments | NOTHING