Probe remote image dimensions (width × height) from just a URL.
Image formats carry their dimensions in the file header, so Dims
fetches only the first ~128 KB via an HTTP Range request, parses
the JPEG/PNG/WebP/GIF header, and discards the bytes — milliseconds
and a few KB per image instead of full downloads.
Dims.probe("https://cdn.example.com/page1.jpg")
#=> %{width: 800, height: 8000}
Dims.probe_all(urls)
#=> [%{url: ..., width: 800, height: 1200}, ...]Built for the real world of images you don't host:
- Batch probing —
probe_all/2runs a bounded-concurrency parallel sweep, preserving input order. - Median backfill — a probe that fails or times out gets the median dimensions of its successful siblings instead of a constant fallback; image sets (chapter pages, galleries) are near-uniform, so the estimate is close and never wrecks layouts built from relative sizes.
- Sampling —
probe_sampled/2probes ~20 evenly-distributed URLs of a huge list and median-fills the rest (accuracy within a percent or two for uniform sets, ~25× less traffic).probe_auto/2picks full vs sampled by list length. - Caching — results cache in ETS keyed by URL (30-day TTL by default); a URL's bytes don't change, so its dimensions don't either.
Options
All functions accept:
:headers— extra request headers, e.g. arefererfor CDNs that check it:headers: [{"referer", "https://source.example/"}]:headers_fun—(url -> headers)when headers depend on the URL (per-host referers); merged over:headers:probe_bytes— Range size to request (default131_071):receive_timeout— per-request timeout ms (default8_000):cache—falseto bypass the cache (defaulttrue):cache_ttl— cache entry TTL ms (default 30 days)
Batch functions additionally accept:
:max_concurrency— parallel probes (default8):sample_size— forprobe_sampled/2(default20):full_threshold— forprobe_auto/2, list length at or below which a full probe runs (default80)
URL fragments are stripped before fetching and caching (they never reach the server anyway).
Summary
Functions
Backfill nil dimensions with the median width/height of the
entries that did probe. Exposed for callers assembling their own
probe results; leaves the list untouched when nothing probed.
Probe a single URL. Returns %{width:, height:} or nil when the
fetch fails or the format is unrecognized.
Probe every URL in parallel. Returns [%{url:, width:, height:}]
preserving input order; failed probes carry the median dimensions of
the successful ones (or nil dims when nothing probed).
Full probe for lists up to :full_threshold (default 80), sampled
beyond — the right default when exactness matters for normal-sized
sets (per-image aspect decisions) but huge sets are near-uniform.
Probe up to :sample_size evenly-distributed URLs and median-fill
the rest. Falls through to probe_all/2 for small lists.
Types
@type dims() :: %{width: pos_integer(), height: pos_integer()}
Functions
Backfill nil dimensions with the median width/height of the
entries that did probe. Exposed for callers assembling their own
probe results; leaves the list untouched when nothing probed.
Probe a single URL. Returns %{width:, height:} or nil when the
fetch fails or the format is unrecognized.
Probe every URL in parallel. Returns [%{url:, width:, height:}]
preserving input order; failed probes carry the median dimensions of
the successful ones (or nil dims when nothing probed).
Full probe for lists up to :full_threshold (default 80), sampled
beyond — the right default when exactness matters for normal-sized
sets (per-image aspect decisions) but huge sets are near-uniform.
Probe up to :sample_size evenly-distributed URLs and median-fill
the rest. Falls through to probe_all/2 for small lists.