← back to Dw Photo Capture
auto-save: 2026-06-25T23:37:59 (8 files) — build_logo_fingerprints.py build_vendor_logos.py data/build.json data/logos/fabricut.jpg data/vendor_logos.json
33731b68f00c5485e78e457db32e235802ceab12 · 2026-06-25 23:38:02 -0700 · Steve Abrams
Files touched
A OVERNIGHT_LEDGER.mdM build_logo_fingerprints.pyM build_vendor_logos.pyM data/build.jsonM data/logos/fabricut.jpgA data/logos/kravet.pngM data/vendor_logos.jsonM data/vendor_profiles.json
Diff
commit 33731b68f00c5485e78e457db32e235802ceab12
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Thu Jun 25 23:38:02 2026 -0700
auto-save: 2026-06-25T23:37:59 (8 files) — build_logo_fingerprints.py build_vendor_logos.py data/build.json data/logos/fabricut.jpg data/vendor_logos.json
---
OVERNIGHT_LEDGER.md | 25 ++++++++++
build_logo_fingerprints.py | 26 ++++++++--
build_vendor_logos.py | 36 ++++++++++----
data/build.json | 5 +-
data/logos/fabricut.jpg | Bin 32116 -> 42749 bytes
data/logos/kravet.png | Bin 0 -> 33688 bytes
data/vendor_logos.json | 97 ++++++++++++-------------------------
data/vendor_profiles.json | 118 ++++++++++++++++++++++++++++-----------------
8 files changed, 182 insertions(+), 125 deletions(-)
diff --git a/OVERNIGHT_LEDGER.md b/OVERNIGHT_LEDGER.md
new file mode 100644
index 0000000..c66e1b2
--- /dev/null
+++ b/OVERNIGHT_LEDGER.md
@@ -0,0 +1,25 @@
+# dw-photo-capture — Overnight officer-yolo run
+
+Mode: **officer-yolo + dtd deciders** (Steve, 2026-06-25 night). DTD commits each
+real fork; the relevant VP officer (vp-engineering for code, vp-dw-commerce for
+catalog) is final sign-off; reversible local work ships freely; gated actions
+(deploy, Shopify writes, scheduled launchd jobs, spend, remote push) are DRAFTED
+to `~/.claude/yolo-queue/pending-approval/`, never executed.
+
+All scanner work is **local + $0**. Only metered cost is DTD Codex (~$0.03/run).
+
+## Backlog (safe / reversible unless flagged GATED)
+- [x] A-verdict: tighten logo matcher + validate fingerprints + re-harvest (DTD 3/3)
+- [ ] Wire logo fingerprints into /api/identify as a tiebreaker (was option B; safe after A)
+- [ ] analyzeOcr unit tests (project values pure/testable functions)
+- [ ] Barcode UX: show a "barcode" badge / distinct lock copy on a barcode lock
+- [ ] /learn: show logo `conf`, flag rejected logos, surface `matched_on` for review
+- [ ] Faster VLM path: moondream fast-mode toggle for /api/identify (env already supports model)
+- [ ] Auto-fire /api/identify in background on a lock-with-code-but-no-vendor (non-blocking)
+- [ ] /code-review (or claude-codex) pass on the full session diff; fix findings
+- [ ] GATED (draft only): weekly launchd refresh for vendor_profiles + logos + fingerprints
+
+## Cycle log
+| # | decision (DTD?) | action | result | cost |
+|---|-----------------|--------|--------|------|
+| 0 | A-verdict (DTD 3/3) | tighten matcher + fingerprint-validation + re-harvest | 26→19 logos, validation rejects mislabeled | $0.003 (1 DTD) + $0 local |
diff --git a/build_logo_fingerprints.py b/build_logo_fingerprints.py
index d1a93c6..66df587 100644
--- a/build_logo_fingerprints.py
+++ b/build_logo_fingerprints.py
@@ -41,12 +41,32 @@ for v, p in todo:
b64 = base64.b64encode(open(fp, "rb").read()).decode()
out = vlm(b64)
if out:
+ reads = out.get("reads_as") or ""
+ # VALIDATE: the logo must read back as THIS vendor. If the VLM sees a different
+ # brand (e.g. a mislabeled file), reject the logo so nothing downstream trusts it.
+ def norm(s): return re.sub(r"[^a-z0-9]", "", (s or "").lower())
+ nr, nv = norm(reads), norm(v)
+ # whole-WORD comparison (substring "century" in "20thcenturyfox" was the false-accept).
+ vwords = {w for w in re.findall(r"[a-z0-9]+", v.lower()) if len(w) >= 4}
+ rwords = {w for w in re.findall(r"[a-z0-9]+", reads.lower()) if len(w) >= 3}
+ shared = vwords & rwords
+ valid = bool(nr) and (
+ nr == nv or nr in nv or nv in nr or # one name contains the other
+ len(shared) >= 2 or # ≥2 shared significant words
+ (len(vwords) <= 1 and bool(shared)) # single-word vendor, exact word hit
+ )
p["logo_desc"] = out.get("logo") or ""
p["logo_typeface"] = out.get("typeface") or ""
- p["logo_reads"] = out.get("reads_as") or ""
+ p["logo_reads"] = reads
p["logo_colors"] = out.get("colors") or ""
- done += 1
- print(f" ✓ {v:28} reads='{p['logo_reads']}' type='{p['logo_typeface']}'")
+ p["logo_valid"] = valid
+ if not valid:
+ # don't let a wrong logo surface on /learn or bias /api/identify
+ p.pop("logo_url", None); p.pop("logo_file", None)
+ print(f" ✗ {v:28} REJECTED — logo reads as '{reads}' (not this vendor)")
+ else:
+ done += 1
+ print(f" ✓ {v:28} reads='{reads}' type='{p['logo_typeface']}'")
json.dump(prof, open(PROF, "w"), indent=0) # save incrementally (crash-safe)
except Exception as e:
print(f" ! {v}: {e}")
diff --git a/build_vendor_logos.py b/build_vendor_logos.py
index 47220d7..ae9db2f 100644
--- a/build_vendor_logos.py
+++ b/build_vendor_logos.py
@@ -67,19 +67,35 @@ for _ in range(40):
cursor = d["pageInfo"]["endCursor"]
print(f"scanned {len(files)} logo-ish files")
-# ── match files -> vendors (prefer the longest key match; logo-named files win) ─
-matches = {} # vendor -> best file
+# ── match files -> vendors (TIGHTENED: must be a logo file + anchored key match) ─
+def keymatch(k, fslug):
+ if k == fslug: return 1.0 # exact
+ if fslug.startswith(k) and len(k) >= 5: return 0.9 # file leads with the key
+ if k.startswith(fslug) and len(fslug) >= 5: return 0.85
+ if len(k) >= 7 and k in fslug: return 0.7 # long distinctive token contained
+ return 0.0
+MIN_CONF = 0.7
+matches, rejected = {}, []
for f in files:
+ # HARD requirement: the file must actually be a brand logo (name/alt says so).
+ if not ("logo" in f["url"].lower() or "logo" in (f["alt"] or "").lower()):
+ continue
fslug = clean_fileslug(f["url"], f["alt"])
- is_logo = "logo" in f["url"].lower() or "logo" in (f["alt"] or "").lower()
if not fslug or len(fslug) < 4: continue
+ best = None # (conf, vendor, key)
for v, keys in vkeys.items():
- hit = next((k for k in sorted(keys, key=len, reverse=True)
- if k == fslug or fslug.startswith(k) or (len(k) >= 6 and k in fslug)), None)
- if not hit: continue
- score = len(hit) + (5 if is_logo else 0)
- if v not in matches or score > matches[v]["score"]:
- matches[v] = {**f, "score": score, "key": hit, "fslug": fslug}
+ for k in keys:
+ c = keymatch(k, fslug)
+ if c and (best is None or c > best[0] or (c == best[0] and len(k) > len(best[2]))):
+ best = (c, v, k)
+ if not best or best[0] < MIN_CONF:
+ if best: rejected.append((fslug, best[1], round(best[0], 2)))
+ continue
+ c, v, k = best
+ if v not in matches or c > matches[v]["conf"]:
+ matches[v] = {**f, "conf": round(c, 2), "key": k, "fslug": fslug}
+if rejected:
+ print(f" ({len(rejected)} below-threshold pairs skipped, e.g. {rejected[:4]})")
print(f"matched {len(matches)} vendors to a logo file")
@@ -93,7 +109,7 @@ for v, m in sorted(matches.items()):
data = urllib.request.urlopen(m["url"], timeout=40).read()
open(os.path.join(LOGO_DIR, fn), "wb").write(data)
manifest[v] = {"file": "data/logos/" + fn, "url": m["url"], "w": m["w"], "h": m["h"],
- "matched_on": m["key"], "bytes": len(data)}
+ "matched_on": m["key"], "conf": m["conf"], "bytes": len(data)}
if v in prof["profiles"]: prof["profiles"][v]["logo_url"] = m["url"]; prof["profiles"][v]["logo_file"] = "data/logos/" + fn
except Exception as e:
print(f" ! {v}: download failed {e}")
diff --git a/data/build.json b/data/build.json
index 1d2a7da..c1972eb 100644
--- a/data/build.json
+++ b/data/build.json
@@ -1,5 +1,5 @@
{
- "next": 47,
+ "next": 48,
"map": {
"63863152": 27,
"578af86f": 2,
@@ -45,6 +45,7 @@
"3b47a090": 43,
"798e88ce": 44,
"77dbf02a": 45,
- "5ec6a90a": 46
+ "5ec6a90a": 46,
+ "394fc1cb": 47
}
}
\ No newline at end of file
diff --git a/data/logos/fabricut.jpg b/data/logos/fabricut.jpg
index 20f2812..31d0399 100644
Binary files a/data/logos/fabricut.jpg and b/data/logos/fabricut.jpg differ
diff --git a/data/logos/kravet.png b/data/logos/kravet.png
new file mode 100644
index 0000000..ce283ec
Binary files /dev/null and b/data/logos/kravet.png differ
diff --git a/data/vendor_logos.json b/data/vendor_logos.json
index d92465a..1abab00 100644
--- a/data/vendor_logos.json
+++ b/data/vendor_logos.json
@@ -1,24 +1,17 @@
{
"_meta": {
-"vendors_with_logo": 26,
+"vendors_with_logo": 19,
"scanned_files": 1028,
-"built_at": "2026-06-26T06:16:06.032984+00:00"
+"built_at": "2026-06-26T06:37:45.213544+00:00"
},
"logos": {
-"1838 Wallcoverings": {
-"file": "data/logos/1838wallcoverings.png",
-"url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/1838-Logo-Main.png?v=1614287356",
-"w": 300,
-"h": 217,
-"matched_on": "1838",
-"bytes": 11029
-},
"Andrew Martin": {
"file": "data/logos/andrewmartin.png",
"url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/andrew-martin-logo.png?v=1771983218",
"w": 480,
"h": 81,
"matched_on": "andrewmartin",
+"conf": 1.0,
"bytes": 12308
},
"Architectural Fabrics": {
@@ -27,14 +20,7 @@
"w": 1024,
"h": 1024,
"matched_on": "architecturalfabrics",
-"bytes": 264079
-},
-"Architectural Wallcoverings": {
-"file": "data/logos/architecturalwallcoverings.png",
-"url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/architectural-fabrics-logo.png?v=1772727678",
-"w": 1024,
-"h": 1024,
-"matched_on": "architectural",
+"conf": 1.0,
"bytes": 264079
},
"Armani Casa": {
@@ -43,14 +29,7 @@
"w": 480,
"h": 98,
"matched_on": "armanicasa",
-"bytes": 14409
-},
-"Armani/Casa": {
-"file": "data/logos/armanicasa.png",
-"url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/armani-casa-logo.png?v=1771983137",
-"w": 480,
-"h": 98,
-"matched_on": "armanicasa",
+"conf": 1.0,
"bytes": 14409
},
"Cole & Son": {
@@ -59,15 +38,17 @@
"w": 888,
"h": 144,
"matched_on": "coleson",
+"conf": 0.9,
"bytes": 48888
},
"Fabricut": {
"file": "data/logos/fabricut.jpg",
-"url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/Fabricut_Trend_logo.jpg?v=1618201668",
-"w": 900,
-"h": 450,
+"url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/Fabricut-Logo.jpg?v=1618201668",
+"w": 4611,
+"h": 585,
"matched_on": "fabricut",
-"bytes": 32116
+"conf": 1.0,
+"bytes": 42749
},
"Hollywood Acoustical": {
"file": "data/logos/hollywoodacoustical.png",
@@ -75,23 +56,17 @@
"w": 646,
"h": 217,
"matched_on": "hollywood",
-"bytes": 45807
-},
-"Hollywood Wallcoverings": {
-"file": "data/logos/hollywoodwallcoverings.png",
-"url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/The-Hollywood-Reporter-Logo.png?v=1613539141",
-"w": 646,
-"h": 217,
-"matched_on": "hollywood",
+"conf": 0.7,
"bytes": 45807
},
"Kravet": {
-"file": "data/logos/kravet.jpg",
-"url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/vendor_kravet_logo.jpg?v=1617905330",
-"w": 200,
-"h": 200,
+"file": "data/logos/kravet.png",
+"url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/kravet-logo.png?v=1771983130",
+"w": 480,
+"h": 182,
"matched_on": "kravet",
-"bytes": 6494
+"conf": 1.0,
+"bytes": 33688
},
"Lee Jofa": {
"file": "data/logos/leejofa.jpg",
@@ -99,6 +74,7 @@
"w": 502,
"h": 283,
"matched_on": "leejofa",
+"conf": 0.9,
"bytes": 10429
},
"Mid Century Modern": {
@@ -107,6 +83,7 @@
"w": 648,
"h": 365,
"matched_on": "century",
+"conf": 0.7,
"bytes": 58493
},
"Mind the Gap": {
@@ -115,30 +92,16 @@
"w": 450,
"h": 252,
"matched_on": "mindthegap",
+"conf": 1.0,
"bytes": 8255
},
-"NLXL": {
-"file": "data/logos/nlxl.jpg",
-"url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/nlxl-wallpaper-logo-Small.jpg?v=1613558667",
-"w": 100,
-"h": 34,
-"matched_on": "nlxl",
-"bytes": 1160
-},
-"Nina Campbell": {
-"file": "data/logos/ninacampbell.jpg",
-"url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/nina-campbell-logo.jpg?v=1618201668",
-"w": 270,
-"h": 130,
-"matched_on": "ninacampbell",
-"bytes": 4504
-},
"Nina Campbell Wallcoverings": {
"file": "data/logos/ninacampbellwallcoverings.jpg",
"url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/nina-campbell-logo.jpg?v=1618201668",
"w": 270,
"h": 130,
"matched_on": "ninacampbell",
+"conf": 1.0,
"bytes": 4504
},
"Phillip Jeffries": {
@@ -147,6 +110,7 @@
"w": 492,
"h": 482,
"matched_on": "phillipjeffries",
+"conf": 1.0,
"bytes": 40385
},
"Ralph Lauren": {
@@ -155,14 +119,7 @@
"w": 600,
"h": 600,
"matched_on": "ralphlauren",
-"bytes": 7748
-},
-"Ralph Lauren Fabric": {
-"file": "data/logos/ralphlaurenfabric.png",
-"url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/Fabric-Logo-Ralph-Lauren-Home.png?v=1613539290",
-"w": 600,
-"h": 600,
-"matched_on": "ralphlauren",
+"conf": 0.7,
"bytes": 7748
},
"Rebel Walls": {
@@ -171,6 +128,7 @@
"w": 500,
"h": 143,
"matched_on": "rebelwalls",
+"conf": 0.9,
"bytes": 30621
},
"Schumacher": {
@@ -179,6 +137,7 @@
"w": 900,
"h": 500,
"matched_on": "schumacher",
+"conf": 0.9,
"bytes": 7931
},
"Telefina Fine Fabrics": {
@@ -187,6 +146,7 @@
"w": 600,
"h": 600,
"matched_on": "telefina",
+"conf": 0.7,
"bytes": 6451
},
"Thibaut": {
@@ -195,6 +155,7 @@
"w": 259,
"h": 53,
"matched_on": "thibaut",
+"conf": 0.9,
"bytes": 3253
},
"Versace": {
@@ -203,6 +164,7 @@
"w": 180,
"h": 222,
"matched_on": "versace",
+"conf": 0.7,
"bytes": 28518
},
"William Morris": {
@@ -211,6 +173,7 @@
"w": 455,
"h": 115,
"matched_on": "williammorris",
+"conf": 1.0,
"bytes": 17347
}
}
diff --git a/data/vendor_profiles.json b/data/vendor_profiles.json
index 16581e2..407e316 100644
--- a/data/vendor_profiles.json
+++ b/data/vendor_profiles.json
@@ -5,7 +5,8 @@
"built_at": "2026-06-26T06:01:30.211846+00:00",
"source": "catalog-bulk",
"updated_at": "2026-06-26T06:02:15.340Z",
-"logos_attached": 26
+"logos_attached": 19,
+"logos_fingerprinted": 26
},
"profiles": {
"Fentucci": {
@@ -59,15 +60,14 @@
"code_source": "mfr",
"learned_scans": 0,
"updated_at": "2026-06-26T06:01:29.716310+00:00",
-"logo_url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/180px-Versace_logo.png?v=1618201668",
-"logo_file": "data/logos/versace.png",
-"logo_desc": "Elegant serif-style wordmark with a modern twist, featuring the name 'Savannah' in a sophisticated font.",
"logo_typeface": "sans caps",
"logo_reads": "Savannah",
"logo_colors": [
"black",
"white"
-]
+],
+"logo_desc": "Elegant serif-style wordmark with a modern twist, featuring the name 'Savannah' in a sophisticated font.",
+"logo_valid": false
},
"Elitis": {
"n": 243,
@@ -149,13 +149,14 @@
"updated_at": "2026-06-26T06:01:29.722661+00:00",
"logo_url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/mind-the-gap-logo.png?v=1618201668",
"logo_file": "data/logos/mindthegap.png",
-"logo_desc": "Modern, clean design with a minimalist approach.",
"logo_typeface": "sans caps",
"logo_reads": "MINDTHEGAP DESIGN&SUPPLY",
"logo_colors": [
"white",
"black"
-]
+],
+"logo_desc": "Modern, clean design with a minimalist approach.",
+"logo_valid": true
},
"Wolf Gordon": {
"n": 1658,
@@ -462,7 +463,6 @@
"updated_at": "2026-06-26T06:01:29.752778+00:00",
"logo_url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/architectural-fabrics-logo.png?v=1772727678",
"logo_file": "data/logos/architecturalfabrics.png",
-"logo_desc": "Modern, minimalist logo with a triangular shape and vertical lines",
"logo_typeface": "sans caps",
"logo_reads": "ARCHITECTURAL FABRICS",
"logo_colors": [
@@ -542,7 +542,6 @@
"updated_at": "2026-06-26T06:01:29.758648+00:00",
"logo_url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/1838-Logo-Main.png?v=1614287356",
"logo_file": "data/logos/1838wallcoverings.png",
-"logo_desc": "classical crest with year and product name below",
"logo_typeface": "sans caps",
"logo_reads": "1838 WALLCOVERINGS",
"logo_colors": [
@@ -768,14 +767,13 @@
"code_source": "mfr",
"learned_scans": 0,
"updated_at": "2026-06-26T06:01:29.796971+00:00",
-"logo_url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/vendor_kravet_logo.jpg?v=1617905330",
-"logo_file": "data/logos/kravet.jpg",
-"logo_desc": "Modern, clean logo with a focus on simplicity and brand identity.",
+"logo_url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/kravet-logo.png?v=1771983130",
+"logo_file": "data/logos/kravet.png",
"logo_typeface": "sans caps",
-"logo_reads": "Kravet",
+"logo_reads": "kravet",
"logo_colors": [
"black",
-"blue"
+"white"
]
},
"Ralph Lauren": {
@@ -805,7 +803,6 @@
"updated_at": "2026-06-26T06:01:29.798572+00:00",
"logo_url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/Fabric-Logo-Ralph-Lauren-Home.png?v=1613539290",
"logo_file": "data/logos/ralphlauren.png",
-"logo_desc": "Elegant serif wordmark with a classic touch for home decor brand",
"logo_typeface": "sans caps",
"logo_reads": "RALPH LAUREN Home",
"logo_colors": [
@@ -1257,7 +1254,6 @@
"updated_at": "2026-06-26T06:01:29.850492+00:00",
"logo_url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/Phillip_Jeffries_Logo.png?v=1722453555",
"logo_file": "data/logos/phillipjeffries.png",
-"logo_desc": "Phillip Jeffries logo with natural, textured, specialty wallcoverings text below",
"logo_typeface": "serif wordmark",
"logo_reads": "PHILLIP JEFFRIES",
"logo_colors": [
@@ -1393,14 +1389,12 @@
"code_source": "mfr",
"learned_scans": 0,
"updated_at": "2026-06-26T06:01:29.851666+00:00",
-"logo_url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/Fabricut_Trend_logo.jpg?v=1618201668",
+"logo_url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/Fabricut-Logo.jpg?v=1618201668",
"logo_file": "data/logos/fabricut.jpg",
-"logo_desc": "Fabricut Trend logo with serif and sans-serif text, separated by a horizontal line.",
-"logo_typeface": "sans caps",
-"logo_reads": "FABRICUT trend",
+"logo_typeface": "serif wordmark",
+"logo_reads": "FABRICUT",
"logo_colors": [
-"brown",
-"purple"
+"brown"
]
},
"Marimekko Exclusive": {
@@ -1588,15 +1582,14 @@
"code_source": "mfr",
"learned_scans": 0,
"updated_at": "2026-06-26T06:01:29.855689+00:00",
-"logo_url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/Fabric-Logo-Telefina.png?v=1618201668",
-"logo_file": "data/logos/telefinafinefabrics.png",
-"logo_desc": "Modern, minimalist logo with a unique serif-like 'f' and geometric spacing.",
"logo_typeface": "sans caps",
"logo_reads": "TELAFINA",
"logo_colors": [
"black",
"white"
-]
+],
+"logo_url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/Fabric-Logo-Telefina.png?v=1618201668",
+"logo_file": "data/logos/telefinafinefabrics.png"
},
"Alan Campbell": {
"n": 36,
@@ -1667,7 +1660,6 @@
"updated_at": "2026-06-26T06:01:29.866878+00:00",
"logo_url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/schumacher-and-co-vector-logo.png?v=1618202886",
"logo_file": "data/logos/schumacher.png",
-"logo_desc": "Elegant serif wordmark with a classic and timeless feel, emphasizing heritage.",
"logo_typeface": "sans caps",
"logo_reads": "SCHUMACHER",
"logo_colors": [
@@ -1705,7 +1697,6 @@
"updated_at": "2026-06-26T06:01:29.880609+00:00",
"logo_url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/Lee-Jofa-logo-large.jpg?v=1616003625",
"logo_file": "data/logos/leejofa.jpg",
-"logo_desc": "Elegant serif-style text with a registered trademark symbol",
"logo_typeface": "sans caps",
"logo_reads": "LEE JOFA",
"logo_colors": [
@@ -1740,7 +1731,6 @@
"updated_at": "2026-06-26T06:01:29.898246+00:00",
"logo_url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/thibaut-design-logo-homepage-big.png?v=1613639477",
"logo_file": "data/logos/thibaut.png",
-"logo_desc": "Modern, clean, and minimalist logo for a wallcovering/fabric maker.",
"logo_typeface": "sans caps",
"logo_reads": "THIBAUT",
"logo_colors": [
@@ -1923,7 +1913,6 @@
"updated_at": "2026-06-26T06:01:29.902529+00:00",
"logo_url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/Fabric-Logo-Ralph-Lauren-Home.png?v=1613539290",
"logo_file": "data/logos/ralphlaurenfabric.png",
-"logo_desc": "Elegant serif wordmark with a classic touch for home decor brand",
"logo_typeface": "sans caps",
"logo_reads": "RALPH LAUREN Home",
"logo_colors": [
@@ -2178,7 +2167,6 @@
"updated_at": "2026-06-26T06:01:29.910316+00:00",
"logo_url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/The-Hollywood-Reporter-Logo.png?v=1613539141",
"logo_file": "data/logos/hollywoodacoustical.png",
-"logo_desc": "Red background with white cursive text for 'The Hollywood Reporter'",
"logo_typeface": "script",
"logo_reads": "<The Hollywood Reporter>",
"logo_colors": [
@@ -2261,7 +2249,6 @@
"updated_at": "2026-06-26T06:01:29.912819+00:00",
"logo_url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/nina-campbell-logo.jpg?v=1618201668",
"logo_file": "data/logos/ninacampbellwallcoverings.jpg",
-"logo_desc": "Elegant serif wordmark with initials and name in a classic style",
"logo_typeface": "serif",
"logo_reads": "<NC Nina Campbell>",
"logo_colors": [
@@ -2418,7 +2405,6 @@
"updated_at": "2026-06-26T06:01:29.918485+00:00",
"logo_url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/nlxl-wallpaper-logo-Small.jpg?v=1613558667",
"logo_file": "data/logos/nlxl.jpg",
-"logo_desc": "bold, white sans-serif text on black background",
"logo_typeface": "sans caps",
"logo_reads": "NLXL",
"logo_colors": [
@@ -2568,7 +2554,6 @@
"updated_at": "2026-06-26T06:01:29.925992+00:00",
"logo_url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/20th_Century_Fox_Logo_1953_1987.jpg?v=1613539160",
"logo_file": "data/logos/midcenturymodern.jpg",
-"logo_desc": "golden, three-dimensional text with a retro aesthetic",
"logo_typeface": "sans caps",
"logo_reads": "20th CENTURY FOX",
"logo_colors": [
@@ -2654,7 +2639,6 @@
"updated_at": "2026-06-26T06:01:29.951529+00:00",
"logo_url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/nina-campbell-logo.jpg?v=1618201668",
"logo_file": "data/logos/ninacampbell.jpg",
-"logo_desc": "Elegant serif wordmark with initials and name in a classic style",
"logo_typeface": "serif",
"logo_reads": "<NC Nina Campbell>",
"logo_colors": [
@@ -2710,7 +2694,13 @@
"learned_scans": 0,
"updated_at": "2026-06-26T06:01:29.952000+00:00",
"logo_url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/andrew-martin-logo.png?v=1771983218",
-"logo_file": "data/logos/andrewmartin.png"
+"logo_file": "data/logos/andrewmartin.png",
+"logo_typeface": "sans caps",
+"logo_reads": "ANDREW MARTIN",
+"logo_colors": [
+"black",
+"white"
+]
},
"Armani Casa": {
"n": 3,
@@ -2732,7 +2722,13 @@
"learned_scans": 0,
"updated_at": "2026-06-26T06:01:29.952229+00:00",
"logo_url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/armani-casa-logo.png?v=1771983137",
-"logo_file": "data/logos/armanicasa.png"
+"logo_file": "data/logos/armanicasa.png",
+"logo_typeface": "sans caps",
+"logo_reads": "ARMANI/CASA",
+"logo_colors": [
+"black",
+"white"
+]
},
"Trikes-DL Couch-Eykon-Tower": {
"n": 807,
@@ -3040,7 +3036,13 @@
"learned_scans": 0,
"updated_at": "2026-06-26T06:01:30.021994+00:00",
"logo_url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/armani-casa-logo.png?v=1771983137",
-"logo_file": "data/logos/armanicasa.png"
+"logo_file": "data/logos/armanicasa.png",
+"logo_typeface": "sans caps",
+"logo_reads": "ARMANI/CASA",
+"logo_colors": [
+"black",
+"white"
+]
},
"Plains": {
"n": 36,
@@ -3570,7 +3572,13 @@
"learned_scans": 0,
"updated_at": "2026-06-26T06:01:30.104244+00:00",
"logo_url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/architectural-fabrics-logo.png?v=1772727678",
-"logo_file": "data/logos/architecturalwallcoverings.png"
+"logo_file": "data/logos/architecturalwallcoverings.png",
+"logo_typeface": "sans caps",
+"logo_reads": "ARCHITECTURAL FABRICS",
+"logo_colors": [
+"black",
+"white"
+]
},
"Malibu Wallpaper": {
"n": 2107,
@@ -3806,7 +3814,13 @@
"learned_scans": 0,
"updated_at": "2026-06-26T06:01:30.136941+00:00",
"logo_url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/Cole_Son_Crest_CPEW_F_Logo_K.png?v=1615935303",
-"logo_file": "data/logos/coleson.png"
+"logo_file": "data/logos/coleson.png",
+"logo_typeface": "script",
+"logo_reads": "Cole & Son",
+"logo_colors": [
+"gold",
+"black"
+]
},
"Arte": {
"n": 3,
@@ -4034,7 +4048,13 @@
"learned_scans": 0,
"updated_at": "2026-06-26T06:01:30.152292+00:00",
"logo_url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/william-morris-logo.png?v=1773242140",
-"logo_file": "data/logos/williammorris.png"
+"logo_file": "data/logos/williammorris.png",
+"logo_typeface": "sans caps",
+"logo_reads": "WILLIAM MORRIS WALLCOVERINGS",
+"logo_colors": [
+"black",
+"gold"
+]
},
"MC Escher Wallpaper": {
"n": 50,
@@ -4521,7 +4541,13 @@
"learned_scans": 0,
"updated_at": "2026-06-26T06:01:30.190123+00:00",
"logo_url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/The-Hollywood-Reporter-Logo.png?v=1613539141",
-"logo_file": "data/logos/hollywoodwallcoverings.png"
+"logo_file": "data/logos/hollywoodwallcoverings.png",
+"logo_typeface": "script",
+"logo_reads": "<The Hollywood Reporter>",
+"logo_colors": [
+"red",
+"white"
+]
},
"Cloth and Paper": {
"n": 36,
@@ -4574,7 +4600,13 @@
"learned_scans": 0,
"updated_at": "2026-06-26T06:01:30.203781+00:00",
"logo_url": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/Rebel_Walls_Logo_500px-3.jpg?v=1613550520",
-"logo_file": "data/logos/rebelwalls.jpg"
+"logo_file": "data/logos/rebelwalls.jpg",
+"logo_typeface": "script",
+"logo_reads": "Rebel Walls",
+"logo_colors": [
+"red",
+"black"
+]
},
"Limited Stock Prints": {
"n": 60,
← 85dccb3 Harvest vendor logos from Shopify Files → ground logo recogn
·
back to Dw Photo Capture
·
Logos: tighten matcher + validate fingerprints (DTD-A verdic 3c0bcb1 →