Verdetto

Verdetto

@verdettoqr.com

Solo developer making Verdetto, a QR and barcode scanner for Android. Notes on torn codes and camera pipelines. Google Play: https://play.google.com/store/apps/details?id=com.verdettoqr.scanner Posted by the developer; drafts prepared with AI assistance.

32 followers55 following163 posts

Pinned

Inside a ring gear, three planets turn around one sun, the first plate of MOTION, my mechanical atlas. Here it's the print with the plate running, and its code opens the page, at verdettoqr.com/m/01. Matte paper, printed to order, $29 or framed $69, and each one supports my free scanner app.

Every character in a link makes its QR code harder to print small. In my scanner a link up to 42 characters long still counts as small. Past 213, I ask for a 5 cm print. #GraphicDesign #AndroidDev

Printed music lives in the barcode range for books. A book's barcode starts 978 or 979, but 979-0 belongs to the ISMN, sheet music's own number. I make my scanner check that fourth digit before it says book. #Barcodes #AndroidDev

Until this month my scanner would have warned that a link to its own Bluesky profile downloads a Windows program. The path ends in verdettoqr.com, and .com was on its list of executable endings. It's off now. Chromium only lists it for Windows anyway. #AppSec #AndroidDev

Greek needed the smallest captions of all thirty-four languages in my app's short film. Its line for torn codes runs about two thirds longer than the English. It fell below the size floor to a wrapped fallback. German, the one I'd braced for, fit at the floor. #i18n #Typography

Quote a Wi-Fi QR code's network name when it's all hex digits, like CAFE or 1234. Android's older Wi-Fi API reads a bare one as raw bytes and looks for a different network. My code maker quotes those now, but a sixty-four digit hex password stays bare. That one's a real WPA key. #QRCode #AndroidDev

Parsing my scanner's safety list at process start made it land a third of a second after the camera. Codes read in that gap didn't get a list check. On a two-core emulator the parse fought the first frame. Now it starts behind that frame and reads wait for it. #AndroidDev #Kotlin

Nothing moves here but the gear train, and that's the point. Ten seconds of the first plate of MOTION, my atlas of mechanisms, cut to read like the print on a wall. The planetary set sits in a cordless drill too. Printed to order on matte paper from $29. The plate runs at verdettoqr.com/m/01

Twelve digits sit in an EAN-13's bars and thirteen on its label, so I drew one to find the missing digit. Each left digit comes in an odd or an even shape, and the run of odds and evens spells the first one. In this drawing it's a five.

Charted the six tables behind my scanner's lookups this morning. Books holds thirty-seven million rows, products four and a half million, and the other four sit well under three hundred thousand. Each is cut into shards by a hash, so a phone fetches one small file and sends no barcode.

Crank, coupler, rocker, ground: four bars that turn a steady spin into a rocking swing. It's the seventh plate of MOTION, my mechanical atlas, here as the print with the plate running, at verdettoqr.com/m/07. Matte paper, printed to order, $29 or framed $69, each one supporting my free scanner app.

Live on Google Play from this morning, a bit over a day after I applied for production. F-Droid has had it since late September, so the two stores finally match. The counter says five plus already, all of them my testers. Which store do you reach for first? #Android

French runs a fifth over the English in my app, and that's the easy part. In seven of ten, one string in twenty passes one and a half times, the worst over triple. Two Russian labels shipped at three lines before a width gate caught them. Which string broke your layout first? #Localization

Any app's share sheet can hand my scanner a link now, and it lands on the result sheet a scan gets. I'd tried two entries, check a link and add to a list. One entry that sorts by what arrives won. A title beside the address still counts as a link. #AndroidDev

Lean copies bite. My site builder blanks the sitemap on purpose and then read the live languages from it. It found none, and one new English key dropped all 23 live languages until the per-page store answered too. I'd assumed a sitemap is always there. #WebDev

Until now, a scam report from my app got a thank-you and silence. 1.1.2 adds Your reports: how many went from this phone and what became of each. Each row says pending or listed, with the date. No account. No server call either: it reads the list the phone already has. #AndroidDev

There's a page to play with behind the desk mat I've just put in the shop. Type a word and it comes back the ten ways the mat spells it. The code printed on the mat points at that page and nowhere else. I wanted an object that works with no app at all. verdettoqr.com/mat

Build eleven is up on F-Droid with the line I look for. It is built and signed by the original developer. Their builder compiled my tag with the Rust toolchain pinned in the recipe and got the bytes I signed. What's the step that breaks reproducibility first in your pipeline? #FDroid

Seventy degrees off square and the reader still got the link out of a QR code in my damage corpus. At 75 it let go. I'd expected the finders to merge long before that. The corpus is public, minus that last failing step. Do you straighten the phone before a scan, or let the reader cope? #QRCode

Covering a QR code's middle with a logo has a real cost, and I watched it happen. The same link at the lowest error-correction level wouldn't read with its center blanked. At the highest it came back exact. My app jumps to level H when you add a center picture. Do you put logos on yours? #QRCode

Found out my site's rebuild has to fit in 128 MB, finished pages and all. I'd inlined the stylesheet and the icon sprite into every page, and that broke once the page count nearly tripled. One shared CSS file and a per-page sprite fixed it. Do you cap a build's memory on purpose? #WebDev

Most of my product sheet mirrored into Arabic on its own. Not the share card. It's drawn on a Canvas, so Compose can't flip it for me and it reads the direction itself before the render. Digits stay left to right, as they should. Does your Canvas get told the direction too? #AndroidDev

Watching F-Droid rebuild my app from the tag in under eight minutes and match the APK I'd signed still surprises me. Quicker than I'd have guessed for a bare machine fetching its own toolchain. Three releases in, the match has held, and they ship my signature on their build. #FDroid #AndroidDev

Set my test phone's theme to Wallpaper and the app turned it down. The palette would blend with the warning chips, so the teal stays. I hadn't expected it to fire. It checks the containers against the danger and caution fills by hue, then RGB distance. #AndroidDev

Eighteen characters come off a door-jamb VIN label, an I ahead of the seventeen. My own car's label read as text at first. Two pixels a bar on a wavy label, and the long Code 39 came back exact on the first pass. Add perspective and uneven light and it's gone on both passes. #barcode #AndroidDev

Ran a Code 128 through the simulator's heaviest ink spread. Every bar comes out fatter, every space thinner. The decoder I wrote lost it at the mild setting. zxing-cpp didn't, because it measures start-of-bar to start-of-bar, and ink spread can't move that. #AndroidDev

Went back to this on the decoder tiers that ship in the app, and the first pass reads both spreads, exact. What lost it last week was my harness's own sweep pass. The app doesn't use that pass, and I'd worded it badly.

Just over four and a half million products in my lookup copy, cut into eight thousand files. A scan fetches one of them, picked by thirteen bits of the barcode's hash. Last night's refresh touched all but twenty-eight files. I hadn't expected a change that wide. #barcode #AndroidDev

Scrambled the whole timing pattern of a level L QR code and both readers still read it. Put a white blob on one corner square at level H and neither got anything. I'd always thought of that dotted line as load-bearing. It isn't. #QRcode #AndroidDev

Two pixels a bar under a diagonal camera smear, and I'd expected nothing back. The edge finder found no edges. The second pass guessed the blur and fitted a model of the bars under it to the smudge. HELLO-2026, exact. I didn't believe it until I'd stared at the capture a while. #barcode #AndroidDev

Tests per hundred lines of Kotlin, by package, and I'd guessed the order wrong. The decode engine is densest and the screens thinnest. The Create screen from this morning's note sits near the bottom, which is where I'd been trusting my eyes. #Kotlin #AndroidDev

Reading my own app's permission list on F-Droid felt like an audit. The camera is the scanner and the Wi-Fi pair lets a Wi-Fi code join the network for you. Network access is there for the lookups, and one switch in Settings turns those off. #FOSS #Android

Escaping was the bit I'd underestimated in the Create screen. A Wi-Fi name with a semicolon needs a backslash before that character, or the reader splits the field in two. So each kind has a test that scans the awkward characters back out as typed. #AndroidDev #QRCode

Turns out right-to-left cost me one flag in the page builder. I'd used inline-start and inline-end for nearly every edge since day one, so dir=rtl mirrors the page on its own. Found one stray margin-left while writing this, a zero, so it gets away with it. #WebDev #CSS

Swap the 1 in paypa1 for an l and it spells the brand. I'd lumped every lookalike together until I wrote this chip. That one says Imitates. One letter off could be a typo, so it only gets a caution. #AndroidDev #Phishing

I'd assumed a scratch is a scratch to a QR code. The damage corpus disagrees. A band across the middle beat both readers at a tenth of the height. The same band down the middle read at a fifth of the width. Data runs in columns, so a cut across nicks nearly every codeword. #QRCode #AndroidDev

I'd been reading a model year out of every VIN's tenth character. That was wrong. Only North American numbers put the year there by rule, so the app reads one only when the check digit matches too. Elsewhere that slot is the maker's to fill. #AndroidDev #Kotlin

Material says a modal sheet blocks what's behind it. I kept the scrim and handle and left the camera live under the half sheet. Another code in view is one tap away. I'd assumed pausing the camera under it was a free win. It wasn't. A rebind costs more than a short pause saves. #AndroidDev

The same two-sentence store blurb is sixty-four characters in English and eighty in German, which is the cap. I'd left room on purpose and German used all of it. Japanese says it in twenty-four. A character limit is a different budget in every language. #AndroidDev

My F-Droid recipe pointed at the release tag, and the reviewer asked for the commit hash instead. I'd thought the tag was the cleaner pin. A tag can move after the fact, a hash can't, and their build must match the APK I signed byte for byte. #AndroidDev

A barcode this time, not a QR code. The simulator smeared a Code 128 label seven pixels at 24 degrees, as a hand moves. A narrow bar is about seven pixels, so the smear is nearly one bar wide. Both routes read it exactly, the own linear decoder in 322 ms. #AndroidDev #BuildInPublic

The bent page beat the reader. This morning's crease was only a shadow, and someone caught that. So this time the simulator warped the page itself, ten pixels each way. Own QR path and zxing-cpp both got nothing. The gentler page-curl scenario still reads exactly. #AndroidDev #BuildInPublic

Testing the reader with no phone in hand: a rendered QR code on simulated paper, through the phone simulator (grain, lens, light, sensor noise, JPEG), today with a crease folded through the code. Read back exactly: own QR path 0.41 s, zxing-cpp 0.71 s. 87 scenarios so far. #AndroidDev #BuildInPublic

A camera's Y plane is not width x height bytes. Rows sit rowStride apart, and the stride can run past the width: copy it as width x height and a QR code comes out as stripes. The buffer ends at the last meaningful pixel: a stride x height check rejects padded frames. Ours did. #AndroidDev #Kotlin

Error correction is paid in modules. One 23-byte link: version 2 at levels L and M (25 modules a side), version 3 at Q and H (29 a side). At one print width each module shrinks about 14 percent. M repairs 15 percent of the codewords, H 30: H for a logo, M for a small sticker. #QRCode #Design

Lessons from six days in F-Droid's review queue: the first question is what the app does that others don't, not the recipe. Full commit hash, never a tag. One build entry until merged. rustup from Debian. Own server on by default: declare TetheredNet yourself. #FDroid #ReproducibleBuilds

Verdetto 1.0.8 is on F-Droid and GitLab. The change I would point at: the vehicle sheet now finds recall campaigns, crash-test ratings and fuel economy under the names NHTSA and EPA use for the model year, so 2026 vehicles show what is on file. Not a government app. #Android #FDroid

By the spec a QR code keeps a quiet zone four modules wide on every side. Readers forgive most of it: zxing-cpp's finder check accepts almost none, and it read this code with a dark frame 4, 2 and 1 modules away. Touching, no read: the frame merges with the finder's outer ring. #QRCode #Design