需求:微信程序项目要生成带有二维码的图片(自己生成了一个二维码然后根据背景图片合成了)
本来想返回文件流,但是想了一下还得有个页面,就先返回页面,然后页面加载完之后ajax请求后端的图片了,缺点就是加载图片会比较慢,要是在前端合成的话,加载很快,但是二维码和背景图是两张图片,客户要一张的,网上找了找JS合成的,又遇到另外一个问题,用微信开发者工具本地测试没问题,但是放到服务器上面背景图不能用在线图片,得缓存到本地,想想算了,还是后端合成吧
页面内容,简单展示一下,就一个div
ajax请求
$().ready(function(){
$.ajax({
url:".../share/shareImage",//你的后台合成路径
dataType:"json",
success:function(data){
$("#image").attr("src","data:image/png;base64,"+data);
}
})
})
二、后端java代码
先返回了一个界面
@RequestMapping("/share")
public String share(HttpServletRequest request) throws Exception {
return "my/share";
}
2.处理ajax请求
```
@RequestMapping("/share/shareImage")
@ResponseBody
public byte[] share(HttpServletRequest request,HttpServletResponse response) throws Exception {
//生成二维码
String url = 二维码路径
//二维码创建路径
String path = request.getServletContext().getRealPath("WEB-INF/template/erweima.jpg");
//生成二维码图片
File file = new File(path);
//二维码工具类
QRCodeUtil.encodeQRCode(url, file, 1, file);
//读取二维码图片
BufferedImage mm = ImageIO.read(file);
//创建模板图片
BufferedImage img = new BufferedImage(1024, 1607, BufferedImage.TYPE_INT_RGB);
//读取背景图片
//qiniuyun图片
String backGround = 网络图片地址url
BufferedImage bg = ImageIO.read(new URL(backGround));
//开启画图
Graphics g = img.getGraphics();
//1024,1607表示图片大小,0, 0, 表示图片位置
g.drawImage(bg.getScaledInstance(1024,1607, Image.SCALE_DEFAULT), 0, 0, null); // 绘制缩小后的图
g.drawImage(mm.getScaledInstance(230,230, Image.SCALE_DEFAULT), 401, 950, null);
String img2 = request.getServletContext().getRealPath("WEB-INF/template/shareImage.jpg");
ImageIO.write(img, "jpg", new File(img2));
g.dispose();
InputStream fis = new FileInputStream(new File(img2));
ByteArrayOutputStream bos = new ByteArrayOutputStream(1000);
byte[] b = new byte[1024];
int len = -1;
while((len = fis.read(b)) != -1) {
bos.write(b, 0, len);
}
fis.close();
bos.close();
/*
优化了下,前端img 可以直接设置属性src的路径是接口路径,使用下面注释的这部分
代码,可以直接返回图片,前端不用处理了
OutputStream os = response.getOutputStream();
IOUtility.copy(bos.toByteArray(), os);
IOUtility.shutdownStream(os);
return null;
*/
return bos.toByteArray();
}
```
二维码工具类
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.imageio.ImageIO;
import com.swetake.util.Qrcode;
import jp.sourceforge.qrcode.QRCodeDecoder;
import jp.sourceforge.qrcode.data.QRCodeImage;
public class QRCodeUtil {
/**
* 解码二维码
*
* @param imageFile
* 要解码的二维码图片文件
* @return 解码出的二维码信息
* @throws IOException
*/
public static String decodeQRCode(File imageFile) throws IOException {
QRCodeDecoder decoder = new QRCodeDecoder();
BufferedImage image = null;
try {
image = ImageIO.read(imageFile);
String decodedData = new String(decoder.decode(new J2SEImage(image)), "GBK");
return decodedData;
} catch (Exception e) {
throw new IOException(e);
}
}
/**
* 二维码编码 level 1可以支持61个汉字183个字节 level 2可以支持333个汉字999个字节
*
* @param text
* 要编入二维码的文本内容
* @param target
* 二维码生成后要存放的文件
* @param level
* 编码级别,级别越高存储的信息也越多
* @throws IOException
*/
public static void encodeQRCode(String text, File target, int level, File logo) throws IOException {
try {
encodeQRCode(text, new FileOutputStream(target), level, new FileInputStream(logo));
} catch (FileNotFoundException e) {
// ignore it
}
}
/**
* 二维码编码 level 1可以支持61个汉字183个字节 level 2可以支持333个汉字999个字节
*
* @param text
* 要编入二维码的文本内容
* @param os
* 二维码生成后要输出的流
* @param level
* 编码级别,级别越高存储的信息也越多
* @param logo
* 要生成中间logo的图片输入流
* @throws IOException
*/
public static void encodeQRCode(String text, OutputStream os, int level, InputStream logo) throws IOException {
try {
int version = 0;
int limit = 0;
int size = 0;
int logoSize = 0;
if (level == 1) { // 45
version = 7;
limit = 183;
size = 67 + 12 * (version - 1);
logoSize = 39;
} else if (level == 2) { // 65
version = 12;
limit = 320;
size = 67 + 12 * (version - 1);
logoSize = 55;
} else if (level == 3) { // 97
version = 20;
limit = 999;
size = 67 + 12 * (version - 1);
logoSize = 75;
} else
throw new IOException("不支持的level:" + level);
Qrcode qrcode = new Qrcode();
/*** 表示的字符串长度: 容错率(ECC) 显示编码模式(EncodeMode)及版本(Version)有关 ***/
/*
* 二维码的纠错级别(排错率),共有四级:可选L(7%)、M(15%)、Q(25%)、H(30%)(最高H)。
* 纠错信息同样存储在二维码中,纠错级别越高,纠错信息占用的空间越多,那么能存储的有用信息就越少,对二维码清晰度的要求越小
*/
qrcode.setQrcodeErrorCorrect('M');
// 编码模式:Numeric 数字, Alphanumeric 英文字母,Binary 二进制,Kanji 汉字(第一个大写字母表示)
qrcode.setQrcodeEncodeMode('B');
/*
* 二维码的版本号:也象征着二维码的信息容量;二维码可以看成一个黑白方格矩阵,版本不同,矩阵长宽方向方格的总数量分别不同。
* 1-40总共40个版本,版本1为21*21矩阵,版本每增1,二维码的两个边长都增4; 版本2
* 为25x25模块,最高版本为是40,是177*177的矩阵;
*/
qrcode.setQrcodeVersion(version);
byte[] d = text.getBytes("utf-8");// text.getBytes("GBK");
BufferedImage bi = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB);
// createGraphics
Graphics2D g = bi.createGraphics();
// set background
g.setBackground(Color.WHITE);
g.clearRect(0, 0, size, size);
g.setColor(Color.BLACK);
if (d.length > 0 && d.length < limit) {
boolean[][] b = qrcode.calQrcode(d);
for (int i = 0; i < b.length; i++) {
for (int j = 0; j < b.length; j++) {
if (b[j][i]) {
g.fillRect(j * 3 + 2, i * 3 + 2, 3, 3);
}
}
}
} else
throw new IOException("要编入二维码的信息过长,限制字节数:" + limit);
if (logo != null) {
Image img = ImageIO.read(logo);
int xy = (size - logoSize) / 2;
g.drawImage(img, xy, xy, logoSize, logoSize, null);
}
g.dispose();
bi.flush();
ImageIO.write(bi, "png", os);
} catch (Exception e) {
throw new IOException(e);
}
}
}
class J2SEImage implements QRCodeImage {
BufferedImage image;
public J2SEImage(BufferedImage image) {
this.image = image;
}
public int getWidth() {
return image.getWidth();
}
public int getHeight() {
return image.getHeight();
}
public int getPixel(int x, int y) {
return image.getRGB(x, y);
}
}
以上就可以了,很多地方不是很明白,以后再慢慢搞吧