Skip to content

Commit 262a882

Browse files
simonwclaude
andcommitted
Add support for rendering images with base64 data URLs
When a user message includes an image, it now renders as an actual <img> tag with a data: URL instead of showing the raw JSON structure. Images are displayed with max-width: 100% for proper sizing. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent fcb8255 commit 262a882

File tree

4 files changed

+54
-1
lines changed

4 files changed

+54
-1
lines changed

src/claude_code_transcripts/__init__.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -651,7 +651,12 @@ def render_content_block(block):
651651
if not isinstance(block, dict):
652652
return f"<p>{html.escape(str(block))}</p>"
653653
block_type = block.get("type", "")
654-
if block_type == "thinking":
654+
if block_type == "image":
655+
source = block.get("source", {})
656+
media_type = source.get("media_type", "image/png")
657+
data = source.get("data", "")
658+
return _macros.image_block(media_type, data)
659+
elif block_type == "thinking":
655660
content_html = render_markdown_text(block.get("thinking", ""))
656661
return _macros.thinking(content_html)
657662
elif block_type == "text":

src/claude_code_transcripts/templates/macros.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,11 @@
131131
<div class="user-content">{{ content_html|safe }}</div>
132132
{%- endmacro %}
133133

134+
{# Image block with base64 data URL #}
135+
{% macro image_block(media_type, data) %}
136+
<div class="image-block"><img src="data:{{ media_type }};base64,{{ data }}" style="max-width: 100%"></div>
137+
{%- endmacro %}
138+
134139
{# Commit card (in tool results) #}
135140
{% macro commit_card(commit_hash, commit_msg, github_repo) %}
136141
{%- if github_repo -%}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
<div class="image-block"><img src="data:image/gif;base64,R0lGODlhyADIAIAAAAAAAAAAACwAAAAAyADIAAAIAgQBADs=" style="max-width: 100%"></div>

tests/test_generate_html.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,47 @@ def test_render_bash_tool(self, snapshot_html):
182182
class TestRenderContentBlock:
183183
"""Tests for render_content_block function."""
184184

185+
def test_image_block(self, snapshot_html):
186+
"""Test image block rendering with base64 data URL."""
187+
# 200x200 black GIF - minimal valid GIF with black pixels
188+
# Generated with: from PIL import Image; img = Image.new('RGB', (200, 200), (0, 0, 0)); img.save('black.gif')
189+
import base64
190+
import io
191+
192+
# Create a minimal 200x200 black GIF using raw bytes
193+
# GIF89a header + logical screen descriptor + global color table + image data
194+
gif_data = (
195+
b"GIF89a" # Header
196+
b"\xc8\x00\xc8\x00" # Width 200, Height 200
197+
b"\x80" # Global color table flag (1 color: 2^(0+1)=2 colors)
198+
b"\x00" # Background color index
199+
b"\x00" # Pixel aspect ratio
200+
b"\x00\x00\x00" # Color 0: black
201+
b"\x00\x00\x00" # Color 1: black (padding)
202+
b"," # Image separator
203+
b"\x00\x00\x00\x00" # Left, Top
204+
b"\xc8\x00\xc8\x00" # Width 200, Height 200
205+
b"\x00" # No local color table
206+
b"\x08" # LZW minimum code size
207+
b"\x02\x04\x01\x00" # Compressed data (minimal)
208+
b";" # GIF trailer
209+
)
210+
black_gif_base64 = base64.b64encode(gif_data).decode("ascii")
211+
212+
block = {
213+
"type": "image",
214+
"source": {
215+
"type": "base64",
216+
"media_type": "image/gif",
217+
"data": black_gif_base64,
218+
},
219+
}
220+
result = render_content_block(block)
221+
# The result should contain an img tag with data URL
222+
assert 'src="data:image/gif;base64,' in result
223+
assert "max-width: 100%" in result
224+
assert result == snapshot_html
225+
185226
def test_thinking_block(self, snapshot_html):
186227
"""Test thinking block rendering."""
187228
block = {

0 commit comments

Comments
 (0)