Skip to content

Fix missing images in exported article PDFs - #1

Open
aaln wants to merge 3 commits into
koredeycode:masterfrom
aaln:fix/article-image-export
Open

Fix missing images in exported article PDFs#1
aaln wants to merge 3 commits into
koredeycode:masterfrom
aaln:fix/article-image-export

Conversation

@aaln

@aaln aaln commented May 21, 2026

Copy link
Copy Markdown

Summary

  • Fixes article PDF exports that silently dropped most images, leaving only the first visible image (or none at all) in the output.
  • Scrolls through the article before extraction so X lazy-loads all [data-testid="tweetPhoto"] nodes.
  • Resolves image URLs from both <img src> and the inner background-image div X uses for rendering.
  • Detects PNG/WebP/GIF data URLs when embedding images in jsPDF instead of hardcoding 'JPEG'.
  • Upgrades pbs.twimg.com URLs to name=large for better export quality.

Problem

When exporting long X articles, most images were missing from the generated PDF. On a real-world article with 16 body images, the exported PDF contained only 1 embedded image.

Three separate bugs contributed:

  1. Lazy loading — X only mounts tweetPhoto nodes for content that has been scrolled into view. The exporter read the DOM immediately, so images below the fold were never found (Processing Images (1/1) instead of (16/16)).

  2. Hardcoded JPEG formatrenderImageBlock always called addImage(..., 'JPEG', ...). PNG article images (common for diagrams/screenshots) failed silently in the catch block and were omitted from the PDF.

  3. No background-image fallback — X renders each image with both a background-image CSS div and an <img> tag. Video posters already had a background-image fallback, but article images only used img.src. When the <img> was not yet loaded, the exporter skipped the image even though the URL was available on the parent div.

Failed fetches made this worse: the PNG placeholder generated on fetch failure was also passed to jsPDF as 'JPEG', so even error placeholders never appeared.

Solution

  • preloadArticleImages() — Scroll the full article view, wait for each tweetPhoto to mount and load, then restore scroll position before extraction.
  • resolveTweetPhotoUrl() — Resolve the best available URL from <img> or background-image (inline + computed styles), ignoring placeholder src values.
  • normalizeTwitterImageUrl() — Request name=large from twimg for higher-quality exports.
  • getImageFormatFromDataUrl() — Pass the correct format to jsPDF for JPEG, PNG, WebP, and GIF data URLs.
  • Selector change — Query [data-testid="tweetPhoto"] containers instead of nested img tags so URL resolution is centralized.

Test plan

  • Open a long X article with many inline images (e.g. https://x.com/_avichawla/status/2049037299334472015)
  • Click Export without manually scrolling — confirm button shows Loading article images... then Processing Images (16/16)...
  • Verify exported PDF contains all body images, including PNG diagrams
  • Confirm cover/hero image outside twitterArticleRichTextView is still captured on the title page
  • Check DevTools console — no [X Articles Exporter] Failed to render image block warnings for valid images

Made with Cursor

Scroll lazy-loaded tweetPhoto nodes into view before extraction, resolve image URLs from background-image fallbacks, upgrade twimg URLs to large, and render PNG/WebP/GIF data URLs with the correct jsPDF format instead of hardcoding JPEG.

Co-authored-by: Cursor <cursoragent@cursor.com>
@vercel

vercel Bot commented May 21, 2026

Copy link
Copy Markdown

@aaln is attempting to deploy a commit to the koredeycode's projects Team on Vercel.

A member of the Team first needs to authorize it.

aaln and others added 2 commits May 21, 2026 15:39
Use crossOrigin Image+canvas to load twimg URLs (bypasses page CSP on fetch), scroll the correct overflow container for lazy-loaded photos, sanitize HTML-encoded URLs, and apply dynamic image formats on cover pages too.

Co-authored-by: Cursor <cursoragent@cursor.com>
Reduce margins, font sizes, line spacing, code block padding, image height, and block gaps so articles fit on fewer printed pages.

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant