主要使用了goole的zxing包,生成二维码比较简单,在常规二维码的基础上封装了可以在二维码中间添加图片的功能,代码都属于初步框架,功能有了,需要根据实际使用情况完善优化。


效果图:

114134955.png

114136437.png


源码如下:


package com.thatway.qr;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.geom.AffineTransform;
import java.awt.p_w_picpath.AffineTransformOp;
import java.awt.p_w_picpath.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Hashtable;

import javax.p_w_picpathio.ImageIO;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.EncodeHintType;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.ReaderException;
import com.google.zxing.Result;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

/**
* 2013-7-23
* @author thatway
* 二维码图片工具类
* 使用了两张工具图,路径分别是D:\qr\heihei.png  D:\qr\qr_bg.png
*/
public class QRUtil {

/**
 * 编码(将文本生成二维码)
*
* @param content 二维码中的内容
* @param width 二维码图片宽度
* @param height 二维码图片高度
* @param p_w_picpathPath 二维码图片存放位置
* @return 图片地址
*/
public static String encode(String content, int width, int height, String p_w_picpathPath) {

Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
// 设置编码类型为utf-8
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
// 设置二维码纠错能力级别为H(最高)
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);

BitMatrix byteMatrix = null;
try {
 // 生成二维码
 byteMatrix = new MultiFormatWriter().encode(content,
  BarcodeFormat.QR_CODE, width, height, hints);
 File file = new File(p_w_picpathPath);
 MatrixToImageWriter.writeToFile(byteMatrix, "png", file);
} catch (IOException e) {
 e.printStackTrace();
} catch (WriterException e) {
 e.printStackTrace();
}

return p_w_picpathPath;

}

/**
* 解码(读取二维码图片中的文本信息)
* @param p_w_picpathPath 二维码图片路径
* @return 文本信息
*/
public static String decode(String p_w_picpathPath) {
// 返回的文本信息
String content = "";

try {
 // 创建图片文件
 File file = new File(p_w_picpathPath);
 if (!file.exists()) {
 return content;
 }
 BufferedImage p_w_picpath = null;
 p_w_picpath = ImageIO.read(file);
 if (null == p_w_picpath) {
 return content;
 }
 // 解码
 LuminanceSource source = new BufferedImageLuminanceSource(p_w_picpath);
 BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
 Hashtable hints = new Hashtable();
 hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
 Result rs = new MultiFormatReader().decode(bitmap, hints);
 content = rs.getText();
} catch (IOException e) {
 e.printStackTrace();
} catch (ReaderException e) {
 e.printStackTrace();
}
return content;
}

/**
* 图片打水印
* @param bgImage 背景图
* @param waterImg 水印图
* @param uniqueFlag 生成的新图片名称中的唯一标识,用来保证生成的图片名称不重复,如果为空或为null,将使用当前时间作为标识
* @return 新图片路径
*/
public static String addImageWater(String bgImage, String waterImg ,String uniqueFlag) {

int x = 0;
int y = 0;
String newImgPath = "";

if(null == uniqueFlag){
 uniqueFlag = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
}else if(uniqueFlag.trim().length() < 1){
 uniqueFlag = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
}

try {
 File file = new File(bgImage);
 String fileName = file.getName();
 Image p_w_picpath = ImageIO.read(file);
 int width = p_w_picpath.getWidth(null);
 int height = p_w_picpath.getHeight(null);
 BufferedImage bufferedImage = new BufferedImage(width, height,
  BufferedImage.TYPE_INT_RGB);
 Graphics2D g = bufferedImage.createGraphics();
 g.drawImage(p_w_picpath, 0, 0, width, height, null);

 Image waterImage = ImageIO.read(new File(waterImg)); // 水印文件
 int width_water = waterImage.getWidth(null);
 int height_water = waterImage.getHeight(null);
 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,
  1));

 int widthDiff = width - width_water;
 int heightDiff = height - height_water;

 x = widthDiff / 2;
 y = heightDiff / 2;

 g.drawImage(waterImage, x, y, width_water, height_water, null); // 水印文件结束
 g.dispose();



 if(bgImage.contains(fileName)){
 newImgPath = bgImage.replace(fileName, uniqueFlag+fileName);
 }
 File newImg = new File(newImgPath);
 ImageIO.write(bufferedImage, "png", newImg);

 File waterFile = new File(waterImg);

 if(file.exists()){
 file.delete();
 }

 if(waterFile.exists()){
 waterFile.delete();
 }
} catch (IOException e) {
 e.printStackTrace();
}

return newImgPath;
}

/**
 * 图片缩放
* @param filePath 图片路径
* @param height 缩放到高度
* @param width 缩放宽度
* @param fill 比例足时是否填白 true为填白,二维码是黑白色,这里调用时建议设为true
* @return 新图片路径
*/
public static String resizeImg(String filePath, int width,int height, boolean fill) {

String newImgPath = "";

try {
 double ratio = 0; // 缩放比例
 File f = new File(filePath);
 String fileName = f.getName();
 BufferedImage bi = ImageIO.read(f);
 Image itemp = bi.getScaledInstance(width, height,BufferedImage.SCALE_SMOOTH);

 if(height != 0 && width!= 0 ){
 // 计算比例
 if ((bi.getHeight() > height) || (bi.getWidth() > width)) {
  if (bi.getHeight() > bi.getWidth()) {
  ratio = (new Integer(height)).doubleValue()
   / bi.getHeight();
  } else {
  ratio = (new Integer(width)).doubleValue() / bi.getWidth();
  }
  AffineTransformOp op = new AffineTransformOp(AffineTransform
   .getScaleInstance(ratio, ratio), null);
  itemp = op.filter(bi, null);
 }
 }

 if (fill) {
 BufferedImage p_w_picpath = new BufferedImage(width, height,
  BufferedImage.TYPE_INT_RGB);
 Graphics2D g = p_w_picpath.createGraphics();
 g.setColor(Color.white);
 g.fillRect(0, 0, width, height);
 if (width == itemp.getWidth(null)){
  g.drawImage(itemp, 0, (height - itemp.getHeight(null)) / 2,
   itemp.getWidth(null), itemp.getHeight(null),
   Color.white, null);
 }else{
  g.drawImage(itemp, (width - itemp.getWidth(null)) / 2, 0,
   itemp.getWidth(null), itemp.getHeight(null),
   Color.white, null);
 }

 g.dispose();
 itemp = p_w_picpath;
 }
 String now = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
 if(filePath.contains(fileName)){
 newImgPath = filePath.replace(fileName, now+fileName);
 }

 File newImg = new File(newImgPath);
 ImageIO.write((BufferedImage)itemp, "png", newImg);
} catch (IOException e) {
 e.printStackTrace();
}

return newImgPath;
}


/**
* 图片添加边框
* @param mainImgPath 要加边框的图片
* @param bgImgPath 背景图(实际上是将图片放在背景图上,只利用背景图的边框效果)
* @return 制作完成的图片路径
*/
public static String addWaterBorder(String mainImgPath,String bgImgPath){

String borderImgPath = "";

try {
 File f = new File(mainImgPath);

 BufferedImage bi;

 bi = ImageIO.read(f);

 //背景图长宽都比主图多4像素,这是因为我画的背景图的边框效果的大小正好是4像素,
 //主图周边比背景图少4像素正好能把背景图的边框效果完美显示出来
 int width = bi.getWidth();
 int height = bi.getHeight();

 int bgWidth = width+4;
 int bgHeight = height+4;

 String now = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
 borderImgPath = QRUtil.addImageWater(QRUtil.resizeImg(bgImgPath, bgHeight, bgWidth, true), mainImgPath,now);

 if(f.exists()){
 f.delete();
 }
} catch (IOException e) {
 e.printStackTrace();
}


return borderImgPath;
}

public static void main(String[] args) {

/**部分一开始***********生成常规二维码*************/
//二维码内容
String content = "介个是内容,
http://weibo.com/sdtvwp";
//二维码宽度
int width = 300;
//二维码高度
int height = 300;
//二维码存放地址
String p_w_picpathPath = "d:/qr/thatway_weibo.png";
//生成二维码,返回的是生成好的二维码图片的所在路径
String qrImgPath = QRUtil.encode(content, width, height, p_w_picpathPath);
/**部分一结束***********如果生成不带图片的二维码,到这步已经完成了*************/


/**部分二开始***********如果生成带图片但图片不带边框的二维码,解开这部分注释*************/

//缩放水印图片,为保证二维码的读取正确,图片不超过二维码图片的五分之一,这里设为六分之一
// String waterImgPath = QRUtil.resizeImg("d:/qr/heihei.jpg", width/6, height/6, true);
//
// //生成带有图片的二维码,返回的是生成好的二维码图片的所在路径
// String qrImage = QRUtil.addImageWater(qrImgPath, waterImgPath,"thatway");
/**部分二结束***********如果生成带图片但图片不带边框的二维码,解开这部分注释*************/


/**部分三开始(部分三不能和部分二共存)***********如果生成带图片且图片带边框的二维码,解开这部分注释****/

//缩放水印图片,为保证二维码的读取正确,图片不超过二维码图片的五分之一,这里设为六分之一
//d:/qr/heihei.png 这图片是要加在二维码中间的那张图
String waterImgPath = QRUtil.resizeImg("d:/qr/heihei.png", width/6, height/6, true);

//d:/qr/qr_bg.png这种图片是自己画好边框光晕效果的边框底图
String tempImg = QRUtil.addWaterBorder(waterImgPath, "d:/qr/qr_bg.png");

//生成带有边框图片的二维码,返回的是生成好的二维码图片的所在路径
String qrImage = QRUtil.addImageWater(qrImgPath, tempImg,"thatway");
/**部分三结束***********如果生成带图片且图片带边框的二维码,解开这部分注释*************/



/*******测试一下解码******/
System.out.println(QRUtil.decode(qrImage));;

}

}



需要的图片和zxing包在附件中,zxing包修改过字符编码的源码,如果自己去google下载的话,需要改一下com.google.zxing.qrcode.encoder.Encoder类中: static final String DEFAULT_BYTE_MODE_ENCODING = "UTF-8"; //默认是iso8859-1,不支持中文

本文出自 “ThatWay” 博客,请务必保留此出处http://thatway.blog.51cto.com/4815281/1255224