使用任何合适的库/模块在 python 中生成 GS1 DataMatrix 代码。包括 FNC1 前导符号

Generate GS1 DataMatrix code in python using any suitable library/module. Include FNC1 leading symbol

提问人:Pavel Legkodymov 提问时间:2/15/2023 最后编辑:Pavel Legkodymov 更新时间:7/1/2023 访问量:532

问:

一项任务是使用任何合适的库/模块在 python 中生成 GS1 DataMatrix 代码(稍后在文本中 - GS1 DM)。问题在于如何在生成 DM 代码时包含前导 FNC1 功能符号。 GS1 DM被广泛用于序列化和跟踪和追溯领域,例如用于药品序列化。 GS1 DataMatrix 是一个普通的 DataMatrix(后面的文本 - DM),但带有前导 FNC1 符号,让扫描设备可以识别这是 GS1 DataMatrix 而不是通常的 DataMatrix。

GS1 DataMatrix 中将包含的用户数据示例如下:

    01048123231123452172KAVEK5HqOQW{GS}91KZF0{GS}92endxMQYZAymmN9rTCsWwm4gcU1oihAn726B86OLBnh0=
    01048702231123452179LimKz7sKYyF{GS}91KZF0{GS}92VllFTqxoBYKxfjjd/uLpXe4Sbm3+3foXpen0DLGIgWQ=

这些示例是单个药品包装的唯一标识符 + 所谓的加密密钥和加密代码。此类标识符在哈萨克斯坦、乌兹别克斯坦和白俄罗斯、俄罗斯等独联体国家用于序列化。{GS1} 是带有 ASCII 29 代码的组分隔符符号。这与任务本身无关,只是为了给你一些背景信息。

**我能够做什么:**使用 python 模块 pylibdmtx 生成具有所需用户内容的 DataMatrix 代码(但不是 GS1 DataMatrix 代码)。

**什么是问题:**当我使用上述 python 库生成 DM 时,我未能找到任何解决方案将 FNC1 符号包含在 DataMatrix 代码中以将此代码“转换”为 GS1 DataMatrix。

**到目前为止我的发现和问题**(如果我错了,请纠正我):

  • FNC1 符号不包含在 ASCII 代码表或 UTF-8 或 ASCII 256 符号表中(无论 ASCII 256 是什么意思,因为没有这种特定的编码)。据我了解,它不包含在任何现有编码中,因为 FNC1:a) 没有图形表示,b) 不打算成为任何编码的一部分,因为它是一个功能“符号”,是 GS1 DM 标准本身的一部分。不管这意味着什么。
  • 在许多来源/链接中,我发现 FNC1 在“扩展 ASCII 表”中具有代码 232 的信息。但是,据我了解,事实并非如此,因为由于我在上一点中给出的原因,FNC1 未包含在任何编码表中。例如,对于 UTF-8 或其他编码,带有代码 232 的符号是“è”或其他符号,这绝对不是 FNC1,因为 FNC1 不能有任何图形表示。
  • 如果您使用一些在线工具生成 DM 代码(如此 https://barcode.tec-it.com/en/GS1DataMatrix,请尝试将 \F 放在包含 GS 组分隔符符号的位置。前导 FNC1 由工具自动添加),然后使用转义序列(例如以 {FNC1} 的形式)将 FNC1 包含在 DataMatrix 和其他代码格式中。但是当我自己通过 python 代码生成 FNC1 时,它没有回答如何将 FNC1 包含在 DM 中的问题。当您选择 GS1 DataMatrix 格式时,某些工具会自动将 FNC1 作为前导符号。0104607045191708211NSBA931BA63A\F91EE07\F92ooqoeKYx9KuYMj2ZZudhhFVAM5ip2M/R3bo5+Je4QE4=
  • 生成 DM 时,代码 FNC1 应由库/模块本身直接包含在 DM 中。库应在DM代码“渲染”/绘制时包括FNC1。但是我还没有找到任何 python 库来生成确切的 GS1 DM 代码,而只是生成 DM 代码。
  • 用于 python 的 DataMatrix 生成的现有库大多非常纯粹地记录在案,尤其是在使用细节或示例方面。甚至根本没有任何文档。
  • 当我通过手机上的任何扫描应用程序扫描不同真实实体药品包装上的 DM 代码(具有 GS1 DM 格式)时,我总是得到 {GS1} 符号(ASCII 表中带有代码 29 的组分隔符符号)作为编码到 DM 的数据的前导符号。但是,据我了解,FNC1 作为前导符号应该被扫描仪跳过,纯粹用于 GS1 DM 格式识别。所以我想知道这是否是移动应用程序端对 GS1 DM 的错误处理,还是制造商对 GS1 DM 构建的错误(可能性要小得多)。或者也许我以错误的方式理解了这个问题。
  • 我还没有找到任何关于堆栈溢出的合适答案,尽管在同一个问题上有很多答案

这是我的完整代码:

    from PIL import Image
    from pylibdmtx.pylibdmtx import encode
    from datetime import datetime
    import os
    
    # FNC1 = chr(232)
    # FNC1 = FNC1.encode("utf-8")
    # FNC1 = bytes.fromhex("E8").decode('utf-8')
    GS1 = chr(29)
    
    DMs = []
    
    class Dm:
        
        def __init__(self, gtin, sn, key, code):
            self.gtin =     gtin
            self.sn =       sn
            self.key =      key
            self.code =     code
            self.dmImg =    self.generateDmImg()
    
        def strToUTF8(self, str):
            return str.encode('utf_8')
        
        def __str__(self):
            return self.getDmContent()
    
        def getSgtin(self):
            return "01" + self.gtin + "21" + self.sn
    
        def getDmContent(self):
            str = "01" + self.gtin + "21" + self.sn + GS1 + "91" + self.key + GS1 + "92" + self.code
            # str = FNC1 + "01" + self.gtin + "21" + self.sn + GS1 + "91" + self.key + GS1 + "92" + self.code
    
            return str 
    
        def generateDmImg(self):
            dmContent = self.getDmContent()
            encoded = encode(dmContent)
            dmImg = Image.frombytes('RGB', (encoded.width, encoded.height), encoded.pixels)
            return dmImg
    
        def saveDmImgToFile(self, filename):
            self.dmImg.save(filename)
    
    def read_file(filename):
    
        # read text strings from the file
        with open(filename) as f:
            text_strings = f.readlines()
    
        return text_strings
    
    def getListOfDMs(text_strings):
    
        DMs = []
    
        for text in text_strings:
    
            if (len(text.strip()) > 0):
                text_split = text.split(";")
                dm = Dm(text_split[0].strip(), text_split[1].strip(), text_split[2].strip(), text_split[3].strip())
                DMs.append(dm)   
            
        return DMs
        
    # ============ MAIN PROGRAM =================
    
    # res = read_file("src_files/source1.csv")
    res = read_file("source1.csv")
    DMs = getListOfDMs(res)
    
    # for dm in DMs: 
    #     print(dm)
     
    # generate a PNG image for each text string
    i = 1
    for dm in DMs:
        now = datetime.now()
        timestamp = now.strftime("%d_%m_%Y_%H_%M_%S")
        dm.saveDmImgToFile(os.path.join("results", dm.sn + "_" + timestamp + "_" + str(i) + ".png"))
        i += 1
    
    # dm = DMs[0]
    # now = datetime.now()
    # timestamp = now.strftime("%d_%m_%Y_%H_%M_%S")
    # dm.saveDmImgToFile(os.path.join("results", dm.sn + "_" + timestamp + "_" + str(i) + ".png"))

下面是 source1.csv 文件的文本示例(4 列是:GTIN、SN、加密密钥、加密代码):

    04812323112345;72KAVEK5HqOQW;KZF0;endxMQYZAymmN9rTCsWwm4gcU1oihAn726B86OLBnh0=
    04812323112345;79LimKz7sKYyF;KZF0;VllFTqxoBYKxfjjd/uLpXe4Sbm3+3foXpen0DLGIgWQ=
    04812323112345;7GaGJ1jCrfxID;KZF0;c2l2SH8LOYmbZK95S8ENwhCQXjmwKWd5BgfA+Pwv6nE=
    04812323112345;7HKrat9IGg2wZ;KZF0;cmt5NuKP23flUwDyJolFj7NMVR+K7vALjEO3ktFToGY=
python 数据矩阵 GS1-Datamatrix

评论


答:

0赞 bjallamo 7/1/2023 #1

对于 GS1 DataMatrix,AIM 代码类型必须解码为“]d2”。“]d1” 是 DataMatrix。 为此,您需要将第一个字符设置为 FNC1,但大多数库不会正确编码以将代码标识为 GS1。 treepoem 支持 GS1 DataMatrix,并在需要时自动添加 FNC1 和 GS 字符。

from treepoem import generate_barcode
from PIL import Image

def generate_and_print(gtin, serial_number, expiry_date, batch_number):
    # Generate datamatrix
    datamatrix = generate_barcode(
        barcode_type='gs1datamatrix',
        data=f"(01){gtin}(21){serial_number}(17){expiry_date}(10){batch_number}",
        options={"parsefnc": True, "format": "square", "version": "26x26"})
    
    # Resize datamatrix to desired size
    dm_size_px = (120, 120)
    datamatrix = datamatrix.resize(dm_size_px, Image.NEAREST)

    # Create white picture
    picture_size_px = (200, 200)
    picture = Image.new('L', picture_size_px, color='white')

    # Position the datamatrix
    barcode_position_px = (40, 40)
    picture.paste(datamatrix, barcode_position_px)

    # Save the image
    picture.save("datamatrix.png")

gtin = "01234567890128"
serial_number = "01234567891011"
expiry_date = "250731"
batch_number = "DATAMATRIXTEST"

generate_and_print(gtin, serial_number, expiry_date, batch_number)