2.x使用示例

一灰灰blogQuickMedia约 4851 字大约 16 分钟

qrcode-plugin 2.0使用教程

本文中所有示例case,均可在测试用例中获取: QrCodeGenUserGuide.javaopen in new window

1. 功能介绍

大的方面主要分为二维码的生成和解析两块,qrcode-plugin生成二维码的功能上,做了深度的开发定制,目前基本上可以覆盖二维码的各种生成场景

    • 支持logo
    • 支持logo样式 (圆角logo, 边框, 圆形logo)
    • 支持二维码颜色设置
    • 支持二维码圆角
    • 支持探测图形颜色设置
    • 支持探测图形选用图片
    • 支持背景图,三种背景样式
    • 支持背景图圆角设置
    • 支持base64格式的二维码图片
    • 支持二维码定制绘制信息样式
    • 三角形
    • 矩形
    • 五边形 (五角星待支持)
    • 六边形
    • 八边形
    • 自定义图片
    • 文字二维码
    • 前置图支持

2. 使用尝鲜

- 环境配置

请直接使用中央仓库引入最新依赖

<!-- https://mvnrepository.com/artifact/com.github.liuyueyi.media/qrcode-plugin -->
<dependency>
    <groupId>com.github.liuyueyi.media</groupId>
    <artifactId>qrcode-plugin</artifactId>
    <version>2.5.6</version>
</dependency>

- 配置介绍

使用qrcode-plugin插件生成二维码是一个非常简单的事情,通过一些基本的参数来控制输出二维码样式,一个链式调用即可完成

参数说明

二维码图片的基本参数

/**
 * 内容
 */
private String msg;

/**
 * 输出图片宽
 */
private Integer w;


/**
 * 输出图片高
 */
private Integer h;


/**
 * 内容编码, default UTF-8
 */
private String code = "utf-8";


/**
 * 边框 0 - 4 (0表示无边框)
 */
private Integer padding;


/**
 * 容错级别
 */
private ErrorCorrectionLevel errorCorrection = ErrorCorrectionLevel.H;


/**
 * 输出二维码图片类型
 */
private String picType = "png";

探测图形(二维码左上,右上,左下三个方框)的参数配置

/**
 * 外面的方框颜色
 */ 
private Color outColor;

/**
 * 内部方框颜色
 */
private Color inColor;

/**
 * 探测图形,优先级高于颜色的定制(即存在图片时,用图片绘制探测图形)
 */
private BufferedImage detectImg;

/**
 * 左上角的探测图形
 */
private BufferedImage detectImgLT;

/**
 * 右上角的探测图形
 */
private BufferedImage detectImgRT;

/**
 * 左下角的探测图形
 */
private BufferedImage detectImgLD;

/**
 * true 表示探测图形单独处理
 * false 表示探测图形的样式更随二维码的主样式
 */
private Boolean special;

二维码图形(就是普通二维码中的黑点)绘制参数:

/**
 * 着色颜色,即二维码点阵中为1的区域绘制颜色,也就是常见二维码中的黑色小方块
 */
private Color preColor;

/**
 * 背景颜色, 即二维码点阵中为0的区域绘制颜色,也就是常见二维码中的白色小方块
 */
private Color bgColor;

/**
 * 透明度填充,如绘制二维码的图片中存在透明区域,若这个参数为true,则会用bgColor填充透明的区域;若为false,则透明区域依旧是透明的
 */
private boolean diaphaneityFill;

/**
 * 背景图,即二维码点阵中为0的区域渲染图片,也就是常见二维码中的白色小方块
 */
private BufferedImage bgImg;

/**
 * 绘制样式: 矩形,三角,原点,五边形,六边形,八边形,图片
 */
private DrawStyle drawStyle;

/**
 * true 时表示支持对相邻的着色点进行合并处理 (即用一个大图来绘制相邻的两个着色点)
 * <p>
 * 说明: 三角形样式关闭该选项,因为留白过多,对识别有影响
 */
private boolean enableScale;

/**
 * 渲染图
 */
private Map<DotSize, BufferedImage> imgMapper;

/**
 * 生成二维码的图片样式,一般来讲不推荐使用圆形,默认为normal
 */
private ImgStyle qrStyle;

/**
 * 圆角的弧度,默认为 1 / 8
 */
private Float cornerRadius;

/**
 * 生成文字二维码时的候字符池
 */
private String text;

/**
 * 生成文字二维码时的字体
 */
private String fontName;

/**
 * 字体样式
 *
 * {@link Font#PLAIN} 0
 * {@link Font#BOLD}  1
 * {@link Font#ITALIC} 2
 */
private int fontStyle;

logo样式配置

/**
 * logo 图片
 */
private BufferedImage logo;

/**
 * logo 样式 (圆角,普通,圆)
 */
private LogoStyle logoStyle;

/**
 * logo 占二维码的比例
 */
private int rate;

/**
 * true 表示有边框,
 * false 表示无边框
 */
private boolean border;

/**
 * 边框颜色
 */
private Color borderColor;

/**
 * 外围边框颜色
 */
private Color outerBorderColor;

/**
 * 用于设置logo的透明度
 */
private Float opacity;

背景图配置

/**
 * 背景图样式
 */
private ImgStyle imgStyle;

/**
 * 圆角弧度,默认为宽高中较小值的 1/8
 */
private float radius;

/**
 * 背景图(静态二维码时使用)
 */
private BufferedImage bgImg;

/**
 * 动态背景图(动态二维码生成时使用)
 */
private GifDecoder gifDecoder;

/**
 * 背景图宽
 */
private int bgW;

/**
 * 背景图高
 */
private int bgH;

/**
 * 背景图样式(全覆盖,指定位置填充,背景图渲染)
 */
private BgImgStyle bgImgStyle;

/**
 * if {@link #bgImgStyle} ==  QrCodeOptions.BgImgStyle.OVERRIDE,
 * 用于设置二维码的透明度
 */
private float opacity;


/**
 * if {@link #bgImgStyle} ==  QrCodeOptions.BgImgStyle.FILL
 * <p>
 * 用于设置二维码的绘制在背景图上的x坐标
 */
private int startX;


/**
 * if {@link #bgImgStyle} ==  QrCodeOptions.BgImgStyle.FILL
 * <p>
 * 用于设置二维码的绘制在背景图上的y坐标
 */
private int startY;

前置图配置

/**
 * 前置图
 */
private BufferedImage ftImg;

/**
 * 背景图样式
 */
private ImgStyle imgStyle;

/**
 * 圆角弧度,默认为宽高中较小值的 1/8
 */
private Float radius;

/**
 * 动态前置图
 */
private GifDecoder gifDecoder;

/**
 * 背景图宽
 */
private int ftW;

/**
 * 背景图高
 */
private int ftH;

/**
 * 用于设置二维码的绘制在前置图上的x坐标
 */
private int startX;


/**
 * 用于设置二维码的绘制在前置图上的y坐标
 */
private int startY;

/**
 * 填充色
 */
private Color fillColor;

接下来我们通过一系列的实例代码,来演示如何生成各种酷炫的二维码

a. 基本二维码

生成一个最常见的最普通的二维码,并保存到qr.png文件,一行代码即可

String msg = "http://weixin.qq.com/r/FS9waAPEg178rUcL93oH";
// 生成二维码,并输出为qr.png图片
boolean ans = QrCodeGenWrapper.of(msg).asFile("qr.png");
dq
dq

v2.5.2 新增二维码圆角设置

/**
 * 默认的二维码生成
 */
@Test
public void defaultQr_corner() {
    try {
        // 生成二维码,并输出为qr.png图片
        String msg = "http://weixin.qq.com/r/FS9waAPEg178rUcL93oH";
        boolean ans = QrCodeGenWrapper.of(msg)
                .setW(500)
                .setPadding(3)
                // 圆角二维码, 不建议使用圆形的二维码,会导致生成的二维码不可用
                .setQrStyle(QrCodeOptions.ImgStyle.ROUND)
                // 圆角弧度默认是宽高的 1/8, 可以根据需要自行设置 
                .setQrCornerRadiusRate(0.125F)
                .setPicType("png")
                .asFile("/tmp/dq_corner1.png");
    } catch (Exception e) {
        e.printStackTrace();
    }
}

输出圆角的二维码图片(建议图片右键新标签页打开,可以看到明显的四边圆角)

圆角二维码
圆角二维码

b. 颜色指定

默认的二维码为白底黑块,如果我希望生成白底蓝块(探测图形外青内红)的二维码,可以如下使用

String msg = "http://weixin.qq.com/r/FS9waAPEg178rUcL93oH";
boolean ans = QrCodeGenWrapper.of(msg)
        .setW(300)
        // 探测图形特殊处理
        .setDetectSpecial()
        // 定位点(探测图形)外边颜色
        .setDetectOutColor(Color.CYAN)
        // 定位点内部颜色
        .setDetectInColor(Color.RED)
        // 二维码着色点
        .setDrawPreColor(Color.BLUE)
        // 二维码背景图
        .setDrawBgColor(0xffffffff)
        .asFile("/tmp/cqr.png");
cqr.png
cqr.png

c. 带logo二维码生成

logo目前支持两种样式,一个是圆角logo,一个是直接原图不做处理;下面是一个简单的圆角logo,并带上边框的实例

String msg = "http://weixin.qq.com/r/FS9waAPEg178rUcL93oH";
// 这里的图片地址,支持网络图片,本地相对路劲图片,本地绝对路径图片
String logo = "https://static.oschina.net/uploads/user/283/566591_100.jpeg";
boolean ans = QrCodeGenWrapper.of(msg)
        .setLogo(logo)
        .setLogoStyle(QrCodeOptions.LogoStyle.ROUND)
        .setLogoBgColor(0xfffefefe)
        .setLogoBorderBgColor(0xffc7c7c7)
        .setLogoBorder(true)
        .asFile("/tmp/lqr3.png");

下图展示了四张带logo的二维码

  • 原始logo
  • 直角带logo背景色
  • 圆角带logo背景色
  • 圆角带logo背景,边框

说明:2.4.2版本优化了logo的锯齿严重的问题

logo
logo

v2.4版本新增圆形logo

/**
 * 带外边框的圆形logo
 */
@Test
public void logoQr4() {
    try {
        String msg = "http://weixin.qq.com/r/FS9waAPEg178rUcL93oH";
        String logo = "logo.jpg";
        boolean ans = QrCodeGenWrapper.of(msg)
                .setW(400)
                .setLogo(logo)
                // 圆形logo支持
                .setLogoStyle(QrCodeOptions.LogoStyle.CIRCLE)
                .setLogoBgColor(0xfffefefe)
                .setLogoBorderBgColor(0xffc7c7c7)
                .setLogoBorder(true)
                .asFile("/tmp/lqr4.png");
    }catch (Exception e) {
        e.printStackTrace();
    }
}
logo
logo

d. 指定背景图

背景图目前支持三种样式,分别是二维码全覆盖在背景图上,在背景图的自定区间进行绘制二维码,生成透明二维码但使用背景图进行渲染,下面

// 默认属于全覆盖的背景模式,对应下图中图1
String msg = "http://weixin.qq.com/r/FS9waAPEg178rUcL93oH";
String bg = "http://ww1.sinaimg.cn/large/8154e929gy1g8vho8x6r0j20b40b43yl.jpg";
boolean ans = QrCodeGenWrapper.of(msg)
        .setBgImg(bg)
        .setW(500)
        .setBgOpacity(0.5f)
        .asFile("/tmp/bqr1.png");

// 指定为填充模式,在背景图的坐标(startX, startY)处绘制二维码(左上角坐标为0,0); 对应下图中的图2
bg = "http://pic.51yuansu.com/pic3/cover/01/07/09/59015a0e53d83_610.jpg";
ans = QrCodeGenWrapper.of(msg)
        .setBgImg(bg)
        .setBgStyle(QrCodeOptions.BgImgStyle.FILL)
        .setBgW(500)
        .setBgH(500)
        .setBgStartX(130)
        .setBgStartY(120)
        .setW(260)
        .setPadding(0)
        .setDrawBgColor(0xfff7f7f7)
        .asFile("/tmp/bqr2.png");
        
// 背景渲染方式,用背景图来填充二维码,对应下图中的图3
bg = "http://img1.juimg.com/180517/355855-1P51H3520817.jpg";
ans = QrCodeGenWrapper.of(msg)
        .setBgImg(bg)
        .setBgStyle(QrCodeOptions.BgImgStyle.PENETRATE)
        .setBgW(500)
        .setBgH(500)
        .setW(500)
        .asFile("/tmp/bqr3.png");
        

// 针对第一种背景方式的扩展,二维码前置、后置都可以使用图片替换
String bg = "overbg/bg.jpg";
String cell = "overbg/a.png";
String bgCell = "overbg/b.png";
Boolean ans = QrCodeGenWrapper.of(msg)
        .setBgImg(bg)
        .setW(500)
        .setErrorCorrection(ErrorCorrectionLevel.H)
        .setBgStyle(QrCodeOptions.BgImgStyle.OVERRIDE)
        .setDrawStyle(QrCodeOptions.DrawStyle.IMAGE)
        .setDrawImg(cell)
        .setDrawBgImg(bgCell)
        .asFile("/tmp/bqr4.png");
qbg.png
qbg.png

给出一个背景图为文字的二维码输出演示case

@Test
public void bgQrTxt() {
    try {
        String msg = "http://weixin.qq.com/r/FS9waAPEg178rUcL93oH";
        BufferedImage bgImg = GraphicUtil.createImg(500, 500, null);
        Graphics2D g2d = GraphicUtil.getG2d(bgImg);
        g2d.setColor(Color.LIGHT_GRAY);
        g2d.fillRect(0, 0, 500, 500);

        Font font = new Font("宋体", Font.BOLD, 500);
        g2d.setFont(font);
        g2d.setColor(Color.RED);
        g2d.drawString("码", 0, 500 - g2d.getFontMetrics().getDescent() / 2);
        g2d.dispose();

        boolean ans = QrCodeGenWrapper.of(msg)
                .setBgImg(bgImg)
                .setBgStyle(QrCodeOptions.BgImgStyle.PENETRATE)
                .setBgW(500)
                .setBgH(500)
                .setW(500)
                .asFile("/tmp/bqrTxt.png");
    } catch (Exception e) {
        e.printStackTrace();
    }
}
bgTxt.png
bgTxt.png

v2.5.2 支持背景图圆角、圆形设置

@Test
public void bgQr1_corner() {
    try {
        String msg = "http://weixin.qq.com/r/FS9waAPEg178rUcL93oH";
        String bg = "https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2859744156,2204003006&fm=26&gp=0.jpg";
        boolean ans = QrCodeGenWrapper.of(msg)
                .setBgImg(bg)
                .setW(500)
                .setBgOpacity(0.6f)
                // 背景圆角比例
                .setBgCornerRadiusRate(0.125f)
                .setBgImgStyle(QrCodeOptions.ImgStyle.ROUND)
                .asFile("/tmp/bqr1_c1.png");
    }catch (Exception e) {
        e.printStackTrace();
    }
}

@Test
public void bgQr1_circle() {
    try {
        String msg = "http://weixin.qq.com/r/FS9waAPEg178rUcL93oH";
        String bg = "http://pic.51yuansu.com/pic3/cover/01/07/09/59015a0e53d83_610.jpg";
        boolean ans = QrCodeGenWrapper.of(msg)
                .setBgImg(bg)
                .setBgStyle(QrCodeOptions.BgImgStyle.FILL)
                .setBgW(500)
                .setBgH(500)
                .setBgStartX(130)
                .setBgStartY(120)
                .setW(260)
                .setPadding(0)
                .setDrawBgColor(0xfff7f7f7)
                .setBgImgStyle(QrCodeOptions.ImgStyle.CIRCLE)
                .asFile("/tmp/bqr2_c2.png");
    }catch (Exception e) {
        e.printStackTrace();
    }
}
bg_style
bg_style

e. 探测图形样式指定

探测图形,指的是左上角、右上角、左下角的三个”回字“,除了上面介绍到的指定不同的颜色之外,还可以用图片替换

// 指定探测图形为固定图片,输出如下图中图1
QrCodeGenWrapper.of(msg)
        .setW(500)
        .setDetectImg("detect.png")
        .asFile("/tmp/tqr1.png");
        

// 分别制定三个探测图形,对应三个图片,输出如下图中图2
QrCodeGenWrapper.of(msg)
        .setW(500)
        .setLTDetectImg("leaf/eye.png")
        .setLDDetectImg("jihe/PDP.png")
        .setRTDetectImg("love/01.png")
        // 这个参数表示探测图形中的透明区域,用二维码背景色填充
        .setDiaphaneityFill(true)
        .asFile("/tmp/tqr2.png");
探测
探测

v2.4 探测图形新增参数special

  • true: 表示探测图形独立绘制,与二维码的绘制样式不同;请注意当设置探测图形img时,这个参数默认为true
  • false: 探测图形的渲染和二维码一致

下面两段代码生成分别为下图一二,请注意setDetectSpecial()设置之后探测图形并不一样了

@Test
public void detectedQr3() {
    String msg = "http://weixin.qq.com/r/FS9waAPEg178rUcL93oH";
    try {
        QrCodeGenWrapper.of(msg)
                .setDrawStyle(QrCodeOptions.DrawStyle.CIRCLE)
                .setDrawEnableScale(true)
                .asFile("/tmp/tqr3.png");
    } catch (Exception e) {
        e.printStackTrace();
    }
}

@Test
public void detectedQr4() {
    String msg = "http://weixin.qq.com/r/FS9waAPEg178rUcL93oH";
    try {
        QrCodeGenWrapper.of(msg)
                .setDetectSpecial()
                .setDrawStyle(QrCodeOptions.DrawStyle.CIRCLE)
                .setDrawEnableScale(true)
                .asFile("/tmp/tqr4.png");
    } catch (Exception e) {
        e.printStackTrace();
    }
}
探测
探测

f. 几何样式二维码生成

默认的二维码的信息为黑色小方块,本插件提供了其他的几个常见的几何形式支持,如圆点,三角,钻石,六边形,八边形;通过指定DrawStyle参数即可

String msg = "http://weixin.qq.com/r/FS9waAPEg178rUcL93oH";
boolean ans = QrCodeGenWrapper.of(msg)
        .setW(400)
        // 支持将临近相同的合并成一个大的圆点
        .setDrawEnableScale(true)
        .setDrawStyle(QrCodeOptions.DrawStyle.CIRCLE)
        .asFile("/tmp/dqr6.png");
几何
几何

v2.4 新增文字二维码

  • 指定一串字符串,根据字符串内容生成二维码
@Test
public void fontQr1() {
    String msg = "http://weixin.qq.com/r/FS9waAPEg178rUcL93oH";

    int size = 500;
    try {
        boolean ans = QrCodeGenWrapper.of(msg)
                .setW(size)
                .setH(size)
                // 不指定text时,默认文本为千字文,宋体加粗
                .setQrText("我是一灰灰欢迎关注")
                .setDetectSpecial()
                .setErrorCorrection(ErrorCorrectionLevel.H)
                .setDrawStyle(QrCodeOptions.DrawStyle.TXT)
                .setPicType("png")
                .asFile("/tmp/fontQr1.png");
    } catch (Exception e) {
        e.printStackTrace();
    }
}
文字二维码
文字二维码

v2.4.1 支持文字二维码渲染模式(顺序or随机)

/**
 * 文字二维码
 */
@Test
public void fontQr3() {
    String msg = "http://weixin.qq.com/r/FS9waAPEg178rUcL93oH";

    try {
        boolean ans = QrCodeGenWrapper.of(msg)
                .setQrText("欢迎关注一灰灰")
                // 指定文字随机渲染方式
                .setQrTxtMode(QrCodeOptions.TxtMode.RANDOM)
                // true 则探测图形有自己的绘制规则
                .setDetectSpecial()
                .setErrorCorrection(ErrorCorrectionLevel.H)
                .setDrawStyle(QrCodeOptions.DrawStyle.TXT)
                // 当相邻的NxN都是黑色小方块时,放大(慎用,因为部分汉子如 `一` 无法友好的填充2x2的方块)
                .setDrawEnableScale(true)
                .setPicType("png")
                .asFile("/tmp/fontQr3.png");
    } catch (Exception e) {
        e.printStackTrace();
    }
}

v2.6.0 新增MINI_RECT样式

MINI_RECT
MINI_RECT
@Test
public void miniRectQr() {
    try {
        String msg = "http://weixin.qq.com/r/FS9waAPEg178rUcL93oH";
        boolean ans = QrCodeGenWrapper.of(msg)
                .setW(200)
                // 如果希望探测图形依然是标准的,加上下面这一行
//                    .setDetectSpecial()
                .setDrawStyle(QrCodeOptions.DrawStyle.MINI_RECT)
                .asFile(prefix + "/dqr0_1.png");
    } catch (Exception e) {
        e.printStackTrace();
    }
}

g. 图片填充

如果你有一套完整的素材,那么可以考虑用这些素材来生成一个更漂亮的二维码;

比如项目的测试中,给出了两套输出,一个爱心,一个集合图形

String msg = "http://weixin.qq.com/r/FS9waAPEg178rUcL93oH";
int size = 500;

// 爱心素材生成的二维码图片,如下图中的图1,请注意我们的二维码背景渲染色指定为透明,最终输出的二维码也是带透明度的png图片,
boolean ans = QrCodeGenWrapper.of(msg)
        .setW(size)
        .setH(size)
        .setErrorCorrection(ErrorCorrectionLevel.M)
        .setDrawBgColor(ColorUtil.OPACITY)
        .setDetectImg("love/01.png")
        .setDrawStyle(QrCodeOptions.DrawStyle.IMAGE)
        .addImg(1, 1, "love/003_01.png")
        .addImg(4, 1, "love/004.png")
        .addImg(1, 4, "love/004_02.png")
        .asFile("/tmp/imgQr1.png");

// 几何素材生成的二维码图片
ans = QrCodeGenWrapper.of(msg)
        .setW(size)
        .setH(size)
        .setErrorCorrection(ErrorCorrectionLevel.H)
        // 因为素材为png透明图,我们这里设置二维码的背景为透明,输出更加优雅
        .setDrawBgColor(ColorUtil.OPACITY)
        .setDetectImg("jihe/PDP.png")
        .setDrawStyle(QrCodeOptions.DrawStyle.IMAGE)
        .addImg(1, 1, "jihe/a.png")
        .addImg(3, 1, "jihe/b.png")
        .addImg(1, 3, "jihe/c.png")
        .addImg(3, 2, "jihe/e.png")
        .addImg(2, 3, "jihe/f.png")
        .addImg(2, 2, "jihe/g.png")
        .addImg(3, 4, "jihe/h.png")
        .setPicType("png")
        .asFile("/tmp/imgQr2.png");

// 除了指定二维码的”前置图片“之外,还可以指定”后置图片“
// 注意下图中的图3,其中黑色小点为素材图片,对应二维码中黑色方块;
// 白色小点也是素材图片,对应二维码中的白色方块
ans = QrCodeGenWrapper.of(msg)
        .setW(size)
        .setH(size)
        .setErrorCorrection(ErrorCorrectionLevel.M)
        .setDrawBgColor(ColorUtil.OPACITY)
        .setDrawBgImg("overbg/b.png")
        .setDrawStyle(QrCodeOptions.DrawStyle.IMAGE)
        .setDrawImg("overbg/a.png")
        .asFile("/tmp/imgQr3.png");

使用这种方式,需要稍微注意一下

  • 必须指定DrawStyle为图片模式
  • addImg(row, column, img) 来声明素材对应的应用场景,这个表示当出现一个row行,column列都有信息时,用img来填充
  • setDrawImg: 如果所有的二维码图片都是一个的话,可以用这个方法替代addImg(1,1,img)
  • setDrawBgImg: 设置的是二维码矩阵中为0(即白色小方块)的渲染图片,不是整个二维码的背景图哦
  • setDrawBgColor(ColorUtil.OPACITY): 设置二维码绘制背景色为透明,可以充分利用素材图片的透明区域,使显示效果更优雅

下面是一个是quick-media提供的三种样式模板

imgQr
imgQr

v2.6.0 图片二维码的支持相同位置的多图随机渲染

MINI_RECT
MINI_RECT
@Test
public void imgQr2() {
    try {
        String msg = "http://weixin.qq.com/r/FS9waAPEg178rUcL93oH";
        int size = 500;
        boolean ans = QrCodeGenWrapper.of(msg)
                .setW(size)
                .setH(size)
                .setErrorCorrection(ErrorCorrectionLevel.M)
                .setDrawBgColor(ColorUtil.OPACITY)
                .setDetectImg("love/01.png")
                .setDrawStyle(QrCodeOptions.DrawStyle.IMAGE)
                .addImg(1, 1, "love/001.png")
                .addImg(2, 2, "love/003_01.png")
                .addImg(2, 2, "love/003_02.png")
                .addImg(2, 2, "love/003_03.png")
                .addImg(4, 1, "love/004.png")
                .addImg(1, 4, "love/004_02.png")
                .asFile(prefix + "/imgQr2.png");
    } catch (Exception e) {
        e.printStackTrace();
    }
}

h. 动态二维码

接下来介绍一下动态二维码的生成,和背景图的使用姿势基本上完全以往,唯一的区别就是背景图为gif动图

// 全覆盖模式,指定二维码的透明度(如下图左)
String msg = "http://weixin.qq.com/r/FS9waAPEg178rUcL93oH";
String bg = "http://ww1.sinaimg.cn/large/8154e929gy1g8pq78mcgrg20dw0boaja.gif";
boolean ans = QrCodeGenWrapper.of(msg)
        .setW(500)
        .setBgImg(bg)
        .setBgOpacity(0.6f)
        .setPicType("gif")
        .asFile("/tmp/gifQr1.gif");
                    

// 填充模式,在背景图的指定位置上绘制二维码,属于常见的一种动图模式(如下图中)
bg = "http://ww1.sinaimg.cn/large/8154e929gy1g8qe2iv0evg20xc0irn68.gif";
boolean ans = QrCodeGenWrapper.of(msg)
      .setW(400)
      .setBgImg(bg)
      .setBgStyle(QrCodeOptions.BgImgStyle.FILL)
      .setBgStartX(20)
      .setBgStartY(137)
      .setPicType("gif")
      .asFile("/tmp/gifQr2.gif");

// 背景渲染模式,直接用背景图来填充二维码信息,因此可以实现炫酷的二维码(如下图右)
bg = "http://ww1.sinaimg.cn/large/8154e929gy1g8w7wj6qvsg20oy0io4dt.gif";
boolean ans = QrCodeGenWrapper.of(msg)
      .setBgImg(bg)
      .setBgW(500)
      .setBgH(500)
      .setBgStyle(QrCodeOptions.BgImgStyle.PENETRATE)
      .setW(500)
      .asFile("/tmp/gifQr3.gif");
list.gif
list.gif

i. 前置图

qrcode v2.5.3 提供前置图功能,支持在二维码上层覆盖图片,基本使用姿势如下(项目源码的test中,通过QrCodeGenUserGuide#ft1查看)

/**
 * 前置图测试,对应下图中的第一张
 */
@Test
public void ft1() {
    try {
        String msg = "http://weixin.qq.com/r/FS9waAPEg178rUcL93oH";
        String ft = "ft/ft_1.png";
        boolean ans = QrCodeGenWrapper.of(msg)
                .setDetectImg("eye3.png")
                .setW(1340)
                .setH(1340)
                // 下面ft开头的都是前置图设置
                .setFtImg(ft)
                // 二维码小于前置图,因此剩余的地方用白色填充
                .setFtFillColor(Color.WHITE)
                // 二维码在前置图中的x,y偏移
                .setFtStartX(100)
                .setFtStartY(130)
                .asFile("/tmp/ft1.png");
    } catch (Exception e) {
        e.printStackTrace();
    }
}
list.gif
list.gif

借助前置图,可以实现某些小伙伴希望在二维码的周边加文字的需求,一种方法是设计一个固定文字的模板,直接作为前置图,使用上面的姿势

也可以自己来生成动态的文字前置图,下面是一个具体实现case

/**
 * 在二维码周边添加文字的示例,对应上图中间的那个
 */
@Test
public void ft2() {
    //  创建一个文字的前置图
    BufferedImage ftImg = GraphicUtil.createImg(500, 600, null);
    Graphics2D g2d = GraphicUtil.getG2d(ftImg);
    g2d.setColor(Color.WHITE);
    g2d.fillRect(0, 500, 500, 500);
    g2d.setColor(Color.BLACK);
    g2d.setFont(new Font(null, Font.PLAIN, 22));
    g2d.drawString("欢迎关注《一灰灰Blog》", 140, 550);


    String msg = "http://weixin.qq.com/r/FS9waAPEg178rUcL93oH";
    try {
        boolean ans = QrCodeGenWrapper.of(msg)
                .setW(500)
                .setH(500)
                .setDetectImg("eye3.png")
                .setFtImg(ftImg)
                .setFtFillColor(Color.WHITE)
                .asFile("/tmp/ft2.png");
    } catch (Exception e) {
        e.printStackTrace();
    }
}

如果希望文字动态,那么更推荐的是结合image-plugin来使用,比如我可以实现文字垂直输出

/**
 * 在二维码周边添加文字的实例,借助 image-plugins 来实现,能更简单的满足UI大佬的设计需求
 * 对应上图中右边的那个
 */
@Test
public void ft3() {
    try {
        // 二维码
        int qrSize = 460;
        String msg = "http://weixin.qq.com/r/FS9waAPEg178rUcL93oH";
        BufferedImage qrImg = QrCodeGenWrapper.of(msg)
                .setW(qrSize)
                .setH(qrSize)
                .setDetectImg("eye3.png")
                .setFtFillColor(Color.WHITE)
                .asBufferedImage();
        ImgCell qrCell = ImgCell.builder().img(qrImg).x(20).y(20).build();


        // 修饰文字
        TextCell textCell = TextCell.builder().font(new Font("宋体", Font.BOLD, 22))
                .color(Color.BLACK)
                .drawStyle(ImgCreateOptions.DrawStyle.VERTICAL_LEFT)
                .alignStyle(ImgCreateOptions.AlignStyle.CENTER)
                .startX(540)
                .startY(0)
                .endX(540)
                .endY(500)
                .text("欢迎关注<一灰灰Blog>")
                .build();

        BufferedImage out = ImgMergeWrapper.merge(Arrays.asList(qrCell, textCell), 600, 500, Color.WHITE);
        ImageIO.write(out, "jpg", new File("/tmp/ft3.jpg"));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

前置渲染模板还支持动态gif,如添加一个动态的logo

public void preGif() {
    String pre = "https://iknow-pic.cdn.bcebos.com/f9dcd100baa1cd11dec1529bbd12c8fcc3ce2d11";
    try {
        // 二维码
        int qrSize = 320;
        String msg = "http://weixin.qq.com/r/FS9waAPEg178rUcL93oH";
        QrCodeGenWrapper.of(msg)
                .setW(qrSize)
                .setH(qrSize)
                .setDrawPreColor(0xff73a7f5)
    //                    .setDrawStyle(QrCodeOptions.DrawStyle.CIRCLE)
                .setDrawEnableScale(true)
                .setFtImg(pre)
                .setFtStartX(0)
                .setFtStartY(-25)
                .setFtFillColor(Color.WHITE)
                .asFile("/tmp/ft_1.gif");

    } catch (Exception e) {
        e.printStackTrace();
    }
}

对应的二维码如下:

j. 综合

上面的几种case,是可以组合使用的,最后给一个综合的"求关注"动态二维码的生成实例

String msg = "http://weixin.qq.com/r/FS9waAPEg178rUcL93oH";
// 网络动图背景
String bg = "http://ww1.sinaimg.cn/large/8154e929gy1g8w9jsxwtdg20pz08zwr8.gif";
// 本地logo
String logo = "logo.jpg";
boolean ans = QrCodeGenWrapper.of(msg)
        .setW(500)
        .setDrawBgColor(ColorUtil.OPACITY)
        .setDrawStyle(QrCodeOptions.DrawStyle.IMAGE)
        .setDetectImg("jihe/PDP.png")
        .addImg(1, 1, "jihe/a.png")
        .addImg(3, 1, "jihe/b.png")
        .addImg(1, 3, "jihe/c.png")
        .addImg(3, 2, "jihe/e.png")
        .addImg(2, 3, "jihe/f.png")
        .addImg(2, 2, "jihe/g.png")
        .addImg(3, 4, "jihe/h.png")
        .setPadding(1)
        .setErrorCorrection(ErrorCorrectionLevel.H)
        .setLogo(logo)
        .setLogoBorder(true)
        .setLogoStyle(QrCodeOptions.LogoStyle.ROUND)
        .setLogoBgColor(0xfffefefe)
        .setLogoBorderBgColor(0xffc7c7c7)
        .setBgImg(bg)
        .setBgW(1870)
        .setBgH(646)
        .setBgStyle(QrCodeOptions.BgImgStyle.FILL)
        .setBgStartX(690)
        .setBgStartY(20)
        .setBgOpacity(0.9f)
        .setPicType("gif")
        .asFile("/tmp/gifQr4.gif");
求关注
求关注
Loading...