com.google.zxing提供的定义白边大小试了好多次不起作用: hints.put(EncodeHintType.MARGIN, 0);//设置白边宽度,取值0~4,
本人的解决思路是:
建好二维码后,再建一个比二维码大一点的空白图片,然后把二维码图片加到空白图片上,这样白边大小就可以自己控制了。
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
public class PayQrcodeUtil {
private static final Log log = LogFactory.getLog(PayQrcodeUtil.class);
private static final int QRCOLOR = 0xFF000000; //默认是黑色
private static final int BGWHITE = 0xFFFFFFFF; //背景颜色
public static void main(String[] args)// throws WriterException
{
/* try {
BufferedImage image = ImageIO.read(new File("D:\\work\\tmp\\0.png"));
System.out.println(image);
} catch (IOException e ) {e.printStackTrace();}*/
try
{
//获取系统中可用的字体的名字
GraphicsEnvironment e = GraphicsEnvironment.getLocalGraphicsEnvironment();
String[] fontName = e.getAvailableFontFamilyNames();
for(int i = 0; i
log.info("font:"+fontName[i]);
}
// getLogoQRCode("http://www.163.com/", null, "设备编号:NO.8888801",550,550);
}
catch (Exception e)
{
e.printStackTrace();
}
}
/**
* 生成带二维码的支付卡台图片
* @param qrPic
* @param logoPic
*/
public static BufferedImage getQRCodeAndBaseImg(String qrUrl, String payNo, HttpServletRequest request, vvps vvps, int width, int height)
{
String content = qrUrl;
try
{
PayQrcodeUtil zp = new PayQrcodeUtil();
//先生成二维码
BufferedImage bim = zp.getQR_CODEBufferedImage(content, BarcodeFormat.QR_CODE, width, height, zp.getDecodeHintType());
//把二维码加到支付卡台图片上
return zp.addQRCode_BaseImg(bim, request, new LogoConfig(), vvps, payNo);
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
/**
* 将二维码添加到支付卡台图片上
* @param bim 二维码
* @param vvps 信息
*/
public BufferedImage addQRCode_BaseImg(BufferedImage bim, HttpServletRequest request, LogoConfig logoConfig, vvps vvps, String payNo)
{
try
{
/** 读取二维码图片,并构建绘图对象 */
BufferedImage Qrcode = bim;
Graphics2D QrcodeG = bim.createGraphics();
/** * 读取LOGO图片 */
String logoFilePath = request.getSession().getServletContext().getRealPath("/") + "image/yzglogo.jpg";
FileInputStream logofis = new FileInputStream(new File(logoFilePath));
BufferedImage logoImg = javax.imageio.ImageIO.read(logofis);
if(logoImg != null){
/** * 设置logo的大小,设置为二维码图片的20%,因为过大会盖掉二维码 */
int widthLogo = logoImg.getWidth(null)>Qrcode.getWidth()*2/10?(Qrcode.getWidth()*2/10):logoImg.getWidth(null),
heightLogo = logoImg.getHeight(null)>Qrcode.getHeight()*2/10?(Qrcode.getHeight()*2/10):logoImg.getWidth(null);
/** * logo放在中心 */
int x = (Qrcode.getWidth() - widthLogo) / 2;
int y = (Qrcode.getHeight() - heightLogo) / 2;
//开始绘制图片
QrcodeG.drawImage(logoImg, x, y, widthLogo, heightLogo, null);
QrcodeG.drawRoundRect(x, y, widthLogo, heightLogo, 15, 15);
QrcodeG.setStroke(new BasicStroke(logoConfig.getBorder()));
QrcodeG.setColor(logoConfig.getBorderColor());
QrcodeG.drawRect(x, y, widthLogo, heightLogo);
QrcodeG.dispose();
}
//给二维码图片加上白框
int whiteMarginX = 15;
int whiteMarginY = 15;
int widthQrcode = Qrcode.getWidth();
int heightQrcode = Qrcode.getWidth();
//生成空白的图片
BufferedImage qrcodeWhiteFrame = qrcodeAddFrame(Qrcode, whiteMarginX);
//把二维码加到空白的图片上
Graphics2D qrcodeFrameG = qrcodeWhiteFrame.createGraphics();
qrcodeFrameG.drawImage(Qrcode, whiteMarginX, whiteMarginY, widthQrcode, heightQrcode, null);
qrcodeFrameG.drawRoundRect(whiteMarginX, whiteMarginY, widthQrcode, heightQrcode, 15, 15);
qrcodeFrameG.setStroke(new BasicStroke(logoConfig.getBorder()));
qrcodeFrameG.setColor(logoConfig.getBorderColor());
qrcodeFrameG.drawRect(whiteMarginX, whiteMarginY, widthQrcode, heightQrcode);
qrcodeFrameG.dispose();
// File file = new File("d:\\work\\tmp\\logo.jpg");
// ImageIO.write(Qrcode, "jpg", file);
/** * 读取支付卡台背景图片 */
String baseFilePath = request.getSession().getServletContext().getRealPath("/") + "image/Base.jpg";
// String baseFilePath = "D:\\work\\workspace\\src\\main\\webapp\\image\\Base.jpg";
log.info(baseFilePath);
FileInputStream fis = new FileInputStream(new File(baseFilePath));
BufferedImage baseImg = javax.imageio.ImageIO.read(fis);//ImageIO.read(new File("D:\\Users\\WorkSpaces\\vpsOnlinePayService\\src\\main\\webapp\\images\\yzglogo.jpg"));
if(baseImg!=null){
/** 支付台卡图片,并构建绘图对象 */
Graphics2D baseG = baseImg.createGraphics();
/** 设置二维码的大小 */
int widthQrcodeFrame = qrcodeWhiteFrame.getWidth(),
heightQrcodeFrame = qrcodeWhiteFrame.getHeight();
/** * 二维码图片放在支付台卡中心 */
int x = (baseImg.getWidth() - qrcodeWhiteFrame.getWidth()) / 2 + 10;
int y = (baseImg.getHeight() - qrcodeWhiteFrame.getHeight()) / 2 + 30;
//开始绘制图片
baseG.drawImage(qrcodeWhiteFrame, x, y, widthQrcodeFrame, heightQrcodeFrame, null);
baseG.drawRoundRect(x, y, widthQrcodeFrame, heightQrcodeFrame, 15, 15);
baseG.setStroke(new BasicStroke(logoConfig.getBorder()));
baseG.setColor(logoConfig.getBorderColor());
baseG.drawRect(x, y, widthQrcodeFrame, heightQrcodeFrame);
//把编号添加到支付卡台上
if (StringUtil.isNotEmptyStr("12131231")) {
//画文字到新的面板
baseG.setColor(Color.WHITE);
//字体、字型、字号
baseG.setFont(new Font("Arial Unicode MS", Font.PLAIN, 45));
//画文字
baseG.drawString("NO. " + payNo, 80, 430);
}
//把姓名添加到支付卡台上
if (StringUtil.isNotEmptyStr("name")) {
//画文字到新的面板
baseG.setColor(Color.BLACK);
//字体、字型、字号
String fontPath = request.getSession().getServletContext().getRealPath("/") + "font/SIMSUN.TTC";
Font font = loadFont(fontPath, 50f);//调用
baseG.setFont(font);
// baseG.setFont(new Font("SansSerif", Font.PLAIN, 50));
//画文字
baseG.drawString("姓名 : " +"name", 160, 1780);
}
//把名称添加到支付卡台上
if (StringUtil.isNotEmptyStr("name")) {
//画文字到新的面板
baseG.setColor(Color.BLACK);
//字体、字型、字号
String fontPath = request.getSession().getServletContext().getRealPath("/") + "font/SIMSUN.TTC";
Font font = loadFont(fontPath, 50f);//调用
baseG.setFont(font);
// baseG.setFont(new Font("Serif", Font.PLAIN, 50));
//画文字
baseG.drawString("名称 : " + "name", 160, 1850);
}
baseG.dispose();
}
if(baseImg!=null){
baseImg.flush();
}
Qrcode.flush();
qrcodeWhiteFrame.flush();
// ByteArrayOutputStream baos = new ByteArrayOutputStream();
// baos.flush();
// File file = new File("d:\\work\\tmp\\1112.jpg");
// ImageIO.write(baseImg, "jpg", baos);
// ImageIO.write(baseImg, "jpg", file);
//二维码生成的路径,但是实际项目中,我们是把这生成的二维码显示到界面上的,因此下面的折行代码可以注释掉
//可以看到这个方法最终返回的是这个二维码的imageBase64字符串
//前端用 其中${imageBase64QRCode}对应二维码的imageBase64字符串
// ImageIO.write(image, "png", new File("C:/Users/xuxiaogen/Desktop/TDC-" + "test.png")); //TODO
// String imageBase64QRCode = Base64.encodeBase64String(baos.toByteArray());
// System.out.println(imageBase64QRCode);
// baos.close();
return baseImg;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
/** * 构建初始化二维码 * * @param bm * @return */
public BufferedImage fileToBufferedImage(BitMatrix bm)
{
BufferedImage image = null;
try
{
int w = bm.getWidth(), h = bm.getHeight();
image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < w; x++)
{
for (int y = 0; y < h; y++)
{
image.setRGB(x, y, bm.get(x, y) ? 0xFF000000 : 0xFFCCDDEE);
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
return image;
}
/** * 生成二维码bufferedImage图片 * * @param content * 编码内容 * @param barcodeFormat * 编码类型 * @param width * 图片宽度 * @param height * 图片高度 * @param hints * 设置参数 * @return */
public BufferedImage getQR_CODEBufferedImage(String content, BarcodeFormat barcodeFormat, int width, int height, Map
{
MultiFormatWriter multiFormatWriter = null;
BitMatrix bm = null;
BufferedImage image = null;
try
{
multiFormatWriter = new MultiFormatWriter();
// 参数顺序分别为:编码内容,编码类型,生成图片宽度,生成图片高度,设置参数
bm = multiFormatWriter.encode(content, barcodeFormat, width, height, hints);
bm = deleteWhite(bm);//删除白边
int w = bm.getWidth();
int h = bm.getHeight();
image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
// 开始利用二维码数据创建Bitmap图片,分别设为黑(0xFFFFFFFF)白(0xFF000000)两色
for (int x = 0; x < w; x++)
{
for (int y = 0; y < h; y++)
{
image.setRGB(x, y, bm.get(x, y) ? QRCOLOR : BGWHITE);
}
}
/* File file = new File("d:\\work\\tmp\\111.jpg");
ImageIO.write(image, "jpg", file);*/
}
catch (Exception e)
{
e.printStackTrace();
}
return image;
}
/** * 设置二维码的格式参数 * * @return */
public static Map
{
// 用于设置QR二维码参数
Map
// 设置QR二维码的纠错级别(H为最高级别)具体级别信息
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
// 设置编码方式
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
hints.put(EncodeHintType.MARGIN, 0);
hints.put(EncodeHintType.MAX_SIZE, 350);
hints.put(EncodeHintType.MIN_SIZE, 100);
return hints;
}
public static Font loadFont(String fontFileName, float fontSize) //第一个参数是外部字体名,第二个是字体大小
{
try
{
File file = new File(fontFileName);
FileInputStream aixing = new FileInputStream(file);
Font dynamicFont = Font.createFont(Font.TRUETYPE_FONT, aixing);
Font dynamicFontPt = dynamicFont.deriveFont(fontSize);
aixing.close();
return dynamicFontPt;
}
catch(Exception e)//异常处理
{
e.printStackTrace();
return new java.awt.Font("宋体", Font.PLAIN, 14);
}
}
//删除白边
public static BitMatrix deleteWhite(BitMatrix matrix) {
int[] rec = matrix.getEnclosingRectangle();
int resWidth = rec[2] + 1;
int resHeight = rec[3] + 1;
BitMatrix resMatrix = new BitMatrix(resWidth, resHeight);
resMatrix.clear();
for (int i = 0; i < resWidth; i++) {
for (int j = 0; j < resHeight; j++) {
if (matrix.get(i + rec[0], j + rec[1]))
resMatrix.set(i, j);
}
}
return resMatrix;
}
//给二维码图片加上白框
public static BufferedImage qrcodeAddFrame(BufferedImage qrcode, int widthFrame){
BufferedImage result = null;
try {
int width = qrcode.getWidth() + widthFrame * 2;
int height = qrcode.getHeight() + widthFrame * 2;
result = getWhiteQR_CODEBufferedImage("http://", BarcodeFormat.QR_CODE, width, height, getDecodeHintType());
} catch (Exception e) {
log.info("qrcodeAddFrame exception" + e);
}
return result;
}
//生成一张空白的二维码图片
public static BufferedImage getWhiteQR_CODEBufferedImage(String content, BarcodeFormat barcodeFormat, int width, int height, Map
{
MultiFormatWriter multiFormatWriter = null;
BitMatrix bm = null;
BufferedImage image = null;
try
{
multiFormatWriter = new MultiFormatWriter();
// 参数顺序分别为:编码内容,编码类型,生成图片宽度,生成图片高度,设置参数
bm = multiFormatWriter.encode(content, barcodeFormat, width, height, hints);
// bm = deleteWhite(bm);//删除白边
int w = bm.getWidth();
int h = bm.getHeight();
image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
// 开始利用二维码数据创建Bitmap图片,分别设为黑(0xFFFFFFFF)白(0xFF000000)两色
for (int x = 0; x < w; x++)
{
for (int y = 0; y < h; y++)
{
image.setRGB(x, y, BGWHITE);
}
}
}
catch (Exception e)
{
log.info("getWhiteQR_CODEBufferedImage exception" + e);
}
return image;
}
}
/*
class LogoConfig
{
// logo默认边框颜色
public static final Color DEFAULT_BORDERCOLOR = Color.WHITE;
// logo默认边框宽度
public static final int DEFAULT_BORDER = 2;
// logo大小默认为照片的1/5
public static final int DEFAULT_LOGOPART = 5;
private final int border = DEFAULT_BORDER;
private final Color borderColor;
private final int logoPart;
*//** * Creates a default config with on color {@link #BLACK} and off color * {@link #WHITE}, generating normal black-on-white barcodes. *//*
public LogoConfig()
{
this(DEFAULT_BORDERCOLOR, DEFAULT_LOGOPART);
}
public LogoConfig(Color borderColor, int logoPart)
{
this.borderColor = borderColor;
this.logoPart = logoPart;
}
public Color getBorderColor()
{
return borderColor;
}
public int getBorder()
{
return border;
}
public int getLogoPart()
{
return logoPart;
}
}*/