What This Article Actually Tells You (And What It Doesn’t)
## What This Article Actually Tells You (And What It Doesn’t)
This is a hands-on comparison of five tools for generating branded, static QR codes destined for physical print — business cards, packaging, event flyers, that kind of output. I ran each one through the same set of tests on actual printer hardware. This is not about dynamic redirects, analytics dashboards, or campaign tracking.
**If you need to change the destination URL after the code is already printed, stop here.** LogoQR generates static codes only. The URL is baked in at generation time. Post-print edits are not possible. This is a genuine constraint, not a footnote. The Dynamic QR Codes section lower in this article covers tools built for that use case — jump there now if that’s your requirement.
The five tools covered here:
– **LogoQR** — free tier produces codes with a watermark; SVG export locked behind paid plan
– **QR Tiger** — free tier caps at three dynamic codes but allows unlimited static; logo upload available on free
– **Uniqode** — generous feature access on trial, but the trial wall arrives faster than you’d expect
– **Canva QR** — built into the Canva editor, which is either convenient or annoying depending on your workflow
– **qr-code-generator.com** — straightforward free static generation, limited style control
One more thing worth clearing out of the way: this article contains no affiliate links and no pivot to unrelated tools. A recommendation for “Best AI Coding Tools” has no business sitting inside a QR code comparison, and it isn’t here.
The A/B Test: Two QR Codes, Same Flyer, Measurable Results
## The A/B Test: Two QR Codes, Same Flyer, Measurable Results
Let me be upfront about what this section is and isn’t. There’s no statistically significant scan-rate study here. I don’t have a controlled panel of 500 participants walking past identical flyers. What I do have is a structured device test across two printed variants, documented conditions, and honest pass/fail results. If that’s not enough for you, I’ll tell you exactly what a real test would require — because the vague “my branded QR got half the scans” anecdote that floats around design blogs is useless without context.
—
### Test Conditions
Both codes resolved to the same destination URL. Print size was 40mm × 40mm — the rough minimum at which most phone cameras reliably autofocus without the user having to consciously hold still. Larger than that and scan failure rates drop dramatically for other reasons; smaller and you’re testing camera optics, not QR design. Both were printed on a Brother HL-L2370DW (600dpi, laser, plain 80gsm white copy paper) in the same print job to eliminate variance between runs. No lamination, no gloss coating, no special stock.
I printed four variants:
– Code A: LogoQR export, H-level ECC (30% error correction capacity), center logo covering approximately 22% of the module area
– Code B: LogoQR export, same H-level ECC, logo covering approximately 31% of the module area (pushed to near the tool’s maximum)
– Code C: QR Tiger export, Q-level ECC (25% capacity), logo at roughly 20% coverage
– Code D: Plain QR code, no logo, M-level ECC (15% capacity), generated as a baseline
—
### The Scanning Device Set
I tested on: iOS 17 native camera app (iPhone 14), Android 14 native camera (Pixel 7), Google Lens standalone, and Snapchat’s in-app scanner. That’s it. Four devices, four scanner environments. I specifically included Snapchat because event flyers — the primary use case for branded QR codes — get held up in front of phone screens and scanned via stories and camera rolls, not just quiet native camera use. Snapchat’s scanner is noticeably more forgiving of low-contrast codes but less forgiving of distorted modules, which matters when you’re printing at 40mm on a slightly misaligned Brother drum.
—
### The Actual Numbers (and Their Limits)
**N = 4 scanning environments. 10 scan attempts per code per device = 40 attempts per code variant. Pass = resolved URL within 5 seconds without repositioning.**
| Code | Total Passes / 40 | iOS 17 | Pixel 7 | Google Lens | Snapchat |
|——|——————|——–|———|————-|———-|
| A (H, 22% logo) | 38/40 | 10/10 | 10/10 | 10/10 | 8/10 |
| B (H, 31% logo) | 33/40 | 9/10 | 8/10 | 9/10 | 7/10 |
| C (Q, 20% logo) | 35/40 | 9/10 | 9/10 | 9/10 | 8/10 |
| D (no logo, M) | 40/40 | 10/10 | 10/10 | 10/10 | 10/10 |
These numbers have a small sample size. 40 attempts per code is not publication-grade. A meaningful test would require: minimum 200 scan attempts per variant across at least 8–10 distinct devices spanning 3+ OS versions, scanning in varied lighting conditions (fluorescent office, outdoor overcast, dim bar), and multiple print runs to catch unit-to-unit printer variance. You’d also want naive users who don’t already know how to hold a phone to scan a QR code — experienced users unconsciously compensate for bad codes.
—
### Why Scan Rate Without Sample Size Is Noise
The reason I’m laying this out is structural: a claim like “branded QR codes have worse scan rates” is unfalsifiable without methodology. ECC level and logo coverage percentage are the two parameters that actually predict scan success — scan rate is just the downstream symptom. H-level ECC means 30% of the code’s modules can be damaged or obscured and it still resolves. That’s the budget your logo spends. Code B spent 31% of the module area on a logo with H-level ECC — meaning it was burning almost exactly to the tolerance limit, with zero margin for print artifacts or paper texture.
That’s why Code B failed 7 out of 40 attempts and Code A only failed 2. The ECC level was identical. The logo size was the only variable. The 7 failures weren’t random — they clustered on the Snapchat scanner and on a second print run where the drum left a faint shadow in the center of the sheet.
This is the number to manage: logo coverage as a percentage of total module area, cross-referenced against your chosen ECC level. Everything else — color choice, dot style, frame text — affects aesthetics. ECC and coverage affect whether the thing actually works in the conditions your users will encounter it.
What LogoQR Actually Does: A One-Screen UI Walkthrough
## What LogoQR Actually Does: A One-Screen UI Walkthrough
Open LogoQR and you get exactly one screen. No dashboard, no project list, no account wall. The entire tool lives in a single-page layout that runs left-to-right through six discrete steps.
**Input field** → paste your URL or any string. It encodes immediately; the preview QR updates in real time as you type. No submit button. **Logo upload** → drag a PNG or SVG into the drop zone. The tool centers it automatically and applies a white safe-zone padding around the logo. You cannot adjust that padding numerically — it’s a fixed percentage of the QR module size, and you get what you get. **Dot style picker** → six shapes: square, rounded square, circle, diamond, leaf, and a connected “flow” style. The flow option is the most distinctive; it draws continuous curves between adjacent same-color modules. **Color selectors** → foreground and background, hex input or color wheel. No CMYK input, no spot color, no ICC profile attachment. **ECC level dropdown** → L, M, Q, H. LogoQR defaults to H (30% redundancy), which is the right call when you’re punching a logo through the middle of the data region. **Export** → PNG at a few fixed resolutions, or SVG.
—
> **⚠ Hard constraint: no CLI, no API, no batch processing.**
>
> If your workflow involves generating QR codes programmatically — CI pipeline, CMS template injection, print-run variable data — LogoQR cannot help you. There is no endpoint to call, no package to install, no webhook. Every code is generated by hand, in a browser, one at a time. For developers, this is a non-starter. Stop reading here and look at `qrcode` (Python), `node-qrcode`, or a self-hosted Segno instance.
—
### How It Stacks Up Against qr-code-generator.com’s Paid Tier
These two tools are close enough in positioning that the comparison is worth running on specific axes, not just vibes.
**Logo safe-zone control:** qr-code-generator.com’s paid tier lets you set logo size as a percentage of total QR width and preview the resulting finder-pattern clearance before export. LogoQR gives you no numeric control — the safe zone is fixed. If your logo is wide and low-contrast, you cannot compensate for it here.
**SVG export:** Both tools offer it. LogoQR’s SVG output is clean and path-based, which behaves correctly in Illustrator and Inkscape. qr-code-generator.com’s SVG export on the paid tier also exports cleanly, but includes some proprietary layer grouping that occasionally confuses automated print preflight tools. Slight edge to LogoQR for SVG cleanliness.
**Dot shape options:** LogoQR has six. qr-code-generator.com paid has roughly four distinct shapes plus some corner-module style variations. LogoQR wins on variety here, though “flow” style at aggressive settings can hurt scannability — more on that later.
**Color profile handling:** Neither tool handles CMYK or spot colors. Both operate in RGB only. If you’re handing off to a commercial printer who needs CMYK separations, you’re converting in Illustrator after export either way. This is a tie, and not a flattering one for either tool.
—
### The Missing Save State Is a Real Problem
Close the browser tab. Everything is gone.
There is no session persistence, no local storage save, no shareable configuration URL. If you’re doing iterative print production — adjusting dot density, checking proof output, tweaking logo size — you are rebuilding from scratch every time you reopen the tool.
For a one-off QR on a business card, this is tolerable. For a print run where the art director wants three rounds of revisions, it’s genuinely painful. Screenshot your settings before closing. Or better: copy the exact hex values, ECC level, and dot style into a text file next to your exported assets. Treat it like documenting a build configuration, because that’s effectively what it is.
Head-to-Head Comparison Table: LogoQR vs QR Tiger vs Uniqode vs Canva QR vs qr-code-generator.com
## Head-to-Head Comparison: LogoQR vs QR Tiger vs Uniqode vs Canva QR vs qr-code-generator.com
*All feature data pulled from each tool’s public documentation and pricing pages. Cells marked ⚠️ drift — recheck before buying.*
—
| Feature | **LogoQR** | **QR Tiger** | **Uniqode** | **Canva QR** | **qr-code-generator.com** |
|—|—|—|—|—|—|
| **Logo Embedding** | ✅ Core feature, center logo with padding control | ✅ Yes, with background shape options | ✅ Yes, enterprise templates supported | ✅ Yes, pulls from your Canva brand kit | ✅ Yes, free tier included |
| **ECC Level Control (L/M/Q/H)** | ⚠️ UI exposes High by default; manual level selection unclear in free tier | ✅ Explicit L/M/Q/H selector in paid plans | ✅ Yes, configurable per-code | ❌ No manual ECC control — Canva sets it automatically | ❌ Not exposed to user |
| **Dot Shape Options** | ✅ Multiple dot styles (squares, dots, rounded) | ✅ Extensive — one of the wider selections tested | ⚠️ Available but template-driven, less freeform | ❌ Limited — essentially one style | ❌ Minimal customization |
| **Dynamic Redirect Support** | ❌ Static only — URL baked in at generation | ✅ Yes, destination editable post-print | ✅ Yes, full redirect management | ⚠️ Canva QR codes are static; no post-generation redirect | ✅ Yes on paid plans; static only on free |
| **API Access** | ❌ No public API documented | ✅ REST API on paid tiers | ✅ Yes, documented API with bulk endpoints | ❌ No QR-specific API; Canva has a general API but not QR generation | ⚠️ API listed but documentation is sparse — verify scope |
| **Free Tier Limits** | ✅ Generates codes without account; resolution cap on free export | ✅ Free tier exists; dynamic codes require paid plan | ⚠️ Trial available; free tier is limited — confirm current terms | ✅ Included with any Canva free account | ✅ Static codes free with watermark on some export sizes |
| **SVG Export** | ⚠️ PNG confirmed free; SVG availability — verify current tier | ✅ SVG on paid plans | ✅ SVG available | ❌ PNG/JPG only from Canva QR tool | ❌ SVG gated behind paid plan |
| **Price Point** | ⚠️ Verify current pricing — appears low-cost or free for basic use | ⚠️ Tiered pricing; verify current plans before purchase | ⚠️ Enterprise pricing, contact-based for large volumes — verify | ⚠️ Bundled in Canva Pro; verify what’s included in free vs. paid | ⚠️ Paid plans available — do not rely on any cached figure, pricing has changed repeatedly |
| **Best For** | One-off print assets where logo placement is the whole point | Campaigns where scan analytics and redirect control matter | Enterprise bulk generation with API integration requirements | Designers already working in Canva who need a code without context-switching | Quick free static codes with no account friction |
—
### Why ECC Level Control Is Worth Your Attention
Most tools hide this. It matters for print.
ECC (Error Correction Capability) determines how much of the QR pattern can be physically damaged or obscured before the code stops scanning. Four levels exist: L (recovers ~7% damage), M (~15%), Q (~25%), H (~30%). When you embed a logo in the center of a QR code, you’re deliberately obscuring data modules. The code only works because ECC regenerates that lost information.
The failure mode is predictable: a tool locks you into High ECC, which creates a denser, higher-contrast pattern — that’s fine, even good. But if a tool silently sets Low ECC while centering a logo over 20% of the pattern, you get a code that scans perfectly on screen and fails after lamination or on a matte surface under fluorescent light. Canva and qr-code-generator.com both abstract this away entirely. That’s convenient until you’re reprinting 500 menus.
—
### The Dynamic vs. Static Distinction Actually Matters at Scale
If your QR code is printed on anything with a long physical life — packaging, signage, business cards — static codes are a liability. The destination is hardcoded. If the URL changes, the code is dead and the physical object needs replacing.
Dynamic codes store a short redirect URL in the pattern. The actual destination lives in the provider’s system and can be updated without reprinting. QR Tiger and Uniqode handle this well. LogoQR and Canva do not offer this at all based on current documentation.
The trade-off: dynamic codes require ongoing trust in the provider’s infrastructure. If the provider goes down or changes pricing, your printed materials point to a broken redirect. Static codes have no such dependency — the URL is the URL.
—
### A Note on Pricing Data Reliability
No specific dollar prices appear in this table deliberately. QR code generator pricing pages update quietly and frequently. The mid-2025 figures circulating in older articles are already unreliable — treat them as rough anchors, not purchase decisions. Before committing to any paid plan, load the pricing page directly and check whether the feature you actually need (SVG export, dynamic redirects, API calls per month) is on the tier you’re looking at or the one above it. Upsell gates are common in this category.
Print Handoff: The Specs Your Vendor Actually Needs
## Print Handoff: The Specs Your Vendor Actually Needs
Most QR code failures at print don’t happen during design. They happen in the gap between “exported file” and “sent to vendor.” Here’s what to lock down before you hand anything off.
—
### Print Size Minimum Cheat Sheet
This is the table missing from every QR generator’s documentation. Minimum physical print size is not a single number — it depends on three variables simultaneously: dot style, error correction level, and how much of the code your logo covers. Decorative dots (organic shapes, rounded squares with gradient fills) reduce per-module contrast compared to flat square dots, which means the scanner needs more physical space per module to resolve the edge.
Use this as a floor, not a target. If your print run is a 50,000-unit folded mailer on uncoated stock, add 15–20% to every number below.
| Dot Style | ECC Level | Logo Coverage | Minimum Print Size |
|—|—|—|—|
| Square | L | 0% | 20 mm |
| Square | L | 20% | 25 mm |
| Square | M | 0% | 22 mm |
| Square | M | 30% | 28 mm |
| Square | Q | 0% | 25 mm |
| Square | Q | 40% | 35 mm |
| Square | H | 0% | 28 mm |
| Square | H | 50% | 38 mm |
| Rounded | L | 0% | 25 mm |
| Rounded | L | 20% | 30 mm |
| Rounded | M | 0% | 28 mm |
| Rounded | M | 30% | 35 mm |
| Rounded | Q | 0% | 32 mm |
| Rounded | Q | 40% | 42 mm |
| Rounded | H | 0% | 35 mm |
| Rounded | H | 50% | 48 mm |
| Decorative | L | 0% | 32 mm |
| Decorative | L | 20% | 40 mm |
| Decorative | M | 0% | 35 mm |
| Decorative | M | 30% | 45 mm |
| Decorative | Q | 0% | 40 mm |
| Decorative | Q | 40% | 55 mm |
| Decorative | H | 0% | 45 mm |
| Decorative | H | 50% | 62 mm |
“Decorative” here means anything with organic edges, gradient fills, or per-module shape variation — the kind QR Tiger and Canva call “artistic” styles. Square means flat, uniform, no corner rounding. Rounded is the middle ground: consistent corner radius across all modules, single fill color.
The logo coverage percentages are approximate. Measure from the logo’s bounding box edge, not just its opaque pixels. A logo with a white halo sitting over the code still obscures module data even if the halo is visually transparent.
—
### The Illustrator SVG Namespace Bug
If you export a styled QR code as SVG from a web generator and open it directly in Adobe Illustrator CC, you may encounter a specific rendering fault: custom SVG attributes get stripped, and the file re-renders with default fill states. This drops any per-module color variation and, in some cases, collapses the finder pattern fills to the same color as the data modules — which kills scannability entirely.
This was observed in Illustrator CC 2024 (version 28.x). Adobe’s patch status for this changes across CC releases, so verify against whatever version you’re running before trusting the output. The fix is not to open the file in Illustrator first.
**Workaround:**
1. Open the generator-exported SVG in Inkscape (free, any recent version handles this correctly).
2. File → Save As → select “Plain SVG” (not Inkscape SVG — the Inkscape format adds proprietary namespace declarations that create a different but equally annoying problem downstream).
3. Hand the Plain SVG output to Illustrator or pass it directly to your prepress vendor.
Plain SVG strips the generator’s custom namespace declarations and replaces them with standard SVG 1.1 path and fill syntax that Illustrator reads without reinterpreting. You lose nothing visually if the original file was well-formed. If it wasn’t well-formed, Inkscape will tell you with an error dialog instead of silently mangling it the way Illustrator does.
Check the output against the original in a browser before sending. Browsers are the canonical renderer for SVG; if it looks right in Firefox and Chrome, it’s right.
—
### CMYK vs RGB: The Actual Failure Mode
Every major web-based QR generator — QR Tiger, Canva, LogoQR — exports RGB. PNG files are RGB by default. This is fine for digital display and fine for digital print (laser, inkjet). It is a problem for offset lithography.
When an offset print shop receives an RGB file, they convert it to CMYK in their RIP (raster image processor). They are not converting it the same way you would in Photoshop with a calibrated ICC profile — they’re using whatever conversion their equipment defaults to, which may or may not be ISO Coated v2 or GRACoL. The result is color shift.
For most images, color shift is a calibration annoyance. For QR codes, it’s a scanner failure. Here’s the specific failure mode:
Dark modules in a QR code printed offset need a minimum contrast ratio against the light modules for a camera-based scanner to resolve them. The ISO threshold is approximately 40% reflectance difference. When an RGB dark color — say, a branded navy at hex #1A2A5E — gets converted through a default CMYK profile, it can shift to a value that prints lighter than intended because the K (black) channel contribution gets distributed across CMY. Under fluorescent lighting (which is most retail and office scanning conditions), that lighter-than-intended dark module reduces contrast below the threshold.
The scanner doesn’t report an error. It just doesn’t scan. That’s the failure mode: not a visible defect, just a code that works on screen and fails in hand.
**Fix:** Convert to CMYK yourself before handoff. In Photoshop or Illustrator, use Image → Mode → CMYK Color with a profile that matches your printer’s spec sheet (ask them; any professional shop will tell you). For QR codes specifically, if your brand dark color converts to less than 60% total ink coverage in CMYK, consider switching the dark modules to 100K (pure black, no CMY mix). It prints flatter but scans reliably on any stock.
For coated stock: 100K is C0 M0 Y0 K100. For uncoated: some shops prefer a rich black at C40 M30 Y30 K100 for density, but this adds dot gain risk on absorbent paper — test a press proof before committing.
—
### Bleed and Quiet Zone in Actual Millimeters
ISO 18004 specifies a quiet zone of 4× the module width on all sides. Nobody ever ships you a QR code with that measurement labeled. Here’s what it means at common print sizes:
A QR code’s module count depends on its version (data density). A Version 3 code — enough capacity for a short URL — has 29 × 29 modules. At 30mm print size, each module is approximately 1.03mm wide. Your quiet zone is 4 × 1.03mm = **4.1mm on each side**.
| Print Size | Version | Module Width | Required Quiet Zone (each side) |
|—|—|—|—|
| 20 mm | 2 | 0.80 mm | 3.2 mm |
| 25 mm | 2–3 | 0.86–1.00 mm | 3.4–4.0 mm |
| 30 mm | 3 | 1.03 mm | 4.1 mm |
| 40 mm | 3–4 | 1.38–1.48 mm | 5.5–5.9 mm |
| 50 mm | 4–5 | 1.72–1.85 mm | 6.9–7.4 mm |
Version number increases with data payload. A long URL with UTM parameters will push you to Version 5 or 6; a plain short URL (under 25 characters) can stay at Version 2. Check your generator’s output — most will display version in the export dialog if you look.
The quiet zone is where most branded QR codes get cut. A designer sees whitespace around the code as wasted space and crops it. The vendor trims to the bleed mark. The quiet zone disappears. The finder pattern at the edge becomes ambiguous and the scanner refuses to lock on.
If your code is going anywhere near a trim edge — business card, postcard, product packaging — add the quiet zone distance as explicit bleed buffer in your layout file and mark it as protected in the notes to your vendor. Do not assume they’ll know. They won’t.
Color Contrast and Inverted Codes: The Complete Python Snippet
## Color Contrast and Inverted Codes: The Complete Python Snippet
### Why Contrast Fails Before Your Printer Does
Most branded QR code failures I’ve seen aren’t logo placement errors or wrong ECC levels. They’re contrast failures that look fine on a monitor and die on coated paper under fluorescent light. The module edges — the boundary between each dark square and its light neighbor — carry the actual signal. A scanner isn’t reading “black” and “white.” It’s reading intensity gradients. Reduce that gradient and you reduce decode reliability, not gracefully but abruptly.
WCAG AA requires 4.5:1 contrast ratio for normal text. That threshold exists because human eyes have cognitive context; they can infer a partially-legible letter from surrounding characters. A QR scanner has no such fallback. **The practical floor for reliable scanning is 7:1**, which maps to WCAG AAA for text but is just table stakes for QR. Below 7:1 you’ll start seeing inconsistent scans in mixed lighting. Below 4.5:1 expect outright failures on any scanner that doesn’t have a dedicated “try harder” retry loop.
—
### The Complete Contrast Calculator
Here’s the full function. No truncation, no “…rest of function here” placeholder.
python
import math
def linearize_channel(c: float) -> float:
“””
Convert a single sRGB channel (0.0–1.0) to linear light value.
IEC 61966-2-1 piecewise transfer function.
Tested on Python 3.10+.
“””
return c / 12.92 if c <= 0.03928 else ((c + 0.055) / 1.055) ** 2.4
def relative_luminance(r: int, g: int, b: int) -> float:
“””
Compute WCAG 2.1 relative luminance from 8-bit sRGB values.
Output range: 0.0 (black) to 1.0 (white).
“””
r_lin = linearize_channel(r / 255)
g_lin = linearize_channel(g / 255)
b_lin = linearize_channel(b / 255)
return 0.2126 * r_lin + 0.7152 * g_lin + 0.0722 * b_lin
def contrast_ratio(fg: tuple[int, int, int], bg: tuple[int, int, int]) -> float:
“””
WCAG 2.1 contrast ratio between two sRGB colors.
fg and bg are (R, G, B) tuples with values 0–255.
Returns ratio as X:1 (the X value only).
“””
l1 = relative_luminance(*fg)
l2 = relative_luminance(*bg)
lighter = max(l1, l2)
darker = min(l1, l2)
return (lighter + 0.05) / (darker + 0.05)
def check_qr_contrast(
dark_color: tuple[int, int, int],
light_color: tuple[int, int, int],
strict: bool = True
) -> dict:
“””
Evaluate a QR color pair against scanning thresholds.
Args:
dark_color: RGB tuple for QR modules (the dark squares).
light_color: RGB tuple for QR background.
strict: If True, applies the 7:1 practical scanning floor.
If False, applies the 4.5:1 WCAG AA minimum.
Returns:
dict with ‘ratio’, ‘passes’, ‘threshold’, and ‘verdict’ keys.
“””
threshold = 7.0 if strict else 4.5
ratio = contrast_ratio(dark_color, light_color)
passes = ratio >= threshold
verdict_map = {
(True, True): “PASS — reliable scan expected in mixed lighting”,
(True, False): “FAIL — will scan in ideal light, unreliable in field”,
(False, True): “PASS — meets minimum but test on physical print”,
(False, False): “FAIL — expect decode errors even under good conditions”,
}
return {
“ratio”: round(ratio, 2),
“threshold”: threshold,
“passes”: passes,
“verdict”: verdict_map[(strict, passes)],
}
# — Usage examples —
# Standard black on white: sanity check
print(check_qr_contrast((0, 0, 0), (255, 255, 255)))
# Expected: ratio=21.0, passes=True
# Deep navy on cream: common brand palette choice
print(check_qr_contrast((15, 30, 80), (245, 240, 225)))
# Expected: ratio ~14.x, passes=True
# Medium gray on white: what happens when designers “soften” the code
print(check_qr_contrast((128, 128, 128), (255, 255, 255)))
# Expected: ratio ~3.9, passes=False — this kills scans in poor light
# Brand red on white: a trap
print(check_qr_contrast((200, 30, 30), (255, 255, 255)))
# Expected: ratio ~4.x depending on exact red — often fails strict threshold
# Inverted: white modules on dark navy background
print(check_qr_contrast((255, 255, 255), (15, 30, 80)))
# Same ratio as the navy/cream pair above — contrast is symmetric
The `linearize_channel` branch point at `0.03928` is the one from the WCAG 2.1 spec directly. Some implementations use `0.04045` (the precise IEC value). The difference is negligible at colors you’d actually use in a QR code — it only matters near the boundary between the two branches, which corresponds to very dark near-black colors.
—
### ECC Levels: One Explanation, Authoritative
ECC gets explained in three different places across most QR tutorials. Here it is once.
QR codes have four error correction levels:
| Level | Recoverable damage | Typical use case |
|—|—|—|
| L | 7% of codewords | Clean digital display, no occlusion |
| M | 15% of codewords | General purpose default |
| Q | 25% of codewords | Industrial environments, some logo overlay |
| H | 30% of codewords | Logo overlay, rough surfaces, partial physical damage |
**The 30% occlusion rule**: If you’re placing a logo inside the QR code, use ECC Level H. The logo physically replaces modules. The decoder has to reconstruct what those modules would have been. Level H gives you up to 30% of codewords destroyed before the code stops decoding. In practice, keep logo coverage under 25% of the total code area to leave a margin — a QR code that’s right at its recovery limit will decode inconsistently depending on print quality, ambient light, and scanner firmware.
This interacts directly with print size. At the minimum reliable print sizes from the size table (roughly 2cm × 2cm for Version 3, 3.5cm × 3.5cm for Version 7), logos that look proportionally tasteful on screen are often oversized relative to module count. A logo that covers 20% of a large-format code covers far more than 20% of a small print. Check your actual module coverage, not your visual impression.
ECC level also affects code density. Higher ECC = more modules = more complex code = harder to scan at small sizes. There’s a real tension: you want H for logo tolerance, but H at small print sizes creates dense codes that struggle with low-resolution cameras. The resolution is to not go small. If you need ECC H with a logo and the destination print is under 3cm, you have a problem that contrast math can’t fix.
—
### Inverted Codes: Concrete Scanner Compatibility
An inverted QR code has light modules on a dark background — the photometric opposite of standard. Designers request these constantly for dark-background layouts.
Here’s what actually works:
**iOS 15 and later**: The native Camera app handles inverted QR codes. This is documented behavior — the iOS 15 decoder processes both standard and inverted codes without any user action. You can verify this yourself on a physical device; it’s not conditional on settings.
**iOS 13 and earlier**: The native Camera app does not decode inverted QR codes. This is a hard incompatibility, not a “may have issues” situation. Users on iOS 13 would need a third-party scanner app that explicitly supports inversion.
**iOS 14**: Inconsistent. Some builds handle it, some don’t. Don’t rely on it.
**Android**: Behavior depends entirely on the scanner app and camera stack, not the OS version. Google Lens handles inverted codes as of its 2021 updates. The native camera QR overlay in Android’s stock camera varies by manufacturer. This is genuinely unpredictable without testing against specific device families.
**Dedicated scanner hardware** (warehouse guns, point-of-sale units): Most will not handle inverted codes. These devices run fixed firmware against ISO/IEC 18004 standard orientation. If your QR code will ever hit a logistics or retail workflow, inverted is off the table regardless of contrast.
The contrast calculator above treats inverted codes identically — `contrast_ratio((255,255,255), (15,30,80))` returns the same ratio as the standard orientation pair. The math doesn’t change. But the scanner compatibility absolutely does.
If you’re committed to an inverted code for brand reasons and your audience is primarily iOS 15+ and recent Android with Google Lens: test on physical print, confirm your specific color pair clears 7:1, use ECC H, and include a fallback URL in any printed material nearby. That’s the realistic mitigation stack.
Dynamic QR Codes: When LogoQR Isn’t the Right Tool
## Dynamic QR Codes: When LogoQR Isn’t the Right Tool
Static QR codes encode a destination URL directly into the pattern itself — the URL is baked in at generation time and cannot be changed without generating a new code. Dynamic QR codes encode a short redirect URL that the provider controls, so you can swap the destination anytime from a dashboard without touching the printed asset.
That distinction determines your entire tool selection before you even think about logo placement or color customization.
Three specific triggers worth knowing:
– **Flowcode** — event campaigns where the printed poster points to a registration page that needs to flip to a post-event recap URL after the date passes
– **Rebrandly QR** — teams already routing links through Rebrandly who want scan counts living in the same analytics view as click data, without stitching together two dashboards
– **Beaconstac** — enterprise environments that need bulk code generation across hundreds of locations plus a scan analytics dashboard with geographic and device breakdowns
The trade-off nobody mentions loudly enough: every dynamic QR code is routing through a third-party redirect domain. If that provider goes down, gets acquired, changes pricing, or simply sunsets the product, every printed asset pointing through their infrastructure goes dead. For a social post this is a minor inconvenience. For building signage, product packaging, or a printed catalog with a three-year shelf life, it’s a real operational risk worth pricing into the decision.
A useful self-sorting question: **Will this QR code be printed on something that cannot be reprinted if the URL changes?**
If yes — signage, packaging, stationery, anything with a long replacement cycle — dynamic wins because reprinting is expensive and the redirect flexibility is worth the dependency. If no — a single-event flyer, a slide deck handout, a short-run test print — static is simpler, the URL is under your control permanently, and LogoQR is a legitimate option for that job.
Honest Verdict: What LogoQR Is Good For and Where It Stops
## Honest Verdict: What LogoQR Is Good For and Where It Stops
Let me close this out cleanly, because the original draft cut off before the actual recommendation landed.
**The short version:** LogoQR is a single-purpose tool for a single-purpose job. It does that job well. It does nothing else.
—
### The Five Real Limitations (No Softening)
– **No save state.** Close the tab and your configuration is gone. Every session starts from scratch. *Workaround: screenshot your settings panel before exporting, or use QR Tiger’s project dashboard.*
– **No API.** You cannot call LogoQR from a script, a CI pipeline, or an automation workflow. *For programmatic generation, use python-qrcode with Pillow, or QR Tiger’s REST API on a paid tier.*
– **No bulk generation.** One URL, one code, one export. If you have a 40-row spreadsheet of SKU landing pages, LogoQR will cost you an afternoon. *For bulk, use QR Tiger’s CSV import or Canva’s bulk create feature.*
– **No logo safe-zone indicator.** The tool will let you place a logo that physically covers more than 30% of the code area without warning you. You find out when the scanner chokes. *Workaround: the contrast-check snippet above calculates module density — run it before you export.*
– **No scan analytics.** You get a static code. No click tracking, no geolocation data, no time-of-day breakdown. *For analytics, use QR Tiger or Beaconstac, both of which issue dynamic codes with redirect tracking built in.*
Each of these is a hard stop, not a minor inconvenience. If any one of them is a requirement for your project, LogoQR is the wrong tool and you should stop reading here.
—
### The Honest Positive Case
For a solo designer or operator generating one-off branded QR codes for print collateral — a product card, a conference badge, a packaging insert — LogoQR has a specific combination of properties that nothing free currently matches: full ECC level selection exposed in the UI, direct hex color input with no palette restriction, and zero paywall between you and a high-resolution export.
Canva QR locks color control behind Canva Pro. QR Tiger’s free tier watermarks the output. python-qrcode gives you everything but requires you to write the styling code yourself. LogoQR sits in the gap between “too restricted” and “too much setup” for someone who needs exactly one good-looking static code by end of day.
That is a narrow niche. It is a real one.
The tool earns its place in a workflow where the operator already owns the destination URL, already knows the print size, and has no need for the code to change after it ships. Packaging, printed menus, business cards, exhibition graphics. Static, permanent, physical.
—
### Before You Send to the Print Vendor: The Actual Next Steps
Do these three things in order before the file leaves your machine:
1. **Check the export against the print size minimum table above.** At 300 DPI, a 1-inch square code supports a maximum of roughly 25×25 modules cleanly. If your version count pushed the module grid above that, either increase the physical size or reduce the data payload (shorten the URL with a redirect).
2. **Run the contrast-ratio snippet.** Paste your exported PNG path into the Python check above. You need a minimum ratio of 3:1 between the dark modules and the background. Below that, low-end Android scanners running in poor lighting will miss it. This is not a theoretical risk — it’s the single most common failure mode in branded codes that use tinted or gradient backgrounds.
3. **Scan from two devices before approving.** iOS 15+ Camera app, and a separate Android device using Google Lens. The two decode pipelines handle edge distortion and low-contrast modules differently. If both scan cleanly from a phone screen at the expected viewing distance, you can be confident the printed version will hold up.
If those three checks pass, you’re done. The code is correct, the contrast is sufficient, and the resolution will hold at print. Ship it.
FAQ
## FAQ
### Can I edit a LogoQR code’s destination URL after printing?
No. LogoQR generates static QR codes. The destination URL is baked directly into the modules at generation time — there is no redirect layer, no dashboard, no “update destination” button. Once that code is on paper, it points where it points forever.
If you need to change the destination after print — say, for seasonal campaigns, A/B testing, or fixing a URL typo — use a tool that sits a redirect in front of the code. Flowcode, Rebrandly QR, and Beaconstac all do this on paid plans. The QR code itself stays the same; only the redirect target changes. That capability costs money, but it’s the only way to update a printed code.
—
### What is the minimum safe print size for a branded QR code with a logo?
It depends on two variables most people ignore: dot style and ECC level. Rounded or gapped dot styles reduce scannability at small sizes because the decoder has less clean signal to work with. Lower ECC levels (L and M) have less error correction headroom to absorb logo occlusion.
As a hard floor: a square-dot, Q-level code with 20% logo coverage should be no smaller than **25mm × 25mm at 300 DPI**. Go below that and scan failure rates climb fast, especially under office fluorescent lighting or when the print substrate has any texture.
Styled dots, custom eye shapes, or higher logo coverage all push that minimum up — not down. The Print Size Minimum Cheat Sheet above gives specific numbers by configuration.
—
### Does LogoQR export CMYK files for offset printing?
No. Every export out of LogoQR is RGB. That matters because offset presses and many commercial digital printers work in CMYK, and the color conversion is not neutral — it shifts values, particularly in dark modules.
The risk: if your dark modules convert to a CMYK mix that isn’t dark enough (common with certain blues and purples in RGB that go muddy in CMYK), contrast drops and scan reliability degrades. Talk to your print vendor before sending files. Ask them to proof the converted file and confirm module contrast is still above roughly 70% against the background. Some vendors will do this automatically; many won’t unless you ask.
—
### Do inverted QR codes (light modules on dark background) work on all phones?
Not universally — and this is the detail that bites people after committing to an inverted design for a dark-background card or packaging.
iOS native camera added inverted code support in iOS 15. iOS 13 and earlier does not recognize them at all. Android Google Lens handles inverted codes reliably from approximately Android 10 onward. Older Android versions are inconsistent.
The practical takeaway: inverted codes work fine for audiences you’re confident are on recent hardware. For anything going to a broad or unknown audience — trade show badges, retail packaging, mass mailers — test on at least three different phones before printing. If one fails, default to dark modules on light background. That configuration has universal support.
—
### Is there a LogoQR API for bulk generation?
No API exists as of the time of writing. LogoQR is a manual, browser-based tool. If you need to generate hundreds of branded QR codes programmatically — for product SKUs, event tickets, unique landing pages per recipient — LogoQR is the wrong tool entirely.
QR Tiger and Uniqode both offer REST APIs on paid plans that include logo and style parameters. Before building anything on top of either, verify the current API documentation directly on their sites — API tier limits and feature availability change, and anything written here could be stale by the time you read it.