如题 JSON参数画图生成图片的一个工具 , 场景: 用于卡片制作, 学生证, 毕业证等各种证书的下载打印等业务, 以及礼品卡的制作, 小程序页等转图片后 分享朋友圈等等....
不多说, 直接上石马 :
DrawingRender.java 去年写的工具...今天被同事用到了, 并且根据他提了一个居中的需求, 我做了一下增强支持ElKit.eval表达式了
package com.momathink.common.plugin.draw;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jfinal.kit.ElKit;
import com.jfinal.kit.Kv;
import com.jfinal.kit.PathKit;
import com.jfinal.kit.StrKit;
import com.jfinal.render.Render;
import com.jfinal.render.RenderException;
/**
* 卡片制作
*
* @author 杜福忠 2017-9-5
*/
public class DrawingRender extends Render {
protected BufferedImage image = null;
protected String cardName = null;
public DrawingRender(String json) {
imageByJson(JSON.parseObject(json));
}
@Override
public void render() {
response.setHeader("Content-Disposition", getFilename(request));
response.setHeader("Pragma","no-cache");
response.setHeader("Cache-Control","no-cache");
response.setDateHeader("Expires", 0);
response.setContentType("image/jpeg");
ServletOutputStream sos = null;
try {
sos = response.getOutputStream();
ImageIO.write(image, "jpeg", sos);
} catch (IOException e) {
if (getDevMode()) {
throw new RenderException(e);
}
} catch (Exception e) {
throw new RenderException(e);
} finally {
if (sos != null) {
try {sos.close();} catch (IOException e) {e.printStackTrace();}
}
}
}
/**
* 解析 卡片
*
* <pre>
{
"name":"卡片生成后的名称"
"path":"背景图片地址"
"list":[{
"type":"image",
"path" : "图片地址"
"x" : "50",
"y" : "50"
},{
"type":"word",
"value" : "字体内容",
"x" : "100",
"y" : "100"
"font" : {
"name" : "Dialog、DialogInput、Monospaced、Serif 或 SansSerif,空为默认字体",
"style" : "0,1,2",
"size" : "1-70"
},
"color" : {
"r":"0到255",
"g":"0到255",
"b":"0到255",
}
}
]
}
* </pre>
*
*/
protected BufferedImage imageByJson(JSONObject configure) {
String basepath = PathKit.getWebRootPath();
BufferedImage background = getImage(basepath + configure.getString("path"));
if (background == null) {
throw new NullPointerException("没有找到 背景图片");
}
cardName = isNull(configure.getString("name"), "Card");
// 默认的验证码大小
Integer width = background.getWidth();
Integer height = background.getHeight();
image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 获取图形上下文
Graphics2D g = image.createGraphics();
//呈现质量和总时间/质量折衷的控制
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
// 图形抗锯齿
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// 字体抗锯齿
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
// 设定默认背景色
//g.setColor(new Color(255, 255, 255));
//g.fillRect(0, 0, width, height);
//背景图
g.drawImage(background, 0, 0, width, height, imageobserver);
//字符内容处理
//设定字体颜色
g.setColor(new Color(0, 0 , 0));
// 处理单元素
try {
setList(configure, basepath, g);
} catch (Exception e) {
print(e);
}
// 销毁图像
g.dispose();
return image;
}
/**
* @param configure
* @param basepath
* @param g
*/
protected void setList(JSONObject configure, String basepath, Graphics2D g) {
// list
JSONArray jsonArray = configure.getJSONArray("list");
for (Integer i = 0; i < jsonArray.size(); i++) {
JSONObject element = jsonArray.getJSONObject(i);
String type = element.getString("type");
if ("word".equals(type)) {
// 文字
String value = element.getString("value");
if (StrKit.isBlank(value)) {
continue;
}
String x = element.getString("x");
String y = element.getString("y");
// 文字
JSONObject color = element.getJSONObject("color");
Integer cr = color.getInteger("r");
Integer cg = color.getIntValue("g");
Integer cb = color.getIntValue("b");
// 字体样式
JSONObject font = element.getJSONObject("font");
String fontname = font.getString("name");
Integer fontStyle = font.getIntValue("style");
String fontSize = font.getString("size");
// 渲染
setStr(g, cr, cg, cb, fontname, fontStyle, fontSize, value, x, y);
} else if ("image".equals(type)) {
// 图片
String path = element.getString("path");
if (StrKit.isBlank(path)) {
continue;
}
String x = element.getString("x");
String y = element.getString("y");
// 渲染
setImage(g, basepath + path, x, y);
}
}
}
/**
* //设定字体 //设定字体颜色 //设定字
*/
protected void setStr(Graphics2D g, Integer colorR, Integer colorG, Integer colorB,
String fontname, Integer fontStyle, String fontSize, String v, String x, String y) {
colorR = isNull(colorR, 0);
colorG = isNull(colorG, 0);
colorB = isNull(colorB, 0);
fontname = isNull(fontname, null);
fontStyle = isNull(fontStyle, 1);
fontSize = isNull(fontSize, "24");
int centerX = image.getWidth() / 2;
x = isNull(x, "0");
y = isNull(y, "0");
try {
Integer fontSizei = ElKit.eval(fontSize,
Kv.by("length", v.length()).set("centerX", centerX));
Font font = new Font(fontname, fontStyle, fontSizei);
FontMetrics fontMetrics = g.getFontMetrics(font);
int textWidth = fontMetrics.stringWidth(v);
Kv data = Kv.by("length", v.length()).set("fontSize", fontSizei).set("str", v)
.set("centerX", centerX).set("textWidth", textWidth)
.set("center", centerX - textWidth / 2);
Integer xi = ElKit.eval(x, data);
Integer yi = ElKit.eval(y, data);
g.setColor(new Color(colorR, colorG, colorB));
g.setFont(font);
g.drawString(v, xi, yi);
} catch (Exception e) {
print(e);
}
}
/**
* 画图片
*
* @param g
* @param path
* @param x
* @param y
*/
protected void setImage(Graphics2D g, String path, String x, String y) {
x = isNull(x, "0");
y = isNull(y, "0");
int centerX = image.getWidth() / 2;
try {
BufferedImage img = getImage(path);
Kv data = Kv.by("img", img).set("context", image).set("center",
centerX - img.getWidth() / 2);
Integer xi = ElKit.eval(x, data);
Integer yi = ElKit.eval(y, data);
g.drawImage(img, xi, yi, imageobserver);
} catch (Exception e) {
print(e);
}
}
protected Integer isNull(Integer val, Integer df) {
return val != null ? val : df;
}
protected String isNull(String val, String df) {
return StrKit.notBlank(val) ? val : df;
}
protected BufferedImage getImage(String imgPath) {
try {
return ImageIO.read(new FileInputStream(imgPath));
} catch (IOException e) {
print(e);
}
return null;
}
protected ImageObserver imageobserver = new ImageObserver() {
@Override
public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
return true;
}
};
protected String getFilename(HttpServletRequest request) {
try {
String agent = request.getHeader("USER-AGENT");
if (agent.toLowerCase().indexOf("firefox") > 0) {
cardName = new String(cardName.getBytes("utf-8"), "iso-8859-1");
} else {
cardName = URLEncoder.encode(cardName, "UTF-8");
}
} catch (UnsupportedEncodingException e) {
print(e);
}
return "attachment; filename=" + cardName + ".jpg";
}
protected void print(Exception e) {
e.printStackTrace();
}
}上面依赖的JAR包 有fastjson解析工具
工具完成, 开始使用:
/**
* 工具
*
* @author 杜福忠 2018-09-07 14:02:52
*
*/
@Clear()
public class KitController extends Controller {
/**
* 画板 /api/kit/drawing?data=JSON
* 也可使用 cache=key
*/
public void drawing() {
String data = getPara("data");
if (data == null) {
data = ConfigKit.getCache().get("apiKitCache", getPara("cache"));
}
render(new DrawingRender(data));
}
/**
* 画板缓存参数 /api/kit/cache?data=JSON
* 返回缓存key
*/
public void cache() {
String data = getPara("data");
String key = StrKit.getRandomUUID();
ConfigKit.getCache().put("apiKitCache", key, data);
renderJson(key);
}
}上面依赖的JAR包 有ehcacheh缓存工具
用法:
如调试参数时使用的例子drawing.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JSON画图工具</title>
<style type="text/css">
.container {
display: table;
width: 80%;
}
.container .left,
.container .right {
display: table-cell;
}
.container .left {
width: 20%;
}
.container .right {
width: 80%;
}
</style>
</head>
<body>
<div class="container">
<div class="left">
<textarea rows="40" cols="80">
{
"name":"卡片生成后的名称"
"path":"/背景图片地址"
"list":[{
"type":"image",
"path" : "/图片地址"
"x" : "50",
"y" : "50"
},{
"type":"word",
"value" : "字体内容",
"x" : "100 center是居中",
"y" : "100"
"font" : {
"name" : "Dialog、DialogInput、Monospaced、Serif 或 SansSerif,空为默认字体",
"style" : "0,1,2",
"size" : "1-70"
},
"color" : {
"r":"0到255",
"g":"0到255",
"b":"0到255",
}
}
]
}
</textarea>
</div>
<div class="right">
<img alt="预览图" src="" >
</div>
</div>
<script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script>
<script type="text/javascript">
$("textarea").keyup(function(){
var json = $("textarea").val();
$("img").attr("src", "/api/kit/drawing?data=" + json);
});
</script>
</body>
</html>上面例子需要 自己调整一下参数 根据自己情况来写, 有说用canvas画的, 我反手就是一下兼容性, 易用性, 普适性啦... 23333 喜欢就好~
再比如小程序中的调用方式:
var jsonData = `
JSON 参数此处 省略
`;
wx.request({ url: 域名+'/api/kit/cache', //仅为示例,并非真实的接口地址
data: {data:jsonData},success: function(res) {
// 此处 修改一下 IMG 的 SRC=域名+"/api/kit/drawing?cache="+res.data 即可
// 或者调用下载API
}
})预览一下:

点个赞呗~