Generating a GS1QR barcode is simple until the payload contains a Group Separator. That single non-printable character, ASCII 29, is what tells a scanner where a variable-length Application Identifier field ends. Developers worked around it with manual byte assembly, custom encoders, or payload splitting, and every workaround carried a risk of producing symbols that scan but do not parse.

Aspose.BarCode for Python via .NET 26.6 removes that problem with a single flag. The encode_gs1_separator_in_byte_mode property forces the QR encoder to write GS1 group separators and the % character as raw bytes, preserving the exact GS1 structure. This tutorial covers the complete barcode generation and recognition workflow in python-net: installing the SDK, generating a compliant GS1QR symbol, and verifying at the code-point level that the separator survived the round trip.

Why Byte-Mode GS1 Separators Matter for GS1QR Barcodes

GS1QR is the two-dimensional carrier of choice in supply chain, healthcare, and retail, where a single symbol has to hold a product identifier, batch number, expiration date, and serial number in one structured payload. The GS1 Application Identifier syntax makes this possible, but it depends on the Group Separator to delimit fields whose length is not fixed.

Consider a payload combining AI (10) for batch number and AI (21) for serial number. Both are variable-length, so the scanner needs an explicit boundary between them. Without a correctly encoded separator, a downstream system reads one concatenated string instead of two fields. The barcode scans successfully and still delivers wrong dat, the worst kind of failure, because nothing in the scan event signals the problem.

Byte-mode encoding solves this at the source. The encoder stops interpreting the separator as a structural marker and writes it verbatim into the data segment. The practical benefits for Python developers are direct:

  • Compliance. The emitted symbol matches the GS1 General Specifications rather than approximating them.
  • Simpler code. No manual byte assembly, no custom encoder subclass, no post-processing pass.
  • Testability. The round trip is verifiable in a unit test by asserting on decoded code points.

Generating GS1QR Barcodes using Aspose.BarCode for Python

Aspose.BarCode for Python via .NET provides a high-level API for both barcode generation and recognition. Install it from PyPI:

pip install aspose-barcode-for-python-via-net

Two classes carry most of the work. BarcodeGenerator, from aspose.barcode.generation, builds and renders symbols. BarCodeReader, from aspose.barcode.barcoderecognition, decodes them. Generation settings are reached through a parameter tree on the generator instance, where symbology-specific options such as the QR settings live under parameters.barcode.qr.

Reference material is available on the product page, the documentation site, and the API reference.

If you have a license file, apply it once at application startup, before any generation or recognition call:

from aspose.barcode import License

license = License()
license.set_license("Aspose.BarCode.Python.NET.lic")

Generate GS1QR Barcode with Byte-Mode Separator

  1. Import the required types - BarcodeGenerator and EncodeTypes for generation, BarCodeReader and DecodeType for verification.
  2. Instantiate BarcodeGenerator with EncodeTypes.GS1QR and a GS1 payload string. Parentheses denote AI sections, as in (10)ASPOSE2001(21)ASPOSE2026.
  3. Enable byte-mode separator encoding by setting gen.parameters.barcode.qr.encode_gs1_separator_in_byte_mode = True.
  4. Set the output resolution so the rendered symbol is usable in print as well as on screen.
  5. Save the image to a lossless format, then read it back to confirm the encoding.

The following example demonstrates the complete workflow:

from aspose.barcode.barcoderecognition import BarCodeReader, DecodeType
from aspose.barcode.generation import BarcodeGenerator, EncodeTypes

# 1. Create a GS1QR Barcode with Sample AI Data
# (10) = Batch or Lot Number, (21) = Serial Number
gen = BarcodeGenerator(EncodeTypes.GS1QR, "(10)ASPOSE2001(21)ASPOSE2026")

# 2. Turn on Byte-Mode Encoding for GS1 Group Separators
gen.parameters.barcode.qr.encode_gs1_separator_in_byte_mode = True

# 3. Set a Print-Ready Resolution
gen.parameters.resolution = 300

# 4. Save the Barcode to a PNG File
gen.save("gs1qr_test.png")

# 5. Verify by Reading the Barcode Back
reader = BarCodeReader("gs1qr_test.png", DecodeType.GS1QR)
for result in reader.read_bar_codes():
    print("BarCode CodeText: " + result.code_text)

How it Works

  • BarcodeGenerator(EncodeTypes.GS1QR, "(10)ASPOSE2001(21)ASPOSE2026") creates a generator configured for the GS1QR symbology. The payload uses GS1 syntax, where (10) is the Batch or Lot Number AI and (21) is the Serial Number AI. The library parses the parenthesised form and inserts the separators the specification requires.
  • gen.parameters.barcode.qr.encode_gs1_separator_in_byte_mode = True activates the option introduced in 26.6. With it enabled, the encoder writes the group separator and % as raw bytes in the data segment instead of interpreting them.
  • gen.parameters.resolution = 300 renders at 300 DPI. Screen-only symbols are fine at the default, but anything destined for a label printer or packaging artwork should be generated at print resolution rather than upscaled afterwards.
  • gen.save("gs1qr_test.png") writes a lossless PNG, preserving the exact module pattern. This matters more for 2D symbols than for 1D, because a QR decoder samples a grid and is unforgiving of blurred module boundaries.
  • read_bar_codes() returns an iterable of BarCodeResult objects, and result.code_text holds the decoded payload including any control characters. In a console, the separator renders as nothing at all, which is exactly why the next section inspects code points instead of trusting the printed output.

Read and Verify the Generated Barcode

Printing the decoded string proves the symbol is readable, not that it is correct. Because the group separator is non-printable, a payload with a missing separator and one with a correct separator look identical in a terminal. Verification has to happen at the code-point level, which also makes it straightforward to assert in a test suite.

Steps

  1. Load the saved PNG with BarCodeReader and DecodeType.GS1QR.
  2. Iterate over the decoded results.
  3. Inspect each character’s Unicode code point, looking for U+001D.
  4. Split the payload on the separator and compare the fields against the original input.
from aspose.barcode.barcoderecognition import BarCodeReader, DecodeType

GROUP_SEPARATOR = "\x1d"

# Load the Barcode Image Generated Earlier
reader = BarCodeReader("gs1qr_test.png", DecodeType.GS1QR)
results = list(reader.read_bar_codes())

if not results:
    raise ValueError("No GS1QR barcode was detected in the image.")

for result in results:
    decoded = result.code_text
    print("Decoded GS1QR payload:", decoded)

    # Inspect the Code Point of Every Character
    for index, char in enumerate(decoded):
        label = repr(char) if char.isprintable() else "<non-printable>"
        print(f"Char {index}: {label} (U+{ord(char):04X})")

    # Confirm the Separator Survived the Round Trip
    if GROUP_SEPARATOR in decoded:
        fields = decoded.split(GROUP_SEPARATOR)
        print(f"Separator found. Payload splits into {len(fields)} field(s):")
        for field in fields:
            print("  -", field)
    else:
        print("Warning: no group separator present in the decoded payload.")

How it Works

  • Configuring the reader with DecodeType.GS1QR restricts recognition to that symbology, which is both faster and safer than scanning for all types, since it prevents a malformed symbol from being decoded as plain QR and quietly passing.
  • Materialising the results with list(...) before checking makes the empty case explicit. A recognition failure returns an empty iterable rather than raising, so an unguarded for loop over a failed read completes silently and reports success.
  • The code-point loop is the actual assertion. Seeing U+001D in the output confirms byte mode worked; its absence means the separator was dropped or transformed, regardless of how clean the printed payload looks.
  • Splitting on \x1d reconstructs the individual AI fields, giving you values that can be compared against the source data in a CI pipeline.

Get a Free License

Aspose offers a temporary free license that removes evaluation watermarks and unlocks full functionality for testing. Request one from the Aspose temporary license page.

Free Additional Resources

Conclusion

The encode_gs1_separator_in_byte_mode option replaces a category of manual byte handling with a single boolean. Set it on the QR parameters and GS1 group separators, along with the % character, are written into the symbol exactly as the specification requires.

This tutorial covered installation, generating a GS1QR symbol with byte-mode separators, and verifying the result at the code-point level rather than trusting console output. That verification step is the part most worth keeping. In GS1 workflows, a barcode that scans is not the same as a barcode that is correct, and a code-point assertion in your test suite is what tells the two apart before the labels reach production.

FAQs

  1. What does the encode_gs1_separator_in_byte_mode option do? It instructs the QR encoder to emit the GS1 group separator (ASCII 29) and the % character as raw byte data rather than treating them as structural markers, so they survive intact in the barcode payload.

  2. Do I need a special license to use the GS1QR features? GS1QR is part of the standard Aspose.BarCode library. You can evaluate it without a license, and request a free temporary license from the Aspose website to remove evaluation watermarks.

  3. Can I use this feature with other QR code types? No. The flag applies to the GS1QR encode type. Standard QR and Micro QR encoders ignore it, because GS1 Application Identifier parsing does not apply to them.

  4. Is the generated barcode image lossless? Saving to PNG, the default, produces a lossless image that preserves the exact module pattern. Avoid JPEG for barcodes, as its compression artifacts blur module edges and reduce read rates.

  5. How do I verify that the separator was encoded correctly? Read the image back with BarCodeReader using DecodeType.GS1QR and inspect the code points of the decoded string. A U+001D in the payload confirms the group separator was encoded in byte mode.

  6. Does enabling byte-mode affect barcode size? Byte mode can require more data bits than alphanumeric mode, which may push the symbol to a larger QR version. The library automatically selects the smallest version that fits, so the increase is usually one version step at most.

  7. Which version of Aspose.BarCode introduced this option? The encode_gs1_separator_in_byte_mode property was added in Aspose.BarCode for Python via .NET 26.6. Earlier versions require manual byte manipulation to embed group separators.

Read More