中秋到了,是时候给你的二维码加个月饼了

2,244 阅读6分钟

我正在参加中秋创意投稿大赛,详情请看:中秋创意投稿大赛

又一年的中秋将至,要怎么样才能蹭一波它的热度呢?作为一个coder,是不是可以用代码写首诗?想法是好,可惜难度有点大,那么就简单点,给自己的二维码上,加个月饼吧

1. logo中加月饼?

在二维码中添加月饼,好像没啥难度,直接网上搜一个二维码生成器,然后找个月饼图,作为logo拍上去,game over

image.png (避免审核不通过,特意抹掉二维码的码眼,无法识别是正常的)

如果仅限于此的话,本文也就没啥意思了,接下来我们看些不一样的东西

2. 拒绝黑白块,满屏二维码

接下来我们使用github上的quick-media:qrcode-plugin来实现更多有意思的二维码定制

首先引入依赖

<dependency>
    <groupId>com.github.liuyueyi.media</groupId>
    <artifactId>qrcode-plugin</artifactId>
    <version>2.6.1</version>
</dependency>

接下来我们使用三个月饼图,来生成一张满屏皆是月饼的二维码

image.png

要生成上面的二维码也很简单,实现代码如下

String sourcePrefix = "/Users/user/Documents/qr/";
QrCodeGenWrapper.of(msg)
        .setW(500)
        .setH(500)
        .setErrorCorrection(ErrorCorrectionLevel.M)
        .setDiaphaneityFill(true) // 透明处用背景色填充
        .setDrawBgColor(Color.WHITE)
        .setDrawStyle(QrCodeOptions.DrawStyle.IMAGE_V2)
        .setImgResourcesForV2(RenderImgResourcesV2.create()
                // 下面配置 1 x 1的方块对应的月饼图片
                .addSource(1, 1).addImg(sourcePrefix + "00.png")
                .addImg(sourcePrefix + "01.png")
                .addImg(sourcePrefix + "02.png", 1) // 最后一个1,表示这个月饼只出现一次
                .addImg(sourcePrefix + "03.png")
                .build()
                // 下面配置 2 x 2的方块对应的月饼图片
                .addSource(2, 2)
                .addImg(sourcePrefix + "00.png").addImg(sourcePrefix + "01.png")
                .addImg(sourcePrefix + "02.png", 1)
                .addImg(sourcePrefix + "03.png").build()
                .addSource(3, 3).addImg(sourcePrefix + "00.png").addImg(sourcePrefix + "01.png")
                .addImg(sourcePrefix + "02.png", 1)
                .addImg(sourcePrefix + "03.png").build()

        )
        .asFile(sourcePrefix + "/out0.jpg");

上面虽然生成了一个满屏就是月饼的二维码,但识别是个问题,关键点就是三个码眼(探测图形)

3. 码眼也要绚起来

既然上面的码眼不够优秀,那就替换掉,用自定义的码眼来代替默认生成的,提高识别率

image.png

要实现上面的这个二维码,方法也很简单,在前面的基础上,指定一下探测图形即可

// 设置左上角码眼
.setLTDetectImg(sourcePrefix + "d1.jpg")
// 设置左下角码眼
.setLDDetectImg(sourcePrefix + "d2.jpg")
// 设置右上角码眼
.setRTDetectImg(sourcePrefix + "d3.jpg")

其他的设置方式和前面的也没有什么区别,实现如下

String sourcePrefix = "/Users/user/Documents/qr/";
QrCodeGenWrapper.of(msg)
        .setW(500)
        .setH(500)
        .setErrorCorrection(ErrorCorrectionLevel.M)
        .setDiaphaneityFill(true) // 透明处用背景色填充
        .setDrawBgColor(Color.WHITE)
        .setDrawStyle(QrCodeOptions.DrawStyle.IMAGE_V2)
        .setLTDetectImg(sourcePrefix + "d1.jpg")
        .setLDDetectImg(sourcePrefix + "d2.jpg")
        .setRTDetectImg(sourcePrefix + "d3.jpg")
        .setImgResourcesForV2(RenderImgResourcesV2.create()
                .addSource(1, 1).addImg(sourcePrefix + "00.png")
                .addImg(sourcePrefix + "01.png")
                .addImg(sourcePrefix + "02.png", 1)
                .addImg(sourcePrefix + "03.png")
                .build()
                .addSource(2, 2)
                .addImg(sourcePrefix + "00.png").addImg(sourcePrefix + "01.png")
                .addImg(sourcePrefix + "02.png", 1)
                .addImg(sourcePrefix + "03.png").build()
                .addSource(3, 3).addImg(sourcePrefix + "00.png").addImg(sourcePrefix + "01.png")
                .addImg(sourcePrefix + "02.png", 1)
                .addImg(sourcePrefix + "03.png").build()

        )
        .asFile(sourcePrefix + "/out_d0.jpg");

4. 印有诗词的二维码

既然最开始说了中秋要用代码写诗来蹭热度,虽然写诗我不行,但是作为一个专职ctrl+c/ctrl+v的coder,抄我可会了,接下来我们把苏轼大大的千古名篇,给印在我们的二维码上

image.png

上面这个二维码有点意思了,直接用中文来渲染,要实现也很简单,下面几个简单配置即可

String sourcePrefix = "/Users/user/Documents/qr/";
QrCodeGenWrapper.of(msg)
        .setDetectSpecial() // 三个码眼还是用标砖的码眼
        .setDrawStyle(QrCodeOptions.DrawStyle.TXT)
        .setQrText("明月几时有把酒问青天不知天上宫阙今夕是何年我欲乘风归去又恐琼楼玉宇高处不胜寒起舞弄清影何似在人间" +
                "转朱阁低绮户照无眠不应有恨何事长向别时圆人有悲欢离合月有阴晴圆缺此事古难全但愿人长久千里共婵娟")
        .setLogo(sourcePrefix+"/logo2.jpg") // 添加一个logo
        .setLogoStyle(QrCodeOptions.LogoStyle.ROUND)
        .setLogoBorderBgColor(Color.GRAY)
        .asFile(sourcePrefix + "/ft.jpg");

5. 有诗词,也有月饼的二维码

只有诗词没有月饼不好看;只有月饼没有诗词不够秀,那就合起来,生成一个类似下面的二维码

image.png

需要注意的是,上面的包中,并没有提供这种混编的方式,需要我们拉到源码自定义改造一番,重写QrCodeOption.DrawStyle中的方法

IMAGE_V2 {
    @Override
    public void draw(Graphics2D g2d, int x, int y, int w, int h, BufferedImage img, String txt) {
        String source  = "明月几时有把酒问青天不知天上宫阙今夕是何年我欲乘风归去又恐琼楼玉宇高处不胜寒起舞弄清影何似在人间" +
                "转朱阁低绮户照无眠不应有恨何事长向别时圆人有悲欢离合月有阴晴圆缺此事古难全但愿人长久千里共婵娟";
        if ("false".equals(txt)) {
            if (Math.random() < 0.8f) {
                if (Math.random() < 0.6f) {
                    int offsetX = w / 5, offsetY = h / 5;
                    int width = w - offsetX * 2, height = h - offsetY * 2;
                    g2d.fillRect(x + offsetX, y + offsetY, width, height);
                    return;
                }

                int index = QuickQrUtil.getIndex();
                if (index >= source.length()) {
                    int offsetX = w / 5, offsetY = h / 5;
                    int width = w - offsetX * 2, height = h - offsetY * 2;
                    g2d.fillRect(x + offsetX, y + offsetY, width, height);
                } else {
                    Font oldFont = g2d.getFont();
                    if (oldFont.getSize() != w) {
                        Font newFont = QuickQrUtil.font(oldFont.getName(), oldFont.getStyle(), w);
                        g2d.setFont(newFont);
                    }
                    g2d.drawString(source.substring(index, index+1), x, y + w);
                    g2d.setFont(oldFont);
                }
            } else {
                g2d.drawImage(img.getScaledInstance(w, h, Image.SCALE_SMOOTH), x, y, null);
            }
        } else {
            g2d.drawImage(img.getScaledInstance(w, h, Image.SCALE_SMOOTH), x, y, null);
        }
    }

    @Override
    public boolean expand(DotSize dotSize) {
        return true;
    }
}

6. 让二维码动起来

上面的这些都是静态的,接下来我们赋予它动起来的能力,生成一个gif版的二维码,需要我们做的事情也不多,找个gif背景图即可

05.gif

上面这个动态二维码的生成方式也很简单,基本配置与前面一致,区别在于指定背景gif图

String sourcePrefix = "/Users/user/Documents/qr/";
QrCodeGenWrapper.of(msg)
        .setW(160)
        .setH(160)
        .setErrorCorrection(ErrorCorrectionLevel.M)
        .setDiaphaneityFill(true) // 透明处用背景色填充
        .setDrawBgColor(Color.WHITE)
        .setPadding(0)
        .setDrawStyle(QrCodeOptions.DrawStyle.IMAGE_V2)
        .setDetectSpecial()
        .setImgResourcesForV2(RenderImgResourcesV2.create()
                .addSource(1, 1).addImg(sourcePrefix + "00.png")
                .addImg(sourcePrefix + "01.png")
                .addImg(sourcePrefix + "02.png", 1)
                .addImg(sourcePrefix + "03.png")
                .build()
                .addSource(2, 2)
                .addImg(sourcePrefix + "00.png").addImg(sourcePrefix + "01.png")
                .addImg(sourcePrefix + "02.png", 1)
                .addImg(sourcePrefix + "03.png").build()
                .addSource(3, 3).addImg(sourcePrefix + "00.png").addImg(sourcePrefix + "01.png")
                .addImg(sourcePrefix + "02.png", 1)
                .addImg(sourcePrefix + "03.png").build()

        )
        .setLogo(sourcePrefix+"/logo.jpg")
        .setLogoRate(12)
        .setLogoStyle(QrCodeOptions.LogoStyle.ROUND)
        .setLogoBorderBgColor(Color.GRAY)
        // 下面是设置背景图,表示将二维码覆盖在背景图的指定坐标上
        .setBgImg(sourcePrefix + "/bg4.gif")
        .setBgStyle(QrCodeOptions.BgImgStyle.FILL)
        .setBgStartX(10)
        .setBgStartY(120)
        .asFile(sourcePrefix + "/out3.gif");
}

除了上面这种动态之外,还可以实现类似logo的动图效果,如

06.gif

实现姿势也很简单,借助FtImg来指定前置的gif图即可

String sourcePrefix = "/Users/user/Documents/qr/";
QrCodeGenWrapper.of(msg)
        .setW(500)
        .setH(500)
        .setDiaphaneityFill(true) // 透明处用背景色填充
        .setDrawBgColor(ColorUtil.OFF_WHITE) // 设置背景色为米黄色,方便gif图的显示效果
        .setDrawStyle(QrCodeOptions.DrawStyle.IMAGE_V2)
        .setDetectSpecial()
        .setImgResourcesForV2(RenderImgResourcesV2.create()
                .addSource(1, 1).addImg(sourcePrefix + "00.png")
                .addImg(sourcePrefix + "01.png")
                .addImg(sourcePrefix + "02.png", 1)
                .addImg(sourcePrefix + "03.png")
                .build()
                .addSource(2, 2)
                .addImg(sourcePrefix + "00.png").addImg(sourcePrefix + "01.png")
                .addImg(sourcePrefix + "02.png", 1)
                .addImg(sourcePrefix + "03.png").build()
                .addSource(3, 3).addImg(sourcePrefix + "00.png").addImg(sourcePrefix + "01.png")
                .addImg(sourcePrefix + "02.png", 1)
                .addImg(sourcePrefix + "03.png").build()
        )
        // 直接从网络下载gif图,缩放为 112 * 120, 在二维码中间绘制
        .setFtImg("https://b-ssl.duitang.com/uploads/item/201609/14/20160914224309_WNUaE.gif")
        .setFtW(112)
        .setFtH(120)
        .setFtStartX(-194)
        .setFtStartY(-190)
        .asFile(sourcePrefix + "/out_ft1.gif");

7. 最后的最后

最后声明,本文中所有资源来自网络,如有侵权,联系即删,本文中所有的二维码生成,都是基于开源项目quick-media来生成的, 有兴趣的小伙伴可以尝鲜一下github.com/liuyueyi/qu…,毕竟月饼节到了,怎么着也得吃个吧

II. 其他

1. 一灰灰Blogliuyueyi.github.io/hexblog

一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛

2. 声明

尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激

  • 微博地址: 小灰灰Blog
  • QQ: 一灰灰/3302797840
  • 微信公众号:一灰灰blog