Every QR generator picks an encoding mode for you by default, and most of the time that default is fine. It stops being fine the moment you need control over it — a numeric ID next to a product code, a block of Japanese text you don’t want stored as UTF-8, or a payload where you need the same bytes out every time you generate it. This guide shows how to set QR code encoding modes in Python explicitly, using Aspose.BarCode for Python via .NET, so a single QR symbol can carry a numeric segment, an alphanumeric segment, a byte segment, and a Kanji segment — each stored in the mode that fits it best.
Aspose.BarCode calls these compaction modes in its own API names (QrExtCompactionMode) and the QR specification itself calls them encoding modes. They’re the same four modes under two names, and this guide uses “encoding mode” throughout since that’s the term the specification and most Python QR libraries use.
Why QR Encoding Modes Affect Symbol Size and Scan Reliability
A QR code’s physical size is driven by how many bits its payload needs, and bits per character depend entirely on the encoding mode used for that segment. The specification defines four data modes with markedly different densities:
| Mode | Character set | Storage | Cost per character |
|---|---|---|---|
| Numeric | Digits 0-9 | 3 digits per 10 bits | 3.33 bits |
| Alphanumeric | Digits, uppercase A-Z, space, $%*+-./: | 2 characters per 11 bits | 5.5 bits |
| Byte | Any 8-bit data, typically UTF-8 | 1 byte per 8 bits | 8 bits |
| Kanji | Shift-JIS double-byte characters | 1 character per 13 bits | 13 bits |
A 30-digit identifier costs roughly 100 bits in numeric mode and 240 bits in byte mode. That gap is often enough to push the symbol up several QR versions, and a higher version means more modules in the same printed area — smaller modules, and a lower read rate on low-resolution cameras, curved packaging, and worn labels.
Automatic mode selection handles most payloads well. It becomes limiting when you know the shape of your data and the analyzer does not: a long numeric run broken by a single letter, Japanese text that byte mode would spend three UTF-8 bytes per character on, or a fixed-format identifier where you want deterministic output across library versions.
When Setting the Mode Manually Is Worth It
Mode switching is not free. Every segment boundary writes a four-bit mode indicator plus a character-count field of eight to sixteen bits depending on the QR version. Over-segmenting a payload can produce a larger symbol than letting the generator decide.
Setting the mode explicitly pays off when:
- The payload contains long, homogeneous runs — a 40-digit serial, a paragraph of Kanji.
- You are encoding Japanese text and want Kanji mode at 13 bits per character rather than byte mode at 24.
- You need reproducible, byte-identical output for regression tests or checksum validation.
It is usually not worth the added complexity for short payloads, data that alternates type every few characters, or URLs, which automatic analysis already handles well. The measurement subsection below shows how to check which case you’re in.
Two Ways to Set QR Encoding Modes in Python
Aspose.BarCode offers two routes to the same encoded result, and it’s worth knowing why both exist before writing code.
QrExtCodetextBuilder | Inline EXTENDED selectors | |
|---|---|---|
| Mode set by | Method calls with enum values | Backslash markers in the string |
| Mistakes caught | At the call site | Only at decode time |
| Escaping concerns | None | \\ escaping, or raw strings |
| Best for | Application code | Codetext from config, a database, or another system |
The builder is the better default. QrExtCompactionMode.NUMERIC either exists or raises an AttributeError immediately, whereas a mistyped \numm in a string silently becomes payload data and only surfaces when someone scans the label. Both approaches feed the same QREncodeMode.EXTENDED generator setting, so you can move between them without changing anything downstream.
Set QR Code Encoding Modes in Python: Step by Step
1. Install and Prepare the Development Environment
Aspose.BarCode for Python via .NET is a cross-platform library supporting generation, recognition, and manipulation across more than 50 symbologies, QR included. Install from PyPI:
pip install aspose-barcode-for-python-via-net
Confirm the version, since these APIs require 26.6 or newer:
pip show aspose-barcode
Then verify the import resolves. The package binds to a .NET runtime, so a successful import tells you more than the presence of files on disk:
from aspose.barcode.generation import QREncodeMode, QrExtCompactionMode
print("Aspose.BarCode imported successfully.")
print("EXTENDED mode available:", hasattr(QREncodeMode, "EXTENDED"))
print("Encoding modes:", [m for m in dir(QrExtCompactionMode) if m.isupper()])
Output:
Aspose.BarCode imported successfully.
EXTENDED mode available: True
Encoding modes: ['ALPHA_NUMERIC', 'AUTO', 'BYTES', 'KANJI', 'NUMERIC']
If EXTENDED is missing, you are on a release older than 26.6 and need to upgrade before continuing.
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")
2. Set the Encoding Mode for Each Segment with QrExtCodetextBuilder
QrExtCodetextBuilder holds an ordered list of segments. Each call appends data together with the encoding mode that should store it, and get_extended_codetext() assembles them into the extended-format string the generator understands.
- Import the generation classes.
- Create a
QrExtCodetextBuilder. - Add a numeric segment with
QrExtCompactionMode.NUMERIC. - Add an alphanumeric segment with
QrExtCompactionMode.ALPHA_NUMERIC. - Add a byte segment with
QrExtCompactionMode.BYTES. - Add a Kanji segment with
QrExtCompactionMode.KANJI. - Retrieve the combined extended codetext.
from aspose.barcode.barcoderecognition import BarCodeReader, DecodeType
from aspose.barcode.generation import (
BarcodeGenerator,
EncodeTypes,
QREncodeMode,
QrExtCodetextBuilder,
QrExtCompactionMode,
)
# Instantiate the Builder.
text_builder = QrExtCodetextBuilder()
# Numeric Segment — 3 Digits per 10 Bits.
text_builder.add_codetext_with_compaction_mode(
QrExtCompactionMode.NUMERIC, "1234567"
)
# Alphanumeric Segment — Uppercase and Digits Only, 2 Characters per 11 Bits.
text_builder.add_codetext_with_compaction_mode(
QrExtCompactionMode.ALPHA_NUMERIC, "ASPOSE2026"
)
# Byte Segment — Lowercase Forces Byte Mode, 8 Bits per Character.
text_builder.add_codetext_with_compaction_mode(
QrExtCompactionMode.BYTES, "aspose2026"
)
# Kanji Segment — Shift-JIS Double-Byte Characters, 13 Bits Each.
text_builder.add_codetext_with_compaction_mode(
QrExtCompactionMode.KANJI,
"\u3062\u3063\u3064\u3065\u3066\u3067\u3068\u3069\u306A",
)
# Assemble the Final Extended Codetext.
codetext = text_builder.get_extended_codetext()
print("Extended codetext:", repr(codetext))
Explanation
- Each
add_codetext_with_compaction_modecall sets the encoding mode for one segment. Order matters — the decoder returns segments concatenated in the sequence you added them. - The alphanumeric set is deliberately narrow: digits, uppercase A-Z, space, and
$%*+-./:. This is whyASPOSE2026fits alphanumeric mode butaspose2026does not. Lowercase letters are outside the set, so that segment must useBYTES. Passing lowercase toALPHA_NUMERICis the single most common mistake when setting modes this way. - The Kanji segment uses
\u3062onward, which are hiragana rather than kanji proper. Kanji mode covers the Shift-JIS double-byte range, which includes kana, so these encode at 13 bits each instead of the 24 bits byte mode would spend on each as UTF-8. get_extended_codetext()produces the string the generator parses in EXTENDED mode. Printing it withrepr()is worth doing once — it shows you the selector syntax the builder emits, which is exactly what the next subsection writes by hand.
3. Set the Encoding Mode Inline, Without the Builder
When the codetext originates outside your Python code, you can set each segment’s mode directly with a selector. Each backslash-prefixed marker governs every character until the next marker appears:
| Selector | Sets mode to |
|---|---|
\num | Numeric |
\alnum | Alphanumeric |
\byte | Byte, UTF-8 |
\kanji | Kanji, Shift-JIS |
\auto | Automatic mode selection |
# Equivalent to the Builder Output Above, Written Directly.
codetext = (
r"\num1234567"
r"\alnumASPOSE2026"
r"\byteaspose2026"
"\\kanji\u3062\u3063\u3064\u3065\u3066\u3067\u3068\u3069\u306A"
)
Note the escaping. In a normal Python string, "\num" is not a selector — it is a newline followed by um. Raw strings (r"...") avoid the problem, but a raw string also blocks \u escapes, which is why the Kanji line above uses a conventional string with \\kanji instead. This escaping trap is the practical argument for preferring the builder in section 2.
4. Generate the QR Barcode in EXTENDED Mode
Setting per-segment modes has no effect until the generator is told to read them. Without QREncodeMode.EXTENDED, the segment information is ignored and the selector markers are encoded as literal payload text.
- Create a
BarcodeGeneratorwithEncodeTypes.QRand the extended codetext. - Set
encode_modetoQREncodeMode.EXTENDED. - Configure resolution, and optionally error correction level and margin.
- Save the barcode to a lossless PNG.
# Create the QR Generator with the Extended Codetext.
gen = BarcodeGenerator(EncodeTypes.QR, codetext)
# Switch to EXTENDED Mode So the Per-Segment Modes Are Respected.
gen.parameters.barcode.qr.encode_mode = QREncodeMode.EXTENDED
# Render at Print Resolution Rather Than Upscaling Later.
gen.parameters.resolution = 300
# Save the Generated QR Code.
gen.save("extended_qr.png")
print("QR code generated and saved as extended_qr.png")
Explanation
gen.parameters.barcode.qr.encode_mode = QREncodeMode.EXTENDEDis the line that activates segment parsing. Leave it out and the generator produces a valid, scannable QR code containing the literal text\num1234567...— which is why the next subsection verifies rather than assumes.gen.parameters.resolution = 300renders at print resolution. Symbols headed for label printers or packaging artwork should be generated at final size, not scaled up afterwards, which softens module edges.savewrites a lossless PNG. Avoid JPEG for any 2D symbology — its compression artifacts blur the module grid the decoder samples.
5. Verify the Encoding Mode Was Applied
Successful generation proves nothing about whether the per-segment modes took effect. The decode step is what separates a correctly encoded symbol from one carrying selector markers as data.
- Initialise a
BarCodeReaderwith the file path andDecodeType.QR. - Materialise the results so a failed read is visible.
- Compare the decoded text against the expected concatenation.
EXPECTED = (
"1234567"
"ASPOSE2026"
"aspose2026"
"\u3062\u3063\u3064\u3065\u3066\u3067\u3068\u3069\u306A"
)
# Initialise the QR Code Reader.
reader = BarCodeReader("extended_qr.png", DecodeType.QR)
results = list(reader.read_bar_codes())
if not results:
raise ValueError("No QR code was detected in extended_qr.png.")
for result in results:
decoded = result.code_text
print("BarCode CodeText:", decoded)
if "\\num" in decoded or "\\alnum" in decoded:
print("Selectors were encoded literally — check that encode_mode is EXTENDED.")
elif decoded == EXPECTED:
print("Verified: all four segments decoded and concatenated as expected.")
else:
print("Mismatch. Expected:", EXPECTED)
Explanation
DecodeType.QRrestricts recognition to QR symbols, which is faster than scanning every supported symbology and prevents a malformed symbol from being decoded as something else.list(...)makes the failure case explicit. A recognition failure returns an empty iterable rather than raising, so an unguardedforloop over a failed read finishes silently and reads as success.- Checking for a literal
\numcatches the most common mistake in this workflow: setting the segments correctly and forgetting to setencode_mode. - The decoded payload is the raw segments concatenated, with all mode information consumed during encoding. Encoding modes are instructions to the encoder, not part of the data.
6. Measure Whether Setting the Mode Manually Helped
Setting the encoding mode manually is an optimisation, so measure it rather than assuming it. Generate the same payload both ways and compare:
RAW = "1234567ASPOSE2026aspose2026"
# Automatic Mode Selection.
auto = BarcodeGenerator(EncodeTypes.QR, RAW)
auto.save("qr_auto.png")
# Manually Set Modes per Segment.
builder = QrExtCodetextBuilder()
builder.add_codetext_with_compaction_mode(QrExtCompactionMode.NUMERIC, "1234567")
builder.add_codetext_with_compaction_mode(QrExtCompactionMode.ALPHA_NUMERIC, "ASPOSE2026")
builder.add_codetext_with_compaction_mode(QrExtCompactionMode.BYTES, "aspose2026")
manual = BarcodeGenerator(EncodeTypes.QR, builder.get_extended_codetext())
manual.parameters.barcode.qr.encode_mode = QREncodeMode.EXTENDED
manual.save("qr_manual.png")
print("Compare qr_auto.png and qr_manual.png — count modules along one edge.")
Count the modules along one edge of each image. A QR version n symbol is 17 + 4n modules square, so version 2 is 25×25 and version 3 is 29×29. If both land on the same version, automatic analysis already found the optimal segmentation and setting the mode manually was maintenance burden for no gain. Discovering that before shipping is a useful result, not a wasted step.
Get a Free License
Aspose offers a temporary free license that lifts evaluation restrictions and unlocks full functionality for testing. Request one from the Aspose temporary license page and apply it before any generation or recognition call.
Free Additional Resources
Conclusion
Setting QR code encoding modes in Python comes down to two questions: which segment gets which mode, and how you tell the generator to respect that choice. QrExtCodetextBuilder and QrExtCompactionMode answer the first question in application code; QREncodeMode.EXTENDED answers the second at the generator. This guide covered both the builder API and the inline selector syntax it produces, generating a four-segment QR symbol, verifying the decoded payload, and measuring the size difference against automatic mode.
Prefer the builder for application code — it catches mode errors at the call site instead of at the scanner. And keep the measurement step. Setting the mode manually is a real win on long homogeneous payloads and a net loss on short mixed ones where mode-switching overhead exceeds the savings. Generate both, compare the module counts, and let the result decide which code you maintain.
FAQs
What is a QR code encoding mode and why would I use one? An encoding mode tells the QR generator how to treat a segment of data — numeric, alphanumeric, byte, or Kanji. Each mode has a different data density, so choosing the right one per segment keeps the QR version, and therefore the symbol, as small as possible. Aspose.BarCode calls these compaction modes; the QR specification calls them encoding modes.
Which encoding modes does QrExtCompactionMode support?
QrExtCompactionModeprovidesNUMERIC,ALPHA_NUMERIC,BYTES, andKANJI, matching the four QR data modes defined in ISO/IEC 18004.Should I use QrExtCodetextBuilder or inline EXTENDED selectors to set the mode? Use the builder for application code. It is type-checked, avoids backslash escaping mistakes, and assembles the extended codetext for you. Inline selectors are useful when the codetext arrives from configuration, a database, or another system that cannot call the builder.
How does the EXTENDED encode mode differ from the standard QR encode mode? EXTENDED mode makes the generator read the codetext as a series of pre-defined segments, each with its own encoding mode, instead of running automatic mode detection across the whole string.
Can I set different encoding modes for different parts of one QR code? Yes. Add several segments to
QrExtCodetextBuilder, each with a differentQrExtCompactionMode, and the builder produces a single extended codetext covering all of them.Is a QR code generated with mixed encoding modes compatible with standard readers? Yes. Multi-segment encoding is part of the QR specification, so any compliant scanner decodes the payload correctly and returns the concatenated data.
Does setting the encoding mode manually always produce a smaller QR code? No. Every segment boundary costs a mode indicator and a character-count field, so splitting data into many short segments can make the symbol larger. Manual mode selection pays off on long, homogeneous runs of numeric or Kanji data.
Do I need a license to set QR encoding modes with QrExtCodetextBuilder? You can evaluate the API without a license, subject to evaluation restrictions. A free temporary license from the Aspose website lifts those restrictions during testing, and production use requires a full license.
What version of Aspose.BarCode for python-net supports these APIs?
QrExtCodetextBuilder,QrExtCompactionMode, andQREncodeMode.EXTENDEDare available in Aspose.BarCode for Python via .NET 26.6 and later.
