Skip to content

Add image preview for texture assets and clipboard image paste - #79

Merged
EmbarrassingMoment merged 3 commits into
dev/1.4.0from
claude/markdown-image-support
Aug 22, 2026
Merged

Add image preview for texture assets and clipboard image paste#79
EmbarrassingMoment merged 3 commits into
dev/1.4.0from
claude/markdown-image-support

Conversation

@EmbarrassingMoment

Copy link
Copy Markdown
Owner

Summary

Adds image support to the Markdown editor without loosening the preview's Content-Security-Policy (img-src data: only — no external requests): project textures referenced with [Alt](/Game/Path/To/Texture) now render in the HTML preview, and a new Paste Image command turns a clipboard image into a texture asset with the link inserted at the cursor. Verified working in the editor with the bundled sample gauge images.

Changes

Texture references in the preview (a772206)

  • New MarkdownImageUtils::EmbedTextureImages() rewrites <img> tags whose src is a UE package path (/Game/, /Engine/, /Plugins/):
    • Loads the referenced UTexture2D, compresses its source pixels to PNG via FImageUtils::CompressImage, and inlines the result as a data:image/png;base64 URI — compatible with the existing CSP, so the preview still makes no network requests
    • Unresolvable texture paths render a red dashed placeholder ([Image not found: ...], new md-missing-image CSS)
    • PNGs over 12 MB are skipped with a log warning to keep the preview data: URL bounded
    • Missing packages are pre-checked with DoesPackageExist to avoid load-failure log noise
  • Hooked into UpdatePreview() after broken-link marking and heading-anchor injection

Paste Image from clipboard (a772206)

  • New toolbar button / command (Ctrl+Shift+V):
    • Reads the Windows clipboard as CF_DIB, supporting 24/32 bpp, BI_RGB and BI_BITFIELDS, bottom-up and top-down row order; 32 bpp DIBs with a zeroed alpha channel (common for screenshots) are treated as opaque
    • Creates a UTexture2D asset under /Game/Markdown/Images/ with a unique timestamped name (BGRA8 source, sRGB, no mips for NPOT screenshots)
    • Inserts the matching [Name](/Game/Markdown/Images/Name) link at the cursor; the normal debounced preview refresh then embeds it
    • Editor notifications for the no-image / creation-failed / success cases; non-Windows platforms report "no image"

Tests & docs

  • MarkdownImageUtilsTests (categories MarkdownAsset.Images.*): non-package src passthrough (http / data:), missing-texture placeholder output, and no-op inputs
  • Editor module now depends on ImageCore
  • README (en/ja): feature bullet, linking-syntax and shortcut table rows; "Image Preview" removed from Planned Features; CHANGELOG entries
  • Sample gauge images under docs/sample-images/ (opaque power-of-two, alpha, and NPOT variants) used for verification (cf2b932)

How to test

  1. Import the PNGs from docs/sample-images/ into the Content Browser
  2. In a Markdown asset, write e.g. [HP gauge](/Game/Textures/T_GaugeBar) — the preview should show the image; a bogus path should show the red placeholder; an https:// image should stay blocked (CSP intact)
  3. Copy any image to the clipboard and press Ctrl+Shift+V in the editor — a texture asset is created under /Game/Markdown/Images/ and the link is inserted
  4. Automation: Tools > Session Frontend > Automation, filter MarkdownAsset, run all (includes the new MarkdownAsset.Images.* tests)

Notes

  • Pasted textures are created dirty; save them normally (Save All)
  • Clipboard image reading is Windows-only (the plugin currently targets Windows)

🤖 Generated with Claude Code

https://claude.ai/code/session_017MsPFParwnXFT1tjnNf27c


Generated by Claude Code

claude and others added 3 commits August 20, 2026 13:44
Implements image support for the Markdown editor without loosening the
preview's Content-Security-Policy (img-src data: only, no external
requests):

- Texture references: ![Alt](/Game/Path/To/Texture) now renders in the
  HTML preview. New MarkdownImageUtils::EmbedTextureImages() rewrites
  <img> tags whose src is a package path (/Game/, /Engine/, /Plugins/)
  by loading the UTexture2D, compressing its source pixels to PNG via
  FImageUtils::CompressImage, and inlining the result as a
  data:image/png;base64 URI. Unresolvable paths render a red dashed
  placeholder span (md-missing-image CSS); PNGs over 12 MB are skipped
  with a warning. Missing packages are pre-checked with DoesPackageExist
  to avoid load-failure log noise.
- Paste Image: new toolbar button/command (Ctrl+Shift+V, Windows-only
  CF_DIB clipboard read supporting 24/32bpp BI_RGB and BI_BITFIELDS,
  bottom-up and top-down rows, zeroed-alpha screenshots treated as
  opaque). Creates a UTexture2D asset with a unique timestamped name
  under /Game/Markdown/Images/ (TSF_BGRA8 source, sRGB, no mips) and
  inserts the matching image link at the cursor, with editor
  notifications for the no-image / failure / success cases.
- Editor module now depends on ImageCore (FImage).
- Tests: MarkdownImageUtilsTests covering non-package src passthrough
  (http/data:), missing-texture placeholder output, and no-op inputs.
- Docs: README (en/ja) feature bullet, linking-syntax and shortcut table
  rows, Image Preview removed from Planned Features; CHANGELOG entries.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017MsPFParwnXFT1tjnNf27c
Three dummy gauge textures used to verify the Markdown image preview:
an opaque 512x64 bar gauge, a 256x256 circular gauge with alpha, and a
500x60 non-power-of-two segmented gauge, plus a short README describing
how to use them.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017MsPFParwnXFT1tjnNf27c
@EmbarrassingMoment
EmbarrassingMoment merged commit 3d80b3a into dev/1.4.0 Aug 22, 2026
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.

2 participants