Draft
Conversation
Migrate compose2pdf from kotlin("jvm") to kotlin("multiplatform") with
JVM, Android, and iOS targets. Portable types (PdfPageConfig, PdfMargins,
PdfLink, etc.) move to commonMain; JVM-specific rendering stays in jvmMain.
Android implementation uses native android.graphics.pdf.PdfDocument with
off-screen Compose rendering via VirtualDisplay + Presentation, producing
vector PDF output. iOS target compiles with stub renderer.
Add shared test-fixtures KMP module with 28 composable fidelity fixtures
(material3) used by both JVM fidelity tests and Android instrumented tests.
Android tests run on Gradle Managed Devices (ATD API 30) with PDF extraction
via TestStorage. Fidelity report now includes cross-platform Android column
with diff images and metrics.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Create intermediate skikoMain source set for code shared between JVM and iOS (both use Skiko). Move ComposeToSvg.kt there with expect/actual for the SVG byte output (JVM uses ByteArrayOutputStream, iOS uses Skia's OutputWStream.toData()). Validates that CanvasLayersComposeScene and SVGCanvas compile on iOS — clearing the critical blocker for iOS PDF. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add complete SVG-to-PDF conversion pipeline for iOS using native APIs: - SvgDocument.kt: NSXMLParser-based SVG DOM parser - CoreGraphicsPdfConverter.kt: Renders SVG elements to CGPDFContext (paths, shapes, text via Core Text, images, transforms, clipping, opacity, link annotations) - CoreGraphicsPathParser.kt: SVG path d-attribute parser (all commands) - IosPdfRenderer.kt: Orchestrator connecting ComposeToSvg (skikoMain) to Core Graphics converter, with single-page and auto-pagination modes Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The skikoMain intermediate source set broke the iOS test→main dependency chain (tests couldn't see iosMain production code). Replace with duplicated ComposeToSvg in both jvmMain and iosMain — the code sharing was causing more problems than it solved. iOS ComposeToSvg uses OutputWStream.toData() instead of ByteArrayOutputStream. CoreGraphicsPdfConverter has known compile errors (K/N API naming) to be fixed in the next iteration. Also fixes Math.PI → kotlin.math.PI in shared test fixtures. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix OutputWStream: use DynamicMemoryWStream on iOS (no-arg constructor) - Fix CG enum constants: CGLineCap.kCGLineCapButt, CGLineJoin.*, CGPathDrawingMode.* - Fix CGRect: use CGRectMake() instead of struct allocation - Fix String→CFStringRef casts: use CFBridgingRetain(text as NSString) - Remove iosTest duplicate, use iosSimulatorArm64Test directly All 2 iOS tests pass (basicRender + 28 shared fixtures) on simulator. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
iOS simulator tests now save generated PDFs to /tmp/compose2pdf-ios-test-output/, which the fidelity report picks up and includes as an "iOS" column alongside JVM Vector, JVM Raster, and Android. The report now shows 4 rendering modes per fixture with diff images and metrics, enabling visual comparison across all 3 platforms. Known: iOS text rendering shows per-glyph spacing from SVG x-position attributes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Per-character CTLine rendering introduced bearing offsets that caused visible letter spacing artifacts. CTFontDrawGlyphs places glyphs directly at SVG coordinates without CTLine's text layout adjustments. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add XXE/DTD prevention to DocumentBuilderFactory (defense-in-depth) - Update CI workflows: add Android SDK setup, iOS simulator tests, switch publish jobs to macOS for full KMP target support - Rewrite all docs to reflect Android and iOS support: README, getting started, compatibility, API reference, architecture, changelog - Rewrite CLAUDE.md for multiplatform (all source sets, pipelines, gotchas) - Add 2.0.0 changelog entry with platform feature matrix Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
android.graphics.pdf.PdfDocument(zero external deps, suspend API, always vector)CGPDFContext) with Skia SVGCanvas intermediaryDocumentBuilderFactory(defense-in-depth)Platform feature matrix
Test plan
./gradlew :compose2pdf:compileKotlinJvm— JVM compiles./gradlew :compose2pdf:jvmTest— JVM unit tests pass./gradlew :fidelity-test:test— Fidelity tests pass (verified locally)./gradlew :compose2pdf:iosSimulatorArm64Test— iOS simulator tests pass (macOS)./gradlew :compose2pdf:publishToMavenLocal— Verify artifact structure in~/.m2cd docs && bundle exec jekyll serve— Docs site renders correctly🤖 Generated with Claude Code