Why Your QR Codes Are Too Big (And How to Make Them Smaller)

Why Your QR Codes Are Bigger Than They Need To Be (And How To Shrink Them)

I was helping a buddy print some QR codes for an event last week. He had them slapped on little table tents, and half the time my phone just sat there squinting at it like it forgot how to read.

So we dug in. And it turns out the QR code was WAY denser than it needed to be. All those tiny squares packed in tight? Most of them didn’t need to be there.

The fix was almost silly. We changed a few lowercase letters to uppercase, and the code got noticeably simpler.

Have you ever run into a QR code that just refuses to scan? There’s a decent chance it’s doing this exact thing to itself.

Now on with the show. 😃

The thing nobody tells you about QR codes


A QR code doesn’t store your text the same way every time. It picks an encoding mode based on what characters you throw at it. And each mode packs characters at a totally different density.

Here are the three you actually care about:

  • Numeric (just 0-9): about 3.33 bits per character
  • Alphanumeric (0-9, UPPERCASE A-Z, space, and a handful of symbols like $ % * + - . / :): about 5.5 bits per character
  • Byte (anything else, including lowercase letters, most symbols, emojis): 8 bits per character

See the jump? The second you include a single lowercase letter, the QR code shrugs and switches the WHOLE thing to byte mode at 8 bits a pop.

Stick to uppercase and numbers, and it stays in alphanumeric mode at 5.5 bits. That’s roughly 30% less data for the exact same message.

Less data means fewer squares. Fewer squares means a bigger, cleaner, easier-to-scan code at the same print size.

Wait, why such weird numbers?


The cool thing is QR codes cheat a little to save space.

In alphanumeric mode there are 45 possible characters. Instead of storing them one at a time, it grabs two characters and packs them into 11 bits. Two characters, 11 bits, so 5.5 bits each.

Numeric mode cheats even harder: three digits crammed into 10 bits. That’s the 3.33.

You don’t have to do any of this math yourself. The encoder handles it. You just have to NOT sabotage it by tossing in a lowercase a.

The free win for URLs


Here’s where this actually pays off in real life.

Domain names don’t care about case. EXAMPLE.COM and example.com go to the same place. So if you’re encoding a link, you can uppercase the whole thing and the QR code gets simpler for FREE.

So instead of:

example.com/promo

Encode:

EXAMPLE.COM/PROMO

Same destination. Smaller code. Nothing lost.

And if you’re making your own short codes or IDs (invoice numbers, coupon codes, tracking IDs), design them as uppercase and digits from the start. Something like INV-2026-AX9 stays in the efficient lane. ⚡

Practical QR code tips I wish I’d known sooner


Once you fix the encoding thing, here are the other gotchas that bite people:

Keep the payload short. Less text equals a simpler code. Use a short link instead of a giant URL stuffed with tracking junk like ?utm_source=.... All that gunk bloats the code for no real benefit.

Leave the quiet zone alone. That blank margin around the code (about 4 squares wide) is not decoration. It’s how scanners find the edges. Crowding it with text or a border is the number one reason codes fail to scan.

Mind the error correction level. QR codes can survive damage because they store backup data. The levels are L, M, Q, and H (roughly 7% up to 30% recovery). Higher means tougher, but also denser.

  • For a clean screen or a nice flyer, M is the sweet spot.
  • Putting your logo in the middle? Use H. That’s literally why you can cover the center and still scan, the backup data fills in the gap.

Dark code, light background. Scanners expect this. Flip it to light-on-dark and a lot of phones just give up.

Don’t blow up a tiny image. Generate it at the final size, or use a vector (SVG) so it stays crisp. A blurry, upscaled QR code is a sad QR code.

Use a redirect link if the destination might ever change. Point the QR code at a short URL YOU control, then point that short URL wherever you want. Static codes bake the destination in forever. Wrong link on 5,000 printed flyers is an expensive lesson. Don’t ask me how I know. 😅

Test it for real. Different phones, iPhone and Android, in real lighting, at the actual size you’re printing. Thirty seconds of testing beats a reprint every single time.

Tell people why to scan. A naked QR code gets ignored. “Scan for the menu” or “Scan for 20% off” gets scanned. Give folks a reason.

One quick heads-up on safety


QR codes hide where they’re sending you, which makes them a favorite trick for scammers (people call it “quishing” now).

Don’t get me wrong, QR codes are great. But when you publish one, show the real web address right next to it so people can trust where they’re headed. And be a little careful scanning random codes on parking meters and flyers yourself.

The takeaway


QR codes feel like magic, but they’re really just following a few simple rules. Learn the rules and you can make them smaller, cleaner, and far more reliable, with almost no extra effort.

Uppercase plus numbers equals alphanumeric mode equals less data equals a code that actually scans on the first try.

It’s a tiny tweak. But tiny tweaks that save time and prevent headaches? That’s pretty much my whole thing. 🤖

How about you? Next time you make a QR code, try uppercasing the link and see how much simpler it gets. Then go scan it from across the room just to feel good about yourself.

P.S. This is the fun part about automation and tech in general. The little details you almost never think about are usually the ones quietly costing you time. Poke at them. Test stuff. You’ll be surprised how often a 10 second change saves you a 10 minute problem.

Run AutoHotkey Scripts by Double-Clicking, No Admin Rights Needed

Run AutoHotkey Scripts by Double-Clicking, No Admin Rights Needed

A friend pinged me last week from his locked-down work laptop. IT won’t let him install anything. No installers, no admin password, nothing. But he can copy files. So he dropped AutoHotkey64.exe onto his machine, wrote a little script to save himself a few minutes a day, and then hit the wall we all hit: double-clicking the .ahk file did absolutely nothing. Or worse, it opened in Notepad. 😀

Have you ever been there? You’ve got the tool, you’ve got the script, and Windows just shrugs at you.

Here’s the cool thing: you don’t need an installer, and you don’t need admin rights. You just need to understand what a “file association” actually is. Spoiler: it’s not magic, and it’s not a program you install. It’s a few lines of text in the registry.

Now on with the show. 🚀

First, kill the myth: nothing gets “installed”

When you double-click a .ahk file, Windows asks a simple question: “Which program opens this kind of file?” The answer lives in the registry as plain text. That’s it. An installer is just a fancy wrapper that writes those text values for you (and usually demands admin rights to do it system-wide).

But the registry has a per-user section that you own. No admin needed. Anything you put under HKEY_CURRENT_USER\Software\Classes applies to you, right away. Windows blends your personal settings on top of the machine-wide ones automatically.

So the whole trick is: write the same text an installer would write, just into your corner of the registry instead of the machine’s.

What the association actually looks like

Two pieces. First, a recipe that says “this is how you open an AutoHotkey script”:

HKEY_CURRENT_USER\Software\Classes\AutoHotkeyScript\shell\open\command
   (Default) = "C:\Portable\AutoHotkey64.exe" "%1" %*
HKEY_CURRENT_USER\Software\Classes\AutoHotkeyScript\DefaultIcon
   (Default) = "C:\Portable\AutoHotkey64.exe",0

Then you tell Windows that .ahk files use that recipe:

HKEY_CURRENT_USER\Software\Classes\.ahk
   (Default) = AutoHotkeyScript

A couple of things worth knowing:

  • “%1” is the file you double-clicked. The quotes matter so paths with spaces don’t blow up.
  • %* passes along any extra command-line arguments to your script.
  • ,0 is just “use the first icon inside the exe” so your scripts get a proper icon.

Write those, and double-clicking a .ahk launches it. Per-user. No admin. Done.

“But we all use the v2 dash launcher now”

Good catch, and yes, this still works. The modern AutoHotkey v2 install doesn’t point .ahk straight at an interpreter. It points at a little launcher that figures out whether your script is v1 or v2 (and 32 vs 64-bit) and then hands it to the right engine. On my machine the real command looks like this:

"...\UX\AutoHotkeyUX.exe" "...\UX\launcher.ahk" "%1" %*

Same idea, different target. Instead of naming an interpreter in your open command, you name the launcher. You’ve got two honest options:

  • Point straight at AutoHotkey64.exe. One file, dead simple, v2 only. If everyone on your team is on v2 (and these days, who isn’t?), a v1 script just errors out. Honestly, kind of a feature.
  • Use the launcher. Full v1/v2 auto-detection and the Dash. The catch: the launcher needs its friends. You have to copy the whole AutoHotkey folder, not a lonely single exe.

Either way, it’s still just text under HKCU\Software\Classes. No admin.

❗ The one gotcha: UserChoice

Windows 8 added a tamper-proof override called UserChoice. If a .ahk association was ever set before (say someone once picked Notepad), Windows obeys that and ignores your new keys.

And no, you can’t fake it. UserChoice carries a secret hash that Microsoft built specifically so malware can’t hijack your file types. If the hash doesn’t match, Windows throws the whole thing out.

The fix is a one-time manual step: open Settings > Apps > Default Apps, find .ahk, and clear or change it. After that, your per-user recipe takes over. If .ahk has never been associated before, you won’t hit this at all.

The part that might save you the whole effort

Here’s something a lot of people miss: AutoHotkey v2’s own setup already supports a per-user, no-admin install. If you copied the full folder, just run its installer (or open the Dash and choose Install) without elevating, and it writes all these keys into HKCU for you, pointing at the launcher exactly like above.

So if you’ve got the whole folder, you may not need to touch the registry yourself at all. Try that first.

I built a little script to do it for you

For the single-exe, locked-down case (or when you just want it done in one click), I wrote a small AutoHotkey v2 script that:

  • Finds your AutoHotkey automatically and uses the launcher if it’s there, otherwise points right at the interpreter.
  • Writes all the per-user keys (no admin).
  • Adds a right-click “Run with AutoHotkey” entry as a backup for when UserChoice is in the way.
  • Warns you if a UserChoice is blocking things, and tells you exactly how to clear it.
  • Has an uninstall switch to cleanly rip it all back out.
  • Uses zero external libraries, so it runs on any bare machine you drop it on.

One thing I’ve learned over the years: the stuff that feels like it needs “permission” usually just needs understanding. A file association isn’t a privilege. It’s a few lines of text you already have the right to write. ⚡

The takeaway

  • File associations are registry text, not installed programs.
  • The per-user section is yours. No admin required.
  • The v2 launcher just changes which exe you name. Same technique.
  • Watch out for UserChoice. It’s the only thing that can block you, and it’s a one-time manual clear.
  • AutoHotkey’s own setup can do a per-user install if you’ve got the full folder.

Don’t let a locked-down PC stop you from automating. Time is the one thing you never get back, and a five-minute setup like this pays you back every single day. 🤖

P.S. The best automations are the boring ones you forget you set up. Build it once, then let it quietly save you time forever.

When you cannot use AutoHotkey

When AutoHotkey Isn’t an Option: Adding PowerShell to Our Automation Toolbox

AutoHotkey is our daily driver for Windows automation — but not every machine can run it. Locked-down corporate boxes, friends who can’t install software, shared kiosks: sometimes you need a fallback that’s already on the computer. We’re starting to lean on PowerShell 5.1 for exactly those situations, and here’s an honest look at what it can and can’t do compared to AHK v2.

Why PowerShell?

PowerShell 5.1 ships with every Windows 10 and Windows 11 install. No admin rights, no installer, no download — it’s already there. You hand it a plain .ps1 text file, and it runs. That alone makes it the most realistic AHK substitute when AutoHotkey is off the table.

Underneath, PowerShell sits on top of the full .NET Framework, which means it can reach into the Win32 API the same way AHK does — just with more typing. We polled a few AI flagship models (GPT-5.3 Codex, Gemini 3.1 Pro, Gemini 3 Flash) for sanity checks on the comparison, and all three landed on the same conclusion: PowerShell is the only serious built-in alternative.

What PowerShell Does Well

These are the tasks where PowerShell matches or beats AHK out of the box — no tricks required:

TaskPowerShell Approach
Copy, move, rename filesCopy-Item, Move-Item, Rename-Item
Read & write text filesGet-Content / Set-Content
Read & write the registryGet-ItemProperty / Set-ItemProperty on HKCU:\, HKLM:\
Launch programsStart-Process with full argument and redirect control
Drive Excel, Word, OutlookNew-Object -ComObject Excel.Application — identical COM as AHK
HTTP / REST API callsInvoke-RestMethod / Invoke-WebRequest
JSON parsingConvertFrom-Json / ConvertTo-Json built-in
WMI / CIM queriesGet-CimInstance Win32_Process (cleaner than AHK’s WMI calls)
ClipboardSet-Clipboard / Get-Clipboard
Scheduled tasksRegister-ScheduledTask — built-in, no AHK equivalent needed

For batch jobs — “rename every file in this folder”, “pull data from an API and dump to Excel”, “back up these registry keys nightly” — PowerShell is genuinely the right tool, not just a fallback.

What PowerShell Does Somewhat Well

These work, but they need an inline C# block (PowerShell’s Add-Type feature) to call the same Win32 APIs AHK calls for you automatically:

AHK v2 FeaturePowerShell Equivalent
Send "{Enter}"[System.Windows.Forms.SendKeys]::SendWait("{ENTER}")
WinActivateP/Invoke FindWindow + SetForegroundWindow via Add-Type
ControlSendP/Invoke PostMessage with child window handles
MouseMove / ClickP/Invoke SetCursorPos + mouse_event
PixelGetColorP/Invoke GetDC + GetPixel
Tray icon + menu[System.Windows.Forms.NotifyIcon] + message pump
Gui() windowsWinForms or WPF — works, but verbose and uglier syntax
SetTimerRegister-ObjectEvent on System.Timers.Timer

Here’s the pattern for reaching the Win32 API from PowerShell. It looks scarier than it is — once you have one of these blocks working, you copy-paste it into every script that needs the same API:

Add-Type -Namespace W -Name U32 -MemberDefinition @'
[DllImport("user32.dll")] public static extern IntPtr FindWindow(string c, string n);
[DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr h);
'@
$h = [W.U32]::FindWindow($null, "Untitled - Notepad")
[W.U32]::SetForegroundWindow($h)

What’s Genuinely Difficult in PowerShell

This is where AHK’s lead becomes unmistakable. These features exist in three characters of AHK and require a hundred-line scaffold in PowerShell:

FeatureWhy It’s Hard
Global hotkeys (#z::)Requires a hidden WinForms window hosting a message pump, plus RegisterHotKey calls per binding, plus a WndProc override to catch WM_HOTKEY. ~40 lines for what AHK does in one.
Hotstrings (::btw::by the way)No equivalent at all. Must install a low-level keyboard hook (WH_KEYBOARD_LL), buffer keystrokes, detect trigger sequences, replay via SendInput. ~150 lines of C# embedded in the script.
Persistent background daemonPowerShell exits when the script finishes. Need [System.Windows.Forms.Application]::Run() or a hidden message-pump form to keep it alive.
ImageSearchNothing built-in. Would require GDI+ pixel-walking in a C# block.
InputHook / key captureOnly achievable via low-level keyboard hook P/Invoke — same painful path as hotstrings.
UIA tree walkingUIAutomationClient.dll is in .NET, so it’s possible — but AHK’s UIA wrapper is dramatically more ergonomic.
Quick dark-themed GUIsWinForms doesn’t theme as easily as AHK’s Gui(). Every control needs per-property styling, and the result still feels like a 2005 Windows form.

One Big Gotcha: Locked-Down Machines

If you’re handing a script to someone whose IT department uses AppLocker or runs PowerShell in Constrained Language Mode, the Add-Type trick (and therefore most Win32 P/Invoke) is blocked. You’re left with just the cmdlets and COM objects. That’s still enough for file ops, registry, Excel automation, and HTTP — but anything that touches keyboard, mouse, or window control is off the table.

For unsigned .ps1 files on a normal user account, this one-liner gets around the default execution policy without admin:

powershell.exe -ExecutionPolicy Bypass -File "C:\path\to\script.ps1"

Our Plan Going Forward

AutoHotkey isn’t going anywhere as our primary tool — the hotkey, hotstring, GUI, and persistent-daemon side of what we build is where AHK earns its keep, and PowerShell can’t match that without a wall of boilerplate. But for the growing pile of jobs where AHK isn’t an option, PowerShell is going into the rotation:

  • One-shot batch jobs — file processing, API pulls, Excel reports, registry tweaks. PowerShell wins, full stop.
  • Scripts we hand to non-technical users who can’t install software. A .ps1 plus a one-line .bat launcher is the cleanest “no install” delivery method.
  • Scheduled background tasks — Task Scheduler integrates more naturally with PowerShell than with AHK.
  • Things that touch .NET deeply — reading Outlook, manipulating PDFs via iTextSharp, advanced Excel via COM. Easier and faster to write in PowerShell.

We’ll keep AutoHotkey for everything that demands real-time input control, custom hotkey layers, and the kind of polished dark-themed GUI that PowerShell makes painful. For everything else, having a second engine in the toolbox is going to pay off — especially for the friends and clients who say “I can’t install anything on my work laptop.”

Expect more posts as we build out our first batch of PowerShell tools. If you’ve got a specific automation task that’s been blocked because the target machine can’t run AHK, drop a comment — we’ll see if it makes a good walkthrough.