[Python]在Windows系统中使用ZXing模块实现二维码、条形码读码,pythonzxing,??需要实现Pyth


??需要实现Python读取图片中二维码、条形码信息。前段时间研究使用zbarlight模块,费了很大功夫安装调试好,但是发现有些图片读取不正确,而且如果图片中二维码倾斜,就读取不了,不能满足要求。昨天琢磨着试一试ZXing,下载ZXing模块安装后,却一直报错。打开模块源码仔细分析,原来该模块是通过调用java程序,使用ZXing的java库来实现的,通过分析命令行输出得到解码结果。忙活了一天多,各种测试、查资料,终于解决了问题。调试过程非常艰辛,现将做法整理如下(Windows 10系统):

?一、 因为需要调用java程序,必须安装jdk。

下载java安装程序,根据提示一步步安装。

  下载地址:http://www.oracle.com/technetwork/java/javase/downloads/index.html。

设置环境变量。

  添加JAVA_HOME环境变量,其值设置为jdk安装目录。将java运行程序所在目录(%JAVA_HOME%\bin)添加到PATH。

在命令行输入java -version并执行,如果没有问题则说明安装成功。

?二、下载ZXing的jar库文件,以及所需java库文件。

下载ZXing Core和ZXing Java SE Extensions库文件。

  登录网址http://www.mvnrepository.com,在搜索栏中输入"zxing"并查找,就能找到这两个库,下载库文件并将其分别改名为core.jar和javase.jar。

下载 JCommander库文件。

  在测试中,安装了上面两个库以后,仍然报错,错误信息中提示JCommander模块找不到,后来下载了这个库文件,经过多番调试,终于成功。登录网址http://www.mvnrepository.com,在搜索栏中输入"jcommander"并查找,就能找到这个库,下载库文件并将其改名为jcommander.jar。

创建一个目录,并将以上三个jar文件复制到其中。

  这个目录可以创建在java安装目录下。我是在java目录下建了一个名为jar的文件夹,将上面三个文件复制到里面。

设置环境变量。

  添加ZXING_JAR_PATH环境变量,将其值设为上面创建的那个文件夹的绝对路径,我的路径是“d:\java\jar”。

?三、在ZXing源代码基础上进行修改,实现二维码、条形码解码功能;增加了两个函数,解决了不支持图片Windows格式绝对路径的问题。

#导入模块import subprocess, re, osclass BarCodeReader():    """    解码器类,调用java执行ZXing库命令实现解码,通过分析输出获得结果。    此模块在ZXing源码基础上修改,改动较大。    """    #ZXing库路径    location = ""    #ZXing库    libs = ["javase.jar", "core.jar", "jcommander.jar"]    #subprocess.Popen参数    args = ["java", "-cp", "LIBS", "com.google.zxing.client.j2se.CommandLineRunner"]    def __init__(self, loc=None):        """        初始化函数,参数loc设置ZXing库所在位置        """                #如果loc为空或者不是字符串对象,读取环境变量ZXING_JAR_PATH的值(没找到就设为空字符串)        if not loc or not isinstance(loc,str):            loc = os.environ.get("ZXING_JAR_PATH", "")                #如果loc不为空,在末尾加上‘\‘,否则设为默认值(即在当前目录的zxing子目录下)        if loc:            loc = loc.rstrip("\\") + "\\"        else:            loc = "zxing\\"            #设置location        self.location = loc    def decode(self, files, try_harder = False, qr_only = False):        """        解码方法,参数files可以是一个文件名(字符串),也可以是一个文件名列表。        """                #根据try_harder和qr_only参数设置,添加相应选项        if try_harder:            self.args.append("--try_harder")        if qr_only:            self.args.append("--possibleFormats=QR_CODE")        #为ZXing库加上路径        libraries = [self.location + lib for lib in self.libs]                #生成命令列表        cmd = [ c if c != "LIBS" else os.pathsep.join(libraries) for c in self.args ]                #单文件标志设为False        SINGLE_FILE = False                #如果files不是列表,将文件files添加到cmd列表,单文件标志设为True        if not isinstance(files, list):            cmd.append(files)            SINGLE_FILE = True        #否则,将文件列表files添加到cmd列表        else:            cmd += files                #利用subprocess.Popen函数执行命令        (stdout, stderr) = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True).communicate()                #初始化编码列表        codes = []                #分析输出内容        file_results = stdout.split("\nfile:")        for result in file_results:            lines = result.split("\n")            if re.search("No barcode found", lines[0]):                codes.append(None)            else:                codes.append(BarCode(result))        #如果是单文件,返回第一个BarCode对象;否则,返回BarCode对象列表        if SINGLE_FILE:            return codes[0]        else:            return codesclass BarCode:    """    BarCode信息类,包含解码所得各项信息。    此模块基本使用了ZXing源码,为方便使用,添加了几个属性。    """    format = ""    points = []    data = ""    raw = ""    def __init__(self, zxing_output):        lines = zxing_output.split("\n")        raw_block = False        parsed_block = False        point_block = False        self.points = []        for l in lines:            m = re.search("format:\s([^,]+)", l)            if not raw_block and not parsed_block and not point_block and m:                self.format = m.group(1)                continue            if not raw_block and not parsed_block and not point_block and l == "Raw result:":                raw_block = True                continue            if raw_block and l != "Parsed result:":                self.raw += l + "\n"                continue            if raw_block and l == "Parsed result:":                raw_block = False                parsed_block = True                continue            if parsed_block and not re.match("Found\s\d\sresult\spoints", l):                self.data += l + "\n"                continue            if parsed_block and re.match("Found\s\d\sresult\spoints", l):                parsed_block = False                point_block = True                continue            if point_block:                m = re.search("Point\s(\d+):\s\(([\d\.]+),([\d\.]+)\)", l)                if (m):                    self.points.append((float(m.group(2)), float(m.group(3))))                #去除多余换行符        self.raw = self.raw.rstrip("\n")        self.data = self.data.rstrip("\n")    @property    def Format(self):        """        返回编码格式        """        return self.format            @property    def Data(self):        """        返回编码数据        """        return self.data            @property    def Points(self):        """        返回坐标点        """        return self.points            @property    def RawData(self):        """        返回解码所得原始数据        """        return self.rawdef GetCodeString(filename):    """    解码函数,只处理单个文件,参数为文件名(含路径)。    返回编码字符串,如果未能成功解码或未找到条码,返回空字符串。    """        #将‘\‘替换成‘/‘    filename = filename.replace("\\", "/")    #如果带有盘符(绝对路径),前面加上‘file:/‘    if re.match(‘^[A-Za-z]:‘, filename):        filename = "file:/" + filename    #创建解码器对象    zxcode = BarCodeReader()    #解码,并将结果保存到barcode    barcode = zxcode.decode(filename)    #如果结果为None,返回空串,否则返回编码字符串    if barcode is None:        return ""    else:        return barcode.Datadef GetCodeObject(filename):    """    解码函数,只处理单个文件,参数为文件名(含路径)。    返回编码对象,其属性如下:        Data,编码信息;        Format,编码类别;        Points,坐标点;        RawData,未处理的编码信息。    如果未能成功解码或未找到条码,返回None    """        #将‘\‘替换成‘/‘    filename = filename.replace("\\", "/")    #如果带有盘符(绝对路径),前面加上‘file:/‘    if re.match(‘^[A-Za-z]:‘, filename):        filename = "file:/" + filename    #创建解码器对象    zxcode = BarCodeReader()    #解码,并将结果保存到barcode    barcode = zxcode.decode(filename)    #返回结果    return barcode

?四、测试。将上述代码保存到zxing.py文件中,编辑测试代码如下:

from zxing import GetCodeString,GetCodeObjectresult = GetCodeString("d:\\barcode.png")print(result)result = GetCodeObject("d:\\qr.png")if result:    print("Format:", result.Format)    print("Data:  ", result.Data)    print("Points:")    for point in result.Points:        print(point)

?五、可以将以上面的代码安装到Python库(注册为zxing模块)。

下载python-zxing模块。下载地址为https://github.com/oostendo/python-zxing。

解压缩到python-zxing文件夹。

将python-zxing\zxing文件夹内__init__.py文件的内容替换成第三步的代码。

在python-zxing文件夹下打开命令行,运行python setup.py install即可。

同样可以使用第四步的代码进行测试。

[Python]在Windows系统中使用ZXing模块实现二维码、条形码读码

评论关闭