带圆角LOGO的QrCode二维码实时生成

简介: 最近工作中经常要用到QrCode二维码,研究了一下,写了个带圆角LOGO的JAVA实现,QrCode之所以能在中间放个LOGO图标,是因为编码时的信息冗余。

最近工作中经常要用到QrCode二维码,研究了一下,写了个带圆角LOGO的JAVA实现,QrCode之所以能在中间放个LOGO图标,是因为编码时的信息冗余。实现的具体代码如下:

方法接口:

import java.io.File;
import java.io.OutputStream;

public interface QRCodeService {

    public void generateToStream(String code, OutputStream stream);
    
    public void generateToStream(String code, OutputStream stream, int width);
    
    public void generateToStream(String code, OutputStream stream, int width, int frontColor);
    
    public void generateToStream(String code, OutputStream stream, int width, int frontColor, File logo);
}
接口实现类:

import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;

import javax.imageio.ImageIO;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;


@Service("qrCodeService")
public class QRCodeServiceImpl implements QRCodeService {

    private static final Logger LOGGER = LoggerFactory.getLogger(QRCodeServiceImpl.class);
    // 二维码的宽
    private static int WIDTH = 250;
    // 中间图片的宽
    private static int IMGWIDTH = 60;
    // 圆角半径
    private static int RADIUS = 10;
    // 留白填充宽度
    private static int MARGIN = 4;
    
    private static int FRONTCOLOR = 0x00000000;//0x00808080;
    
    /**
     * 功能描述:生成普通二维码到输出流
     */
    @Override
    public void generateToStream(String code, OutputStream stream) {
        this.generateToStream(code, stream, WIDTH, FRONTCOLOR, null);
    }
    
    @Override
    public void generateToStream(String code, OutputStream stream, int width) {
        this.generateToStream(code, stream, width, FRONTCOLOR, null);
    }

    @Override
    public void generateToStream(String code, OutputStream stream, int width, int frontColor) {
        this.generateToStream(code, stream, width, frontColor, null);
    }

    @Override
    public void generateToStream(String code, OutputStream stream, int width, int frontColor, File logo) {
        Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        // 修正容量高
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        // 边框留白
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix matrix = null;
        try {
            matrix = new MultiFormatWriter().encode(code, BarcodeFormat.QR_CODE, width, width, hints);
        } catch (WriterException e) {
            LOGGER.error("", e);
        }
        proc(matrix, stream, frontColor, logo);
    }

    public void proc(BitMatrix matrix, OutputStream stream, int frontColor, File logo) {
        int width = matrix.getWidth();
        // 处理后图片的数据
        int pixels[] = new int[width * width];
        // 中间图片数组数据
        int src[][] = null;
        boolean hashlogo = false;
        if(logo != null){
            src = getPic(logo);
            hashlogo = true;
        }
        // 填充色
        int margincolor = 0xffffffff;// 白色
        int w_half = width / 2;
        int frame = MARGIN;
        int img_half = IMGWIDTH / 2;
        int r = RADIUS;
        int near = width / 2 - img_half - frame + r;//101
        int far = width / 2 + img_half + frame - r;//149
        for (int y = 0; y < width; y++) {
            for (int x = 0; x < width; x++) {
                if(!hashlogo){
                    // 二维码
                    pixels[y * width + x] = matrix.get(x, y) ? frontColor : margincolor;
                } else {
                    // 中间图片
                    if (x > w_half - img_half && x < w_half + img_half
                            && y > w_half - img_half && y < w_half + img_half) {
                        //
                        pixels[y * width + x] = src[x - w_half + img_half][y - w_half + img_half];

                    } else if ((x > w_half - img_half - frame // 左边框
                            && x < w_half - img_half + frame && y > w_half - img_half - frame && y < w_half
                            + img_half + frame)
                            || (x > w_half + img_half - frame // 右边框
                                    && x < w_half + img_half + frame
                                    && y > w_half - img_half - frame && y < w_half + img_half
                                    + frame)
                            || (x > w_half - img_half - frame // 上边框
                                    && x < w_half + img_half + frame
                                    && y > w_half - img_half - frame && y < w_half - img_half
                                    + frame)
                            || (x > w_half - img_half - frame // 下边框
                                    && x < w_half + img_half + frame
                                    && y > w_half + img_half - frame && y < w_half + img_half
                                    + frame)) {
                        
                        // 圆角处理
                        if(x<near && y<near && (near-x)*(near-x)+(near-y)*(near-y)> r*r){
                            // 左上圆角
                            pixels[y * width + x] = matrix.get(x, y) ? frontColor : margincolor;
                        } else if(x>far && y<near && (x-far)*(x-far)+(near-y)*(near-y) > r*r){
                            // 右上圆角
                            pixels[y * width + x] = matrix.get(x, y) ? frontColor : margincolor;
                        } else if(x<near && y>far && (near-x)*(near-x)+(y-far)*(y-far) > r*r){
                            // 左下圆角
                            pixels[y * width + x] = matrix.get(x, y) ? frontColor : margincolor;
                        } else if(x>far && y>far && (x-far)*(x-far)+(y-far)*(y-far) > r*r){
                            // 右下圆角 
                            pixels[y * width + x] = matrix.get(x, y) ? frontColor : margincolor;
                        } else {
                            // 边框填充颜色
                            pixels[y * width + x] = margincolor; 
                        }
                    } else {
                        // 二维码
                        pixels[y * width + x] = matrix.get(x, y) ? frontColor : margincolor; 
                    }
                }
            }
        }
        BufferedImage image = new BufferedImage(width, width, BufferedImage.TYPE_INT_RGB);
        image.getRaster().setDataElements(0, 0, width, width, pixels);
        try {
            ImageIO.write(image, "png", stream);
        } catch (IOException e) {
            //TODO
        }
    }

    // 图片的压缩、圆角处理,并生成数组
    public int[][] getPic(File logo) {
        BufferedImage biSrc = null;
        try {
            biSrc = ImageIO.read(logo);
        } catch (IOException e) {
            
        }
        BufferedImage biTarget = new BufferedImage(IMGWIDTH, IMGWIDTH, BufferedImage.TYPE_3BYTE_BGR);
        biTarget.getGraphics().drawImage(biSrc.getScaledInstance(IMGWIDTH, IMGWIDTH, Image.SCALE_SMOOTH), 0, 0, null);
        int src[][] = new int[IMGWIDTH][IMGWIDTH];
        // 圆角处理半径
        int r = RADIUS;
        int max = IMGWIDTH;
        int bordercolor = 0x00000000;
        int whitecolor = 0xffffffff;
        for (int x = 0; x < IMGWIDTH; x++) {
            for (int y = 0; y < IMGWIDTH; y++) {
                if(x<r&&y<r&&((r-x)*(r-x)+(r-y)*(r-y)>(r-1)*(r-1))){
                    // 左上圆角
                    if((r-x)*(r-x)+(r-y)*(r-y)>r*r){
                        src[x][y] = whitecolor;
                    } else {
                        src[x][y] = bordercolor;
                    }
                } else if (x>(max-r)&&y<r&&(x+r-max)*(x+r-max)+(r-y)*(r-y)>(r-1)*(r-1)){
                    // 右上圆角
                    if((x+r-max)*(x+r-max)+(r-y)*(r-y)>r*r){
                        src[x][y] = whitecolor;
                    }else{
                        src[x][y] = bordercolor;
                    }
                } else if (x<r&&y>(max-r)&&(r-x)*(r-x)+(y+r-max)*(y+r-max)>(r-1)*(r-1)){
                    // 左下圆角
                    if((r-x)*(r-x)+(y+r-max)*(y+r-max)>r*r){
                        src[x][y] = whitecolor;
                    }else{
                        src[x][y] = bordercolor;
                    }
                } else if (x>(max-r)&&y>(max-r)&&(x+r-max)*(x+r-max)+(y+r-max)*(y+r-max)>(r-1)*(r-1)){
                    // 右下圆角 
                    if((x+r-max)*(x+r-max)+(y+r-max)*(y+r-max)>r*r){
                        src[x][y] = whitecolor;
                    }else{
                        src[x][y] = bordercolor;
                    }
                } else {
                    if(((x>=r && x<=max-r) && (y==0||y==1||y==max-1||y==max)) || ((y>=r &&y<=max-r) && (x==0||x==1||x==max-1||x==max))){
                        // 四周除圆角的边框
                        src[x][y] = bordercolor;
                    } else {
                        // 图片值
                        src[x][y] = biTarget.getRGB(x, y);
                    }
                }
            }
        }
        return src;
    }
}
控制器类:

@Controller
@RequestMapping("")
public class QrCodeController {
    
    private static final Logger LOGGER = LoggerFactory.getLogger(QrCodeController.class);

    @Resource(name = "qrCodeService")
    QRCodeService qrCodeService;
    
    @RequestMapping("qrcode")
    public void generateQrCode(HttpServletRequest request,HttpServletResponse response){
        try {
            String code = request.getParameter("url");
            if(StringUtils.isBlank(code)){
                LOGGER.error("url is null");
                return;
            }
            String width = request.getParameter("width");
            String color = request.getParameter("color");
            String logo = request.getParameter("logo");
            OutputStream os = response.getOutputStream();
            if (StringUtils.isNotBlank(width) && StringUtils.isNotBlank(color) && StringUtils.isNotBlank(logo)){
                int my_width = Integer.valueOf(width);
                int my_color = Integer.valueOf(color);
                //int my_logo = Integer.valueOf(logo);
                LOGGER.info("hash logo");
                File logofile = new File("logo.jpg");
                qrCodeService.generateToStream(code, os, my_width, my_color, logofile);
            } else if (StringUtils.isNotBlank(width) && StringUtils.isNotBlank(color)){
                int my_width = Integer.valueOf(width);
                int my_color = Integer.valueOf(color);
                qrCodeService.generateToStream(code, os, my_width, my_color);
            } else if(StringUtils.isNotBlank(width)) {
                int my_width = Integer.valueOf(width);
                qrCodeService.generateToStream(code, os, my_width);
            } else {
                qrCodeService.generateToStream(code, os);
            }
            os.flush();
            os.close();
            LOGGER.info("generate qrcode succeed");
        } catch (IOException e) {
            LOGGER.error("generate qrcode error : ", e);
        }
    }
    
}
生成效果:


目录
相关文章
|
4月前
|
前端开发 小程序
微信小程序canvas画布绘制base64图片并保存图片到相册中
微信小程序canvas画布绘制base64图片并保存图片到相册中
|
9月前
|
Java Maven
让一句话生成一张二维码图片
让一句话生成一张二维码图片
|
JavaScript
vue里怎么生成带有图标logo的二维码?
vue里怎么生成带有图标logo的二维码?
269 0
vue里怎么生成带有图标logo的二维码?
|
移动开发 Android开发 iOS开发
iOS WebView长按网页里的图片识别图片中的二维码和保存图片
iOS WebView长按网页里的图片识别图片中的二维码和保存图片
iOS WebView长按网页里的图片识别图片中的二维码和保存图片
|
JavaScript 前端开发
带有logo的二维码
带有logo的二维码
带有logo的二维码
|
安全 JavaScript 前端开发
JavaScript 技术篇-如何实现在线logo网站制作后的logo去水印,免费制作无水印logo方法
JavaScript 技术篇-如何实现在线logo网站制作后的logo去水印,免费制作无水印logo方法
472 0
JavaScript 技术篇-如何实现在线logo网站制作后的logo去水印,免费制作无水印logo方法
|
程序员 C# 图形学
C# 生成二维码,彩色二维码,带有Logo的二维码及普通条形码
每次写博客,第一句话都是这样的:程序员很苦逼,除了会写程序,还得会写博客!当然,希望将来的一天,某位老板看到此博客,给你的程序员职工加点薪资吧!因为程序员的世界除了苦逼就是沉默。我眼中的程序员大多都不爱说话,默默承受着编程的巨大压力,除了技术上的交流外,他们不愿意也不擅长和别人交流,更不乐意任何人走进他们的内心!    废话少说,咱直接进入正题:    目前来说,比较流行的二维码生成方式有两种:一种是:QrCode.Net和谷歌的Zxing.Net,我个人比较倾向于使用ZXing.Net,今天本篇博客主要讲解Zxing.Net的使用。
1885 0
QRCode二维码生成方案及其在带LOGO型二维码中的应用(1)
原文:QRCode二维码生成方案及其在带LOGO型二维码中的应用(1) 提要:很多公司为商业宣传之需,常将企业LOGO加入二维码中,但如果LOGO遮挡区域足够地大,二维码就变得无法识别。
1484 0
QRCode二维码生成方案及其在带LOGO型二维码中的应用(2)
原文:QRCode二维码生成方案及其在带LOGO型二维码中的应用(2) 续前:QRCode二维码生成方案及其在带LOGO型二维码中的应用(1)  http://blog.csdn.net/johnsuna/article/details/8525038 首先我们来看看二维码的符号字符区域,然后再看看其编码流程。
1425 0
|
Shell C# 图形学
C#生成带logo的二维码
原文:C#生成带logo的二维码 带logo的二维码生成分为两步骤:首先根据输入的内容生成二维码图片,然后读取本地的logo图片,通过图片处理生成带logo的二维码。 生成的二维码效果如下: 下面直接贴出二维码生成类   QRCodeHelper.
1172 0