RORK LABJP
MAX — Rork Max generates native Swift apps for iPhone, iPad, Apple Watch, Apple TV, and Vision Pro, with two-click App Store publishing that never opens XcodeWIDGET — Rork Max also covers games, widgets, and live activities, widening the scope beyond the React Native output Rork started withFUND — Rork raised $2.8 million from a16z, and the platform now sees roughly 743,000 monthly visits with a reported 85% growth rateMAESTRO — Expo added an insights dashboard for Maestro end-to-end test runs on July 20, letting teams track run performance over timeCICD — A Posh case study published July 23 walks through rebuilding a mobile CI/CD pipeline on EAS Workflows, fingerprinting, and Expo UpdatesSIRI — The iOS 27 public beta opened on July 13, and its generative-AI Siri requires an A17 Pro chip or newer with at least 8 GB of RAMMAX — Rork Max generates native Swift apps for iPhone, iPad, Apple Watch, Apple TV, and Vision Pro, with two-click App Store publishing that never opens XcodeWIDGET — Rork Max also covers games, widgets, and live activities, widening the scope beyond the React Native output Rork started withFUND — Rork raised $2.8 million from a16z, and the platform now sees roughly 743,000 monthly visits with a reported 85% growth rateMAESTRO — Expo added an insights dashboard for Maestro end-to-end test runs on July 20, letting teams track run performance over timeCICD — A Posh case study published July 23 walks through rebuilding a mobile CI/CD pipeline on EAS Workflows, fingerprinting, and Expo UpdatesSIRI — The iOS 27 public beta opened on July 13, and its generative-AI Siri requires an A17 Pro chip or newer with at least 8 GB of RAM
Articles/App Dev
App Dev/2026-07-29Advanced

The same wallpaper appeared twice in my catalog — measuring perceptual hash thresholds across 324 images

Four approaches to image catalog deduplication measured end to end: SHA-256, dHash, a hue signature, and a block signature. dHash alone scored 0.9% precision. Here is why perceptual hashes collapse on smooth images, and how the ground truth turned out to be the thing that was wrong.

image processing2perceptual hashingdHashdeduplicationasset managementNode.jssharpindie development34

Premium Article

I was scrolling my own wallpaper app one morning when my thumb stopped.

The same artwork appeared twice, a dozen rows apart.

One came from the original launch batch, the other from a later import. Different filenames, different upload dates, so nothing in the catalog table had ever flagged it. When you maintain a few thousand image assets as an indie developer, this kind of drift accumulates quietly.

Nobody had complained in an App Store review. It still felt wrong that a paying user would scroll past the same picture twice.

Reviewing several thousand images by hand was not an option, so I built something to find them mechanically.

The design I sketched at the start was wrong twice over. Here is what the measurements actually showed.

Building a verification set I could re-run

Experimenting directly on the production catalog would have left me with no way to check my own results. Instead I synthesized a set with the same characteristics.

160 source images at 1290×2796, the iPhone portrait resolution — 40 each of gradients, blurred blobs, stripes, and noise clouds. That mix mirrors what a wallpaper catalog tends to contain.

From those I generated five kinds of derivative:

DerivativeCountGround truth
Re-encoded at JPEG quality 92 → 7454Duplicate
Resized 1290×2796 → 828×179232Duplicate
Brightness raised 6%23Duplicate
Cropped 2% on each edge, scaled back15Duplicate
Hue rotated 80 degrees40Distinct

324 images in total. Labeling the hue variants as distinct is the pivot of the whole exercise. In a wallpaper catalog the color variant is the product, and merging it would delete inventory.

Everything below was measured on Node 22.22.3 with sharp 8.18.3 (libvips).

SHA-256 gets you almost nothing

I started with a SHA-256 over the raw file bytes. A few lines of code, and it seemed reasonable to sweep the exact matches first.

It found 3 of the 124 real duplicates. A recall rate of 2.4%.

In hindsight the result is obvious. Re-encoding a JPEG changes every byte. So does resizing, brightness adjustment, and cropping. Byte equality only catches the case where the identical file was uploaded twice — and an upload-time guard had already been handling that case for years.

What remained in the catalog was precisely the category exact hashing cannot see: visually identical, byte-wise different.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
SHA-256 byte matching found 3 of 124 real duplicates — a 2.4% recall rate. The measured breakdown shows exactly which transformations defeat exact hashing and why re-encoding alone is enough
dHash at a Hamming threshold of 10 scored 97.5% recall against 0.9% precision, with 16,570 false pairs. The cause: 80 of 160 source images collapsed to an identical, information-free hash. A popcount gate brings false positives to zero
Complete implementation of a three-band classifier (auto-merge, human review, distinct) with 96.9% precision in the auto band, zero missed duplicates, and 20.6 ms per image across 324 files
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

App Dev2026-04-06
Rork App Monetization Complete Strategy: Building Revenue from Zero with AdMob, Subscriptions, and In-App Purchases
A complete guide to monetizing apps built with Rork. Covers AdMob ad design, subscription setup, and in-app purchases — with practical insights from an indie developer generating over ¥1M/month. Full content, free.
App Dev2026-07-18
Walk Through an App Store Submission Without Writing Code — Sticker Packs as a Dress Rehearsal
An iMessage sticker pack is one of the few things you can ship to the App Store with zero code. It cannot make money — and that constraint is exactly what makes it a clean rehearsal for the submission process.
App Dev2026-07-16
Placing Native Ads in a Masonry Wallpaper Grid: Designing the Lifetime of an Ad Cell
One native ad in a masonry gallery pushed memory from 180 MB to 420 MB over twenty minutes of scrolling. Here is why cell recycling and ad object lifetime never line up, the pool-based implementation that fixed it, and how I picked the insertion interval from measured numbers.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →