java,python各自实现替换图片中的二维码

wylc123 1年前 ⋅ 4913 阅读

JAVA方法:可以设置替换图片中原有二维码的图片,生成或覆盖原来的图片。

上代码:

QRCodeTools.java

/**
 * @author SongBin on 2019/10/31.
 */
package com.wylc.eshop.common.utils.qrcode;

import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;


public class QRCodeTools {

    /**
     *
     * @Title: deEncodeByPath
     * @Description: 替换原图片里面的二维码
     * @param @param filePath
     * @param @param newPath    设定文件
     * @return void    返回类型
     * @throws
     */
    public static void deEncodeByPath(String filePath, String newPath) {

        // 原图里面二维码的url
        String originalURL = null;
        try {
            // 将远程文件转换为流
            BufferedImage readImage = ImageIO.read(new File(filePath));
            LuminanceSource source = new BufferedImageLuminanceSource(readImage);
            Binarizer binarizer = new HybridBinarizer(source);
            BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);

            Map<DecodeHintType, Object> hints = new HashMap<DecodeHintType, Object>();
            hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
            Result result = null;
            result = new MultiFormatReader().decode(binaryBitmap, hints);
            originalURL = result.getText();

            // 解码
            ResultPoint[] resultPoint = result.getResultPoints();
            System.out.println("原二维码里面的url:" + originalURL + ",\npoints1: " + resultPoint[0] + ",\npoints2: " + resultPoint[1] + ",\npoints3: "
                    + resultPoint[2]);

            // 获得二维码坐标
            float point1X = resultPoint[0].getX();
            float point1Y = resultPoint[0].getY();
            float point2X = resultPoint[1].getX();
            float point2Y = resultPoint[1].getY();

            // 替换二维码的图片文件路径
            BufferedImage writeFile = ImageIO.read(new File(newPath));

            // 宽高
            final int w = (int) Math
                    .sqrt(Math.abs(point1X - point2X) * Math.abs(point1X - point2X) + Math.abs(point1Y - point2Y) * Math.abs(point1Y - point2Y))
                    + 12 * (7 - 1);
            final int h = w;

            Hashtable<EncodeHintType, Object> hints2 = new Hashtable<EncodeHintType, Object>();
            hints2.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
            hints2.put(EncodeHintType.CHARACTER_SET, "UTF-8");
            hints2.put(EncodeHintType.MARGIN, 1);

            Graphics2D graphics = readImage.createGraphics();
            //此处,偏移,会有定位问题
            int x = Math.round(point1X) - 36;
            int y = Math.round(point2Y) - 36;

            // 开始合并绘制图片
            graphics.drawImage(writeFile, x, y, w, h, null);
            // logo边框大小
            graphics.setStroke(new BasicStroke(2));
            // //logo边框颜色
            graphics.setColor(Color.WHITE);
            graphics.drawRect(x, y, w, h);
            readImage.flush();
            graphics.dispose();

//            // 打印替换后的图片
            NewImageUtils.generateWaterFile(readImage, "F:\\image\\zfb.png");
        }

        catch (IOException e) {
            System.out.println("资源读取失败" + e.getMessage());
            e.printStackTrace();
        }
        catch (NotFoundException e) {
            System.out.println("读取图片二维码坐标前发生异常:" + e.getMessage());
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        deEncodeByPath("F:\\image\\zfb.png", "F:\\image\\gzh.jpg");
    }
}

NewImageUtils.java

/**
 * @author SongBin on 2019/10/31.
 */
package com.wylc.eshop.common.utils.qrcode;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class NewImageUtils {
    /**
     *
     * @Title: 构造图片
     * @Description: 生成水印并返回java.awt.image.BufferedImage
     * @param file
     *            源文件(图片)
     * @param waterFile
     *            水印文件(图片)
     * @param x
     *            距离右下角的X偏移量
     * @param y
     *            距离右下角的Y偏移量
     * @param alpha
     *            透明度, 选择值从0.0~1.0: 完全透明~完全不透明
     * @return BufferedImage
     * @throws IOException
     */
    public static BufferedImage watermark(File file, File waterFile, int x, int y, float alpha) throws IOException {
        // 获取底图
        BufferedImage buffImg = ImageIO.read(file);
        // 获取层图
        BufferedImage waterImg = ImageIO.read(waterFile);
        // 创建Graphics2D对象,用在底图对象上绘图
        Graphics2D g2d = buffImg.createGraphics();
        int waterImgWidth = waterImg.getWidth();// 获取层图的宽度
        int waterImgHeight = waterImg.getHeight();// 获取层图的高度
        // 在图形和图像中实现混合和透明效果
        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
        // 绘制
        g2d.drawImage(waterImg, x, y, waterImgWidth, waterImgHeight, null);
        g2d.dispose();// 释放图形上下文使用的系统资源
        return buffImg;
    }

    /**
     * 输出水印图片
     *
     * @param buffImg
     *            图像加水印之后的BufferedImage对象
     * @param savePath
     *            图像加水印之后的保存路径
     */
    public  static void generateWaterFile(BufferedImage buffImg, String savePath) {
        int temp = savePath.lastIndexOf(".") + 1;
        try {
            ImageIO.write(buffImg, savePath.substring(temp), new File(savePath));
        } catch (IOException e1) {
            e1.printStackTrace();
        }
    }

    /**
     *
     * @param args
     * @throws IOException
     *             IO异常直接抛出了
     * @author bls
     */
    public static void main(String[] args) throws IOException {
        String sourceFilePath = "D://img//di.png";
        String waterFilePath = "D://img//ceng.png";
        String saveFilePath = "D://img//new.png";
        NewImageUtils newImageUtils = new NewImageUtils();
        // 构建叠加层
        BufferedImage buffImg = NewImageUtils.watermark(new File(sourceFilePath), new File(waterFilePath), 0, 0, 1.0f);
        // 输出水印图片
        newImageUtils.generateWaterFile(buffImg, saveFilePath);
    }
}

Python方法:提供logo图片根据原来的二维码解析内容,结合新logo图片生成新的二维码覆盖原来的二维码。

上代码:

#!/usr/bin/env python
# _*_coding:utf-8_*_
__author__ = 'Jun'
__time__ = '2019/4/25 10:48'

#识别图片中的二维码,并对二维码进行替换,经过多次验证,识别率极高,替换效果很好,特分享出来,供需要的兄弟参考

import pyzbar.pyzbar as pyzbar
import numpy as np
import cv2
import qrcode
from PIL import Image
import urllib.request

# 生成新的二维码图片并覆盖原图
def detect(im, save_path=None):
    # 解析图片中的二维码内容
    results = pyzbar.decode(im)
    points = []
    # 获取所有解析对象
    for code in results:
        points = code.polygon
    # 如果这些点不形成四边形,则找到一个
    if len(points) > 4:
        hull = cv2.convexHull(np.array([point for point in points], dtype=np.float32))
        hull = list(map(tuple, np.squeeze(hull)))
    else:
        hull = points
    # 将cv2对象转换为Image对象
    img = Image.fromarray(cv2.cvtColor(im, cv2.COLOR_BGR2RGB))
    # 若二维码解析成功,则生成新的二维码并覆盖
    if hull:
        # 获取二维码解析数据
        data = results[0].data.decode("utf-8")
        if data:
            width = results[0].rect.width + 2
            height = results[0].rect.height + 2
            left = results[0].rect.left - 1
            top = results[0].rect.top - 1
            # 生成带中心图标的二维码  data为原来的二维码数据,可以替换为自己的数据
            qr_code_img = make_qr_code_with_icon(data, 'F:/image/log.jpg')
            # 设置二维码的尺寸
            qr_code_img = qr_code_img.resize((width, height), Image.ANTIALIAS)
            # 将原图上的二维码替换为新的二维码
            img.paste(qr_code_img, (left,top))
    # 保存新生成的图片
    if save_path:
        img.save(save_path)
    # 显示原图和新生成的图片
    img.show()
    cv2.imshow('imshow', im)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    return save_path

# 生成新的带中心logo的二维码图片
def make_qr_code_with_icon(content, icon_path):
    # 生成一张二维码图片
    qr_code_maker = qrcode.QRCode(version=5,
                                  error_correction=qrcode.constants.ERROR_CORRECT_L,
                                  box_size=10,
                                  border=0,
                                  )
    qr_code_maker.add_data(data=content)
    qr_code_maker.make(fit=True)
    qr_code_img = qr_code_maker.make_image(fill_color="black", back_color="white").convert('RGBA')
    # 加载中心图标,设置大小
    icon_img = Image.open(icon_path)
    code_width, code_height = qr_code_img.size
    icon_img = icon_img.resize((code_width // 4, code_height // 4), Image.ANTIALIAS)
    # 将图标放置于原始图片上
    qr_code_img.paste(icon_img, (code_width * 3 // 8, code_width * 3 // 8))
    return qr_code_img;

# 根据图片路径获取cv2对象
def get_cv2_image(img_path):
    image = None
    if img_path.startswith('http:') or img_path.startswith('https:'):
        # 从网络路径加载图片资源
        resp = urllib.request.urlopen(img_path)
        image = np.asarray(bytearray(resp.read()), dtype="uint8")
        image = cv2.imdecode(image, cv2.IMREAD_COLOR)
    else:
        # 从本地获取图片资源
        image = cv2.imread(img_path)
    return image

if __name__ == '__main__':
    # img_path = 'https://bpb-test.oss-cn-beijing.aliyuncs.com/test/1.jpg?OSSAccessKeyId=LTAIBGsGFQH2Kxns&Expires=1555700356&Signature=%2FgLKrl4Fyjko%2FD97OmJGHlYea3s%3D'
    img_path = 'F:/image/zfb1.jpg'
    image = get_cv2_image(img_path)
    detect(image)
更多内容请访问:IT源点

相关文章推荐

全部评论: 0

    我有话说: