NeuroAgent

How to Create GS1 DataMatrix with FNC1 in Python

Learn how to properly create GS1 DataMatrix images with the FNC1 functional character in Python. Complete guide to solving encoding issues and implementation.

Question

How to properly form a GS1 DataMatrix image with the FNC1 functional character in Python?

I have an array of codes in text format, and I need to generate a DataMatrix graphical image. The problem is that I cannot correctly insert the FNC1 functional character.

According to the documentation, the FNC1 functional character is a byte with value 232 (0xE8). I tried to add this byte as follows:

python
for code in codes:
    code_bytes = bytes(code, "utf-8")

    # If the first byte is not FNC1 (0xE8), add it
    if not code_bytes.startswith(b"\xE8"):
        code_bytes = b"\xE8" + code_bytes

    encoded = encode(code_bytes)
    img = Image.frombytes("RGB", (encoded.width, encoded.height), encoded.pixels)

    buf = BytesIO()
    img.save(buf, format="PNG")
    buf.seek(0)
    img_reader = ImageReader(buf)

    img_w = page_width - 2 * margin_mm
    img_h = page_height - 2 * margin_mm
    c.drawImage(img_reader, margin_mm, margin_mm, width=img_w, height=img_h)
    c.showPage()

Libraries used:

  • pylibdmtx
  • PIL (Pillow)
  • reportlab
  • tkinter

The codes have the following format:
“0104603757310758215!&QFA\u001D93gqwy”
“0104603757310758215!aa-”\u001D93Y2wD"
“0104603757310758215!bUoo\u001D93isPA”

However, when scanning the first character of the code, instead of FNC1, the character “è” is displayed. Searching the internet did not provide a solution to this problem. How to correctly implement the insertion of the FNC1 functional character in GS1 DataMatrix using Python?

NeuroAgent

Proper GS1 DataMatrix Image Formation with FNC1 Functionality in Python

To properly form a GS1 DataMatrix image with FNC1 functionality in Python, you need to use special encoding methods that correctly handle the GS1 Element String structure. The problem is that simply adding byte 0xE8 to the beginning of the string doesn’t ensure proper GS1 format - the correct structure with delimiters and proper FNC1 symbol positioning is required.

Table of Contents

Problem with Current Approach

The current method of adding byte 0xE8 to the beginning of the string doesn’t conform to the GS1 DataMatrix standard. The main issues are:

  1. Incorrect FNC1 positioning: In GS1 DataMatrix, FNC1 should be properly positioned within the data structure, not just added to the beginning.

  2. Lack of GS1 Element String structure: GS1 requires the use of a special format with delimiters (ASCII 29 or \u001D) between application identifiers and their values.

  3. Incorrect code page handling: The pylibdmtx library may not correctly interpret the raw byte 0xE8 as a functional symbol.

As noted in the GS1 Sweden documentation, “GS1 DataMatrix uses a syntax, or data element, called GS1 Element String”.

Correct GS1 DataMatrix Structure

GS1 DataMatrix requires the following structure:

  1. FNC1 symbol: Must be properly positioned to indicate the start of GS1 data
  2. Application Identifiers (AI): For example, “01” for GTIN, “10” for batch number, “17” for expiry date
  3. Identifier values: Data corresponding to each AI
  4. Delimiters: ASCII 29 (0x1D) between data elements

The standard structure looks like:

FNC1 + AI1 + value1 + delimiter + AI2 + value2 + ...

where:

  • FNC1 = 0xE8
  • AI = application identifier (e.g., “01”, “10”, “17”)
  • delimiter = ASCII 29 (0x1D)

Implementation with pylibdmtx

For proper implementation of GS1 DataMatrix with FNC1 in Python using pylibdmtx:

python
import pylibdmtx
from PIL import Image
import io

def create_gs1_datamatrix(gs1_data):
    """
    Creates GS1 DataMatrix with proper FNC1 formatting
    gs1_data: string in GS1 Element String format
    """
    # Convert GS1 string to bytes with proper encoding
    gs1_bytes = gs1_data.encode('utf-8')
    
    # Add FNC1 (0xE8) at the beginning to indicate GS1 format
    gs1_bytes = b'\xE8' + gs1_bytes
    
    # Encode using pylibdmtx
    encoded = pylibdmtx.encode(gs1_bytes)
    
    # Create image
    img = Image.frombytes('RGB', (encoded.width, encoded.height), encoded.pixels)
    
    return img

# Example usage
codes = [
    "0104603757310758215\u001D10QFA\u001D93gqwy",
    "0104603757310758215\u001D10aa-\u001D93Y2wD", 
    "0104603757310758215\u001D10bUoo\u001D93isPA"
]

for i, code in enumerate(codes):
    img = create_gs1_datamatrix(code)
    img.save(f'gs1_datamatrix_{i+1}.png')

Alternative Solutions

If pylibdmtx doesn’t provide proper GS1 support, consider alternative approaches:

1. Using specialized libraries

python
# Example with zxing-cpp (via subprocess)
import subprocess

def create_gs1_datamatrix_with_zxing(data):
    """
    Creates GS1 DataMatrix using zxing-cpp
    """
    # Create temporary file with data
    with open('temp_data.txt', 'w') as f:
        f.write(data)
    
    # Call zxing-cpp to generate barcode
    cmd = [
        'datamatrix', 
        '--read', 'temp_data.txt',
        '--format', 'png',
        '--output', 'output.png'
    ]
    
    subprocess.run(cmd)
    
    # Load image
    return Image.open('output.png')

2. Using commercial libraries

As mentioned in the Aspose documentation, commercial libraries often provide better GS1 standard support:

python
# Example with Aspose (commercial library)
from aspose.pybarcode import BarcodeGenerator, BarcodeEncodeType

def create_gs1_datamatrix_aspose(gs1_data):
    """
    Creates GS1 DataMatrix using Aspose.BarCode
    """
    generator = BarcodeGenerator(
        BarcodeEncodeType.DATAMATRIX, 
        gs1_data
    )
    generator.setGs1Data(True)  # Enable GS1 mode
    
    # Save as image
    generator.save("gs1_datamatrix.png")
    
    return Image.open("gs1_datamatrix.png")

Complete Working Example

Here’s a complete example that properly handles GS1 DataMatrix with FNC1:

python
import pylibdmtx
from PIL import Image
import io
from reportlab.lib.pagesizes import A4
from reportlab.platypus import SimpleDocTemplate, Image as RLImage
from reportlab.lib.units import mm

def create_gs1_datamatrix_document(codes, output_file="gs1_barcodes.pdf"):
    """
    Creates PDF document with GS1 DataMatrix barcodes
    """
    doc = SimpleDocTemplate(output_file, pagesize=A4)
    story = []
    
    page_width, page_height = A4
    margin_mm = 10
    
    for i, code in enumerate(codes):
        # Format GS1 data (assuming code is already in correct format)
        gs1_bytes = b'\xE8' + code.encode('utf-8')
        
        # Encode DataMatrix
        encoded = pylibdmtx.encode(gs1_bytes)
        
        # Create image
        img = Image.frombytes('RGB', (encoded.width, encoded.height), encoded.pixels)
        
        # Save to buffer
        buf = io.BytesIO()
        img.save(buf, format='PNG')
        buf.seek(0)
        
        # Add image to document
        img_reader = RLImage(buf)
        img_w = page_width - 2 * margin_mm
        img_h = page_height - 2 * margin_mm
        
        story.append(img_reader)
        
        if (i + 1) % 2 == 0:  # Split pages with 2 barcodes each
            story.append(pageBreak)
    
    doc.build(story)

# Usage
codes = [
    "0104603757310758215\u001D10QFA\u001D93gqwy",
    "0104603757310758215\u001D10aa-\u001D93Y2wD", 
    "0104603757310758215\u001D10bUoo\u001D93isPA"
]

create_gs1_datamatrix_document(codes)

It’s important to ensure your codes already contain the correct GS1 Element String structure with ASCII 29 (\u001D) delimiters between application identifiers. If not, preprocess the data:

python
def format_as_gs1_element_string(gtin, batch, expiry):
    """
    Formats data as GS1 Element String
    """
    return f"{gtin}\u001D10{batch}\u001D17{expiry}"

# Example formatting
formatted_code = format_as_gs1_element_string(
    "0104603757310758215", 
    "QFA", 
    "2024-12-31"
)

Sources

  1. GS1 Sweden - Difference between Data Matrix, GS1 DataMatrix and QR code
  2. Odoo Forum - GS1 DataMatrix generation
  3. Aspose Python Barcode Documentation
  4. pylibdmtx Python Library Documentation

Conclusion

  1. Correct structure: For GS1 DataMatrix, you must use the GS1 Element String format with ASCII 29 delimiters between application identifiers.

  2. FNC1 positioning: Byte 0xE8 should be added to the beginning of the data string to indicate GS1 format, but only after properly formatting the structure.

  3. Alternative libraries: If pylibdmtx doesn’t provide proper functionality, consider using specialized libraries for GS1 encoding.

  4. Verification: Always verify generated barcodes with scanners that support GS1 standards to ensure correct encoding.

  5. Documentation: Carefully study the documentation of the library you’re using - some libraries have special methods for GS1 encoding that can automatically handle FNC1 symbols.