Multimodal token economics: images and PDFs
TL;DR. Text is not the only thing that fills a window. An image is billed as tokens too, by a
rule with nothing to do with file size: for the Anthropic models the estimate is
(width * height) / 750, after the image is downscaled so its long edge fits a per-model cap. A
20 KB icon and a 20 MB photo scaled to the same pixels cost the same tokens. The lab measures the
consequences: past the long-edge cap, extra megapixels cost nothing, so uploading a full-res
original is wasted bytes; below it, tokens scale with pixels, so downscaling is a real lever; a
code screenshot costs about 3x the same code sent as text (and loses searching, diffing, and
byte-stable caching); and a PDF is billed as a per-page image plus its extracted text, so a
200-page manual is a ~637,000-token context on its own. The disciplines are the ones you already
know, pointed at pixels: select before you send, downscale to the task, and prefer text when the
information is text.
Contents
- Pixels are the currency, not bytes
- The lab: what images and PDFs actually cost
- Reading the results
- The decisions this changes
- Claude Code and multimodal context
- Further reading
- Takeaways
The book has treated the window as text because most of it is. But the moment you paste a screenshot, attach a PDF, or run a computer-use agent that sends frames, you are spending the same token budget on a different kind of input, priced by a different rule that catches people out. This short chapter closes the coverage gap: the token economics of Chapter 2 extended to the modalities, so an image in your context is a budgeted decision like every other.
Pixels are the currency, not bytes
The intuition to unlearn is that an image's cost tracks its file size. It does not. The model does not read your PNG's compression; it reads a grid of pixels, and the token estimate for the Anthropic models is:
$$\text{image_tokens} \approx \frac{\text{width}{px} \times \text{height}{px}}{750}$$
with one step before it: the image is first scaled down (preserving aspect ratio) so its long edge fits a per-model cap, historically around 1,568 pixels, raised on the high-resolution models (Opus 4.7 and later) to a few thousand tokens per image for tasks where fine detail matters. Two consequences fall out immediately, and the lab measures both: below the cap, cost is linear in pixels (downscaling saves proportionally); at or above the cap, extra resolution is free in tokens and wasted in bytes.
PDFs compose two costs. Each page is rendered to an image and has its text extracted, and you are billed for both, per page, so a document's token cost scales linearly with its length regardless of how little of it you needed.
The lab: what images and PDFs actually cost
No image files required; the lab computes from dimensions using the formula and cap above.
"""Multimodal token economics: images and PDFs are tokens too. From scratch.
Text is not the only thing that fills a window. An image is billed as tokens
too, by a rule that surprises people because it has nothing to do with file
size on disk: for the Anthropic models the estimate is
image_tokens ~= (width_px * height_px) / 750
with the image first downscaled so its LONG EDGE fits a per-model cap
(historically ~1568 px; the high-resolution models raise it, up to a few
thousand tokens per image). A 20 KB icon and a 20 MB photo scaled to the
same pixel dimensions cost the SAME number of tokens: pixels are the
currency, not bytes.
This lab makes that concrete and turns it into decisions:
1. RESOLUTION LADDER: the token cost (and dollar cost) of one image at a
range of resolutions, with the long-edge cap applied, so you can see
what downscaling before upload actually buys.
2. SCREENSHOT vs TEXT: a full-screen screenshot of a code file vs the same
code pasted as text, to show when an image is the expensive way to send
information a computer already has as characters.
3. PDF PAGES: a document billed as (per-page image) + (extracted text),
and why "just send the PDF" scales linearly with page count.
Standard library only; no image files needed (we compute from dimensions).
"""
IN_RATE = 5.00 / 1_000_000 # claude-opus-4-8 input, per token
LONG_EDGE_CAP = 1568 # conservative baseline cap; high-res models raise it
DIVISOR = 750 # (w*h)/750 token estimate
def image_tokens(w, h, cap=LONG_EDGE_CAP):
"""Downscale to fit the long-edge cap (preserving aspect), then estimate."""
long_edge = max(w, h)
if long_edge > cap:
scale = cap / long_edge
w, h = round(w * scale), round(h * scale)
return round(w * h / DIVISOR), (w, h)
def experiment_resolution_ladder():
print("=== 1. One image, five resolutions (long-edge cap 1568) ===")
print(f"{'nominal':>14}{'billed dims':>16}{'~tokens':>10}{'~$ each':>10}"
f"{'as text?':>12}")
sizes = [(640, 480), (1280, 960), (1920, 1080), (3024, 4032), (8000, 6000)]
for w, h in sizes:
tok, dims = image_tokens(w, h)
capped = "" if max(w, h) <= LONG_EDGE_CAP else " (capped)"
print(f"{f'{w}x{h}':>14}{f'{dims[0]}x{dims[1]}'+capped:>16}"
f"{tok:>10,}{tok*IN_RATE:>10.5f}{'~'+str(tok*4)+' chars':>12}")
print("""
Two lessons. First, past the long-edge cap, more megapixels cost NOTHING
extra: the 8000x6000 and 3024x4032 shots both bill the capped size, so
uploading the full-res original is wasted bytes, not wasted tokens. Second,
below the cap, tokens scale with PIXELS, so downscaling a 1920x1080 shot to
1280x720 before upload is a real, controllable saving. The rightmost column
is the reframe: that token budget could carry thousands of characters of
text instead.
""")
def experiment_screenshot_vs_text():
print("=== 2. A screenshot of code vs the same code as text ===")
# Compare EQUAL information. A 1920x1200 editor window shows about 45
# lines of code at a readable font, so that is the fair comparison: the
# screenshot's tokens against the ~45 lines it can actually display.
shot_w, shot_h = 1920, 1200
shot_tok, _ = image_tokens(shot_w, shot_h)
visible_lines = 45
code_chars = visible_lines * 60 # ~45 visible lines * ~60 chars
code_tok = code_chars // 4 # chars/4 estimate (Chapter 2)
print(f" screenshot {shot_w}x{shot_h} (shows ~{visible_lines} lines): "
f"~{shot_tok:,} tokens, ${shot_tok*IN_RATE:.5f}")
print(f" those ~{visible_lines} lines as text (~{code_chars:,} ch): "
f"~{code_tok:,} tokens, ${code_tok*IN_RATE:.5f}")
print(f" ratio: the screenshot costs ~{shot_tok/max(code_tok,1):.1f}x the text, "
f"for the SAME code\n")
print("Per line of code actually conveyed, the screenshot is several times")
print("dearer, and the text version is also SEARCHABLE, DIFF-ABLE, and")
print("CACHE-STABLE byte-for-byte while the model must OCR the image first.")
print("Send pixels only when the pixels ARE the information (a chart, a UI")
print("bug, a diagram); never to move text a machine already has as text.\n")
def experiment_pdf():
print("=== 3. A PDF is per-page image + extracted text ===")
print(f"{'pages':>7}{'~image tok':>13}{'~text tok':>12}{'~total':>10}{'~$':>9}")
per_page_img = image_tokens(1275, 1650)[0] # a letter page at ~150 DPI
per_page_txt = 500 // 4 * 4 # ~500 words of body text
per_page_txt = 500 * 13 // 10 # ~words*1.3
for pages in (1, 10, 50, 200):
img = per_page_img * pages
txt = per_page_txt * pages
tot = img + txt
print(f"{pages:>7}{img:>13,}{txt:>12,}{tot:>10,}{tot*IN_RATE:>9.3f}")
print("""
Each page is billed BOTH as a rendered image AND as its extracted text, and
it scales linearly with page count: a 200-page PDF is a five-figure token
context on its own. The selection lesson (Chapter 31) applies hardest here:
retrieve the 3 relevant pages, do not paste the manual. When you only need
the text, extract it and send text; reserve full-page images for documents
whose LAYOUT carries meaning (forms, tables, figures).
""")
if __name__ == "__main__":
experiment_resolution_ladder()
experiment_screenshot_vs_text()
experiment_pdf()
Running it:
=== 1. One image, five resolutions (long-edge cap 1568) ===
nominal billed dims ~tokens ~$ each as text?
640x480 640x480 410 0.00205 ~1640 chars
1280x960 1280x960 1,638 0.00819 ~6552 chars
1920x10801568x882 (capped) 1,844 0.00922 ~7376 chars
3024x40321176x1568 (capped) 2,459 0.01230 ~9836 chars
8000x60001568x1176 (capped) 2,459 0.01230 ~9836 chars
Two lessons. First, past the long-edge cap, more megapixels cost NOTHING
extra: the 8000x6000 and 3024x4032 shots both bill the capped size, so
uploading the full-res original is wasted bytes, not wasted tokens. Second,
below the cap, tokens scale with PIXELS, so downscaling a 1920x1080 shot to
1280x720 before upload is a real, controllable saving. The rightmost column
is the reframe: that token budget could carry thousands of characters of
text instead.
=== 2. A screenshot of code vs the same code as text ===
screenshot 1920x1200 (shows ~45 lines): ~2,049 tokens, $0.01025
those ~45 lines as text (~2,700 ch): ~675 tokens, $0.00338
ratio: the screenshot costs ~3.0x the text, for the SAME code
Per line of code actually conveyed, the screenshot is several times
dearer, and the text version is also SEARCHABLE, DIFF-ABLE, and
CACHE-STABLE byte-for-byte while the model must OCR the image first.
Send pixels only when the pixels ARE the information (a chart, a UI
bug, a diagram); never to move text a machine already has as text.
=== 3. A PDF is per-page image + extracted text ===
pages ~image tok ~text tok ~total ~$
1 2,534 650 3,184 0.016
10 25,340 6,500 31,840 0.159
50 126,700 32,500 159,200 0.796
200 506,800 130,000 636,800 3.184
Reading the results
- The cap makes full-resolution uploads pointless. The 8000×6000 and 3024×4032 shots bill the same 2,459 tokens, because both are scaled down to the same capped dimensions before counting. Uploading the 48-megapixel original costs you upload bandwidth and zero extra model capability; downscale to the cap yourself and you have lost nothing.
- Below the cap, downscaling is a real, linear lever. The 1280×960 image costs 1,638 tokens; halve each dimension and you quarter the tokens. For any image whose detail the task does not need (a UI layout, a rough diagram), pre-downscaling is the multimodal version of Chapter 4's "ask for less".
- A code screenshot is 3x the same code as text, and worse in every non-token way. The screenshot bills 2,049 tokens to convey ~45 lines that cost 675 tokens as text, and the text is searchable, diff-able, and cache-stable byte-for-byte while the image must be OCR'd first. Sending a machine text as pixels is the clearest waste in this chapter.
- PDFs scale linearly and get large fast. 200 pages is ~637,000 tokens, more than the usable context of Chapter 33 before the question is even asked. The double billing (image + text per page) means "just attach the PDF" is rarely the right move; Chapter 31's selection lesson applies hardest to documents.
The decisions this changes
- Select pages, do not paste manuals. Everything in Chapter 31 applies to PDFs, amplified by the per-page double cost. Retrieve the relevant pages; index the document once and pull the three that matter.
- Extract text when only text is needed. If a PDF or screenshot carries information that is fundamentally text (a code file, a log, a config), extract it and send text: cheaper, and it restores search, diff, and caching. Reserve full-page images for documents whose layout carries meaning, forms, tables, figures, diagrams, where the pixels are the information.
- Downscale to the task, not to the cap and not above it. Above the cap is free but wasteful in bytes; well below the cap is where you should sit for detail-insensitive images. Pick the smallest resolution at which the task still succeeds, and confirm with the context eval approach if accuracy is on the line.
- Budget frames in computer-use and vision loops. An agent that screenshots every step spends thousands of tokens per turn on images that then re-send on every later turn like any other context (Chapter 17). The high-resolution models let you trade detail for tokens deliberately; 1080p frames are a common balance, lower for cost-sensitive runs.
Claude Code and multimodal context
Claude Code reads images and PDFs through the same Read tool it uses for text, so they land in
the same window and the same usage accounting (Chapter 23):
- A pasted or Read image shows up in Messages and is priced by the pixel rule above; the
/contextpanel (Chapter 21) and the session audit count its tokens like any other content, so the differential-/contextmethod prices an attached diagram exactly as it prices an MCP server. - Prefer telling the agent where the text is over screenshotting it. "Read
src/app.pylines 40 to 90" costs a fraction of a screenshot of the same lines and gives the agent something it can edit, not just describe. The screenshot is for the failing UI, the rendered chart, the diagram, the thing that has no text form. - PDFs are a retrieval decision in the agent too. If you drop a large PDF into a session, its per-page tokens sit in the window for the rest of the session; when you only need a section, extract or point the agent at the pages, the same discipline as bounding a code read in Chapter 29.
Remember. An image is not free context because it is "just one attachment". It is hundreds to thousands of tokens, priced by pixels not bytes, re-sent every turn like all context, and often carrying information the model would use better as text. Ask the same question you ask of any token: does the task need this in the window, at this resolution, in this modality?
Further reading
- Anthropic vision and PDF documentation (
platform.claude.com/docs): the authoritative per-model image token formula, the long-edge caps, the high-resolution limits, and PDF page/size limits. These move; the lab's constants are the conservative baseline, so re-check the current numbers before a budget. count_tokenswith an image or PDF block (Chapter 2, Chapter 30): the exact count for a specific asset, the same pre-flight instrument used for text.- Chapter 31 (select before you send) and Chapter 33 (does the model use it), both of which apply to pixels as much as to text.
Takeaways
- Images are billed as tokens by pixels, not bytes:
(w * h) / 750after downscaling to a per-model long-edge cap. File size is irrelevant; a huge photo and a small one at equal pixels cost equally. - Past the cap, more resolution is free (so full-res uploads waste bytes); below it, cost is linear in pixels (so downscaling to the task is a real lever).
- A code screenshot costs ~3x the same code as text and forfeits search, diff, and byte-stable caching; send pixels only when the pixels are the information.
- PDFs bill per page as image plus extracted text and scale linearly: 200 pages is ~637k tokens. Select the pages; extract text when layout does not matter.
- In Claude Code, images and PDFs land in Messages and are audited like any content; prefer bounded text reads over screenshots, and treat a dropped-in PDF as a retrieval decision.
👉 That completes the input side: the window can be too big, underused, hostile, or filled with the wrong modality, and you now have a measured lever for each. The next part makes all of them concrete in one production tool. Continue to Inside one Claude Code session.