Logo from a domain, programmatic generate()
- logo_fetch.py: find a company's logo from its domain (homepage logo candidates, staging URLs, touch icons, favicon services), cached by domain - generate_sprite.py: --domain / --logo-cache, domain column in --batch, logos as PIL images, generate(..., write_files=False) for use as a library
This commit is contained in:
46
README.md
46
README.md
@@ -37,6 +37,9 @@ python generate_sprite.py "Rosas Landscaping" logos/rosas.png --type grass --rer
|
||||
|
||||
# Both libraries side by side
|
||||
python generate_sprite.py "Rosas Landscaping" logos/rosas.png --type grass --compare
|
||||
|
||||
# No logo file: find the logo on the business's website
|
||||
python generate_sprite.py "Rosas Landscaping" --domain rosaslandscaping.com --type grass
|
||||
```
|
||||
|
||||
Each run writes `sprites/<slug>.png`, `sprites/<slug>@4x.png` and `sprites/<slug>.json` (library, type, parts, colors). With `--reroll N`, the file names end in `-rN`. With `--compare`, each library writes `<slug>-<library>.*` and `<slug>-compare.png` shows them next to each other at the same height. Both use the same type and colors.
|
||||
@@ -51,12 +54,14 @@ Each run writes `sprites/<slug>.png`, `sprites/<slug>@4x.png` and `sprites/<slug
|
||||
| `--compare` | Render with both libraries and write a comparison sheet |
|
||||
| `--out DIR` | Output folder (default `sprites`) |
|
||||
| `--scale N` | Size of the upscaled copy (default 4, `1` disables it) |
|
||||
| `--domain D` | Find the logo on this website when no logo file or `--colors` is given (see [Logo from a domain](#logo-from-a-domain)) |
|
||||
| `--logo-cache DIR` | Where logos found with `--domain` are cached (default `logos`) |
|
||||
|
||||
Logo colors: transparent pixels, soft edge pixels and a solid white/black/gray background are ignored, and colored brand colors are used before white, black or gray. A logo with only white, black or gray in it still uses those colors.
|
||||
|
||||
## Batch
|
||||
|
||||
Use a CSV with the columns `name,logo,type,description`. Only `name` is required, and rows with no `type` use the classifier.
|
||||
Use a CSV with the columns `name,logo,domain,type,description`. Only `name` is required. Rows with no `type` use the classifier, and rows with a `domain` but no `logo` look the logo up on that website.
|
||||
|
||||
```bash
|
||||
OPENROUTER_API_KEY=<API_KEY> python generate_sprite.py --batch businesses.csv --out sprites
|
||||
@@ -64,6 +69,45 @@ OPENROUTER_API_KEY=<API_KEY> python generate_sprite.py --batch businesses.csv --
|
||||
|
||||
Add `--compare` to get both libraries for every row.
|
||||
|
||||
## Logo from a domain
|
||||
|
||||
`logo_fetch.py` finds a business's logo from its website and caches it by domain.
|
||||
|
||||
```bash
|
||||
python logo_fetch.py rosaslandscaping.com --out logos # -> logos/rosaslandscaping.com.png (method)
|
||||
python logo_fetch.py rosaslandscaping.com --extra https://staging.example.net/ # also search this page
|
||||
```
|
||||
|
||||
```python
|
||||
from logo_fetch import fetch_logo, fetch_logo_info, normalize_domain
|
||||
fetch_logo("rosaslandscaping.com", "logos") # Path or None
|
||||
fetch_logo_info("rosaslandscaping.com", "logos", extra_urls=["https://staging.example.net/"]) # (Path or None, method)
|
||||
normalize_domain("HTTPS://www.Rosas.com/about") # "rosas.com"
|
||||
```
|
||||
|
||||
Search order, best first. The first image with a brand hue wins; an image with only white/black/gray is kept as a fallback in case nothing colorful turns up (its method ends in `-mono`).
|
||||
|
||||
| Method | Source |
|
||||
|---|---|
|
||||
| `site-logo` | The homepage (https, then http, without and with www): images with "logo" in class/id/file name/alt, images in a logo/brand container, the first image in `<header>`/`<nav>`, inline `<svg>` logos, JSON-LD `"logo"` |
|
||||
| `extra-logo` | The same on each `extra_urls` page (e.g. a staging copy of the site) |
|
||||
| `site-icon`, `extra-icon` | `apple-touch-icon`, large `<link rel=icon>`, `msapplication-TileImage` |
|
||||
| `google-favicon`, `ddg-favicon` | Google s2 favicons (sz=128), then DuckDuckGo ip3; their default globe icons (HTTP 404) are rejected |
|
||||
|
||||
A homepage `og:image` is used (as a `site-logo` candidate) only when its URL says "logo"; otherwise it is nearly always a photo.
|
||||
|
||||
Images named after something other than the domain (partner badges, "brands we carry") and images in partner/client/carousel sections rank lower, and only candidates close to the best one's score are tried. Theme stand-ins (`mock-logo`, `your-logo`, `my-company`, ...) are skipped. Parked/for-sale/expired domains and redirects to social or review sites are skipped. SVG is rasterized with `cairosvg` if it is installed, else the `rsvg-convert` binary if it is on PATH, else skipped. Blank, fully transparent or single-color images are rejected. Each download has a wall-clock cap and one search stops trying new candidates after 75 s, so a slow or stalled site can't hold up a batch. Logos are stored as PNG (at most 256 px) with a `<domain>.json` next to them holding the method; misses are cached too, so reruns make no requests (`--refresh` / `refresh=True` retries). `fetch_logo` is thread-safe, so callers can run many lookups in a thread pool.
|
||||
|
||||
## Python API
|
||||
|
||||
```python
|
||||
import generate_sprite as gs
|
||||
lib = gs.load_library("pixellab")
|
||||
info, sprite = gs.generate(lib, "Rosas Landscaping", None, "grass", logo="logos/rosas.png", write_files=False)
|
||||
```
|
||||
|
||||
With `write_files=False`, `generate` returns the info dict (plan, parts, attributes, colors) and the PIL image without writing or printing anything. `logo` may be a path or a PIL image. The part registries find their art folders (`parts_pl/`, `parts/`) relative to the working directory, so run from this folder (or `os.chdir` to it) before importing.
|
||||
|
||||
## PixelLab library
|
||||
|
||||
Each base creature has a spec in `pixellab_library/<body>.json`: the prompt and seed for its base image, plus one edit prompt per part ("add a pair of gold horns ..."). `pixellab_library.py` generates the base with PixelLab's pixen model and makes each part as an edit of that exact image. The part is the pixel difference between the edit and the base, so it lines up with the base and gets its attach point automatically. The full spec schema and conventions are in the docstring at the top of `pixellab_library.py`.
|
||||
|
||||
Reference in New Issue
Block a user