Fix extremely oversized text in PDF export
Three defensive fixes for WKWebView.createPDF() rendering text far larger than the source HTML's actual font sizes specify: - Added a viewport meta tag and explicit -webkit-text-size-adjust: 100% — WebKit's shared engine has a text-autosizing heuristic (normally associated with mobile Safari, but can trigger in WKWebView contexts too, especially for content loaded via loadHTMLString with no base URL) that boosts font sizes for perceived readability; this disables it explicitly rather than relying on it not firing. - Explicit body font-size (was previously unset, relying on WebKit's default) and webView.pageZoom = 1.0. - Resize the webview to the actual rendered content height (via document.body.scrollHeight) before calling createPDF, instead of relying on its undocumented auto-sizing against the arbitrary initial frame — a bounds mismatch here is a known cause of blown-up/rescaled PDF output.
This commit is contained in:
@@ -56,6 +56,7 @@ enum ConversationExportService {
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>\(htmlEscape(name))</title>
|
||||
<style>\(css)</style>
|
||||
</head>
|
||||
@@ -69,9 +70,10 @@ enum ConversationExportService {
|
||||
|
||||
nonisolated private static let css = """
|
||||
:root { color-scheme: light dark; }
|
||||
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", sans-serif; \
|
||||
color: #1a1a1a; background: #ffffff; max-width: 820px; margin: 40px auto; padding: 0 24px; \
|
||||
line-height: 1.5; }
|
||||
font-size: 15px; color: #1a1a1a; background: #ffffff; max-width: 820px; margin: 40px auto; \
|
||||
padding: 0 24px; line-height: 1.5; }
|
||||
h1 { font-size: 24px; border-bottom: 1px solid #ddd; padding-bottom: 12px; }
|
||||
.message { margin: 20px 0; padding: 12px 16px; border-radius: 8px; border-left: 4px solid transparent; }
|
||||
.message.user { background: #f5f7fa; border-left-color: #4a90d9; }
|
||||
@@ -112,6 +114,7 @@ enum ConversationExportService {
|
||||
static func pdfData(name: String, messages: [Message]) async throws -> Data {
|
||||
let htmlString = html(name: name, messages: messages)
|
||||
let webView = WKWebView(frame: NSRect(x: 0, y: 0, width: 816, height: 1056))
|
||||
webView.pageZoom = 1.0
|
||||
// PDF content is baked at export time, so it can't respond to prefers-color-scheme
|
||||
// live like the HTML export does — match whatever appearance the app is in right now.
|
||||
webView.appearance = NSApp.effectiveAppearance
|
||||
@@ -119,6 +122,14 @@ enum ConversationExportService {
|
||||
webView.navigationDelegate = delegate
|
||||
try await delegate.load(htmlString, in: webView)
|
||||
|
||||
// Resize to the actual rendered content height so createPDF's capture bounds match
|
||||
// reality, rather than relying on its undocumented auto-sizing against the arbitrary
|
||||
// initial frame — a mismatch here is a common cause of blown-up/rescaled PDF output.
|
||||
if let heightValue = try? await webView.evaluateJavaScript("document.body.scrollHeight"),
|
||||
let height = (heightValue as? NSNumber)?.doubleValue, height > 0 {
|
||||
webView.frame = NSRect(x: 0, y: 0, width: webView.frame.width, height: height)
|
||||
}
|
||||
|
||||
return try await withCheckedThrowingContinuation { continuation in
|
||||
webView.createPDF(configuration: WKPDFConfiguration()) { result in
|
||||
continuation.resume(with: result)
|
||||
|
||||
Reference in New Issue
Block a user