Repository navigation
KitePDF 0.12.0
KitePDF 0.12.0 now checks the digital signatures of a signed PDF, and decodes big scans at the size they are drawn, so a 600 dpi page on a phone no longer needs hundreds of megabytes. EPUB books gain MathML, flex, grid and multi-column layout, every format gets a reading order for screen readers, and the release closes more than a hundred issues (127 issues in total). Two changes break the API (they are marked 🔴 below). The biggest thing about this update is that it brings major performance enhancements to the Compose renderer, and fixes a plethora of issues most of which caused crashes.
Usage
// Every format: PDF, EPUB, CBZ, SVG, XPS and OpenXPS
implementation("io.github.yuroyami:kitepdf:0.12.0")
// Or one format only
implementation("io.github.yuroyami:kitepdf-pdf:0.12.0")
implementation("io.github.yuroyami:kitepdf-epub:0.12.0")
implementation("io.github.yuroyami:kitepdf-cbz:0.12.0")
implementation("io.github.yuroyami:kitepdf-svg:0.12.0")
implementation("io.github.yuroyami:kitepdf-xps:0.12.0")
// Optional (but you may probably need one of these depending on your use case)
implementation("io.github.yuroyami:kitepdf-compose-viewer:0.12.0") // KiteDocView for Compose Multiplatform (renderer)
implementation("io.github.yuroyami:kitepdf-native-renderer:0.12.0") // page-to-image on the platform canvas (headless+renderer)
implementation("io.github.yuroyami:kitepdf-skia-renderer:0.12.0") // page-to-image on Skia multiplatform (headless+renderer)
implementation("io.github.yuroyami:kitepdf-javascript:0.12.0") // runs the JavaScript inside PDFs (pulls KiteJS artifact)
implementation("io.github.yuroyami:kitepdf-net:0.12.0") // allows KitePDF to remotely load documents from a URLkitepdf-core arrives with every handler. Do not add it yourself.
Changelog
🔴 Breaking changes
| Change | What to do |
|---|---|
#449: KiteLinkAction.Uri is gone, and KiteLinkAction has the new kinds Epub and Plain |
Read link.uri, or add Epub and Plain to a when without else |
#449: KiteDocView no longer takes onEpubReferenceTap |
Check link.kind in onLinkTap |
2fe3273: kitepdf-core no longer passes its image engine, now KiteImageCodec, on to apps |
If you call the engine directly, add io.github.yuroyami:kiteimagecodec:0.2.0, import io.github.yuroyami.kiteimagecodec, and call KiteImageCodec.decode |
Two changes still compile. onLinkTap now also receives links inside the document before the viewer follows them, so a callback that returns true for every link stops that navigation (#449). KiteSelectionMenu now sits next to the selection by default. Pass an alignment to pin it as before (#408).
Everything since 0.11.0
| Area | Type | Change |
|---|---|---|
| Viewer (60) | New Features | #410: Flung the pan of a zoomed page, and turned the page past its edge |
| #411: Zoomed with Ctrl and the wheel, paged and zoomed with the keyboard, and selected text with a mouse drag | ||
| #433: Brought a linked place to the top at any zoom and layout, turned the page for named links, and ran script links | ||
| #444: Let the app see an internal EPUB link before the viewer follows it, to show a note in place (reported by @ksokolovskiy) | ||
| API Changes | #30: Added pageOverlay, pageRectToViewport and displayRectToViewport, to place a composable over a rectangle on a page | |
#408: Placed the selection menu next to the selection, and added selectionBounds for hosts that place their own | ||
| #429: Moved a state's suspend calls onto the viewer's thread, so an app can navigate from any thread | ||
#431: Let KitePageRasterizer.rasterize take a form state, to export a filled form | ||
#432: Added hitTestDisplay, which gives a hit in display space for every format | ||
🔴 #449: Gave onLinkTap every link in every format before the viewer acts, with uri, target, kind, pageIndex and rect on each link | ||
acbe57d: Passed Compose runtime, foundation and ui on to apps, since KiteDocView's API takes and returns their types | ||
| Performance | #370: Rendered two pages at once, the visible one first, with cancellation for every format | |
| #372: Gave a Vectorized page its own layer, so an overlay change no longer redraws it | ||
| #373: Moved the layer on a zoom or pan frame, with no recomposition | ||
| #374: Recomposed the page widgets only when the reader crosses a page | ||
| #375: Drew the part on screen in tiles past the bitmap cap, so deep zoom stays sharp | ||
| #376: Rasterized a settled zoom only for the pages in view | ||
| #380: Built a page's text off the main thread before a long press selects it | ||
| #390: Rasterized a page once a resize holds, not on every frame | ||
| #391: Cached thumbnails, and kept one EPUB outline per state | ||
| #393: Put decoded pixels into a bitmap once on Skia targets | ||
| #394: Kept a themed page's raster when only the page background changes | ||
| #395: Freed the page cache when its budget is zero or the view is Vectorized | ||
| a0ebaa7: Rendered a page drawn in a host font once, not twice | ||
| e75ca6a: Let a soft mask's canvas share the image bitmaps of its page | ||
| e8a5c53: Converted each glyph outline to a path once per draw | ||
| Fixes | #332: Laid out very tall and very wide pages in the Continuous layout | |
#338: Ignored zoom input that is not finite, and checked doubleTapZoom and offscreenPages | ||
| #342: Kept the reader on their page when a chapter lands above them in the Continuous layout | ||
| #343: Ran the Paged correction for a long chapter that lands, in an app as in tests | ||
| #344: Kept the jump to a bookmark going when the reader drags while a book opens | ||
| #345: Made the viewer state the only saved reading position | ||
#346: Took the position of a new KiteDocViewState under the same KiteDocView | ||
| #348: Landed on the last page of a loading chapter when the reader pages back onto it | ||
| #350: Kept a selection drag going while a chapter lands | ||
| #352: Kept the position when Continuous switches between vertical and horizontal | ||
| #353: Letterboxed a chapter placeholder in a pager like a page | ||
| #392: Confirmed that a Vectorized page and a pool raster of one document draw safely at once | ||
| #397: Let the reader reach both ends of a zoomed Continuous strip | ||
#398: Made swiping, panning and the opening zoom work with any minZoom | ||
| #399: Kept a zoomed page in view when the viewer changes size | ||
| #400: Bounded the pan by the page, so a zoomed page no longer slides into empty margins | ||
| #401: Placed spread pages from the left in a right-to-left app, so a tap finds the right page | ||
| #402: Updated the page indicator on a page step inside one spread | ||
| #403: Kept a set zoom when a Paged or Spread layout appears | ||
| #404: Applied a changed pan setting to the next two-finger pan | ||
| #405: Let a finger or a zoom request stop a running zoom animation | ||
| #406: Placed selection handles on the ends of the text in every writing direction | ||
| #407: Dropped a selection that a navigation leaves behind, so scrolling unlocks | ||
| #409: Gave a chapter placeholder in a pager the taps, double taps and pinches of a page | ||
| #417: Drew a Vectorized page only inside its slot | ||
| #418: Drew a Vectorized page again at the settled zoom, with sharp images and thin hairlines | ||
| #419: Painted placeholders, chapter gaps, thumbnails and form widgets in the reader theme | ||
| #420: Kept the cached pixels of two reader themes apart | ||
| #421: Rendered a page again when the font environment changes | ||
| #422: Drew a page at every accepted raster quality | ||
| #430: Kept a page's last bitmap when its raster fails, and let the app see and retry the failure | ||
#435: Kept every argument in the IDE quick fixes of the deprecated PdfView and EpubView | ||
| ed0f7ab: Reported the reader's page exactly between a chapter landing and the next measure | ||
| Docs | #436: Made the viewer's KDoc say what the code does | |
| PDF (11) | New Features | #203: Validated digital signatures: CMS, PKCS #1, RSA-PSS and ECDSA, with the certificate chain, time stamps and a check for changes after signing |
| #204: Drew rich-text form fields, and wrapped the text of multi-line fields | ||
| #447: Reported whether a signature's certificate was revoked, from the CRL and OCSP data in the file or given by the app | ||
| #448: Judged each change made after a signature against the permissions of a certification signature and a field lock | ||
| Performance | #383: Parsed each font once per document, within a memory budget, instead of once per page render | |
| #387: Built the page list of a large PDF off the main thread | ||
| Fixes | #329: Opened a PDF whose page count is wrong as the pages it really holds | |
| #330: Opened a PDF page whose page box cannot be read, instead of crashing | ||
| #333: Kept the app running when a page or the form layer fails to draw | ||
| #334: Kept the app running after a tap or a long press on a malformed page | ||
| #441: Read and drew a form whose entries point at missing objects | ||
| EPUB (31) | New Features | #27: Followed the manifest's fallback chain for a resource the engine cannot render, and showed one branch of an epub:switch |
| #28: Painted opacity, overflow, visibility, 2D transforms, rounded corners, box shadows, background images and linear gradients in fixed-layout books | ||
#29: Gave audio and video elements a box on the page, and listed them in EpubPage.media | ||
| #32: Rendered presentation MathML: fractions, scripts, limits, radicals, tables and stretching fences | ||
#33: Laid out display: flex, so flex pages no longer stack vertically | ||
| #34: Laid out multi-column blocks in columns | ||
#35: Laid out display: grid | ||
| #37: Read the spread, orientation and layout rendition properties, and paired spreads as the book declares | ||
| #39: Carried pronunciation hints into the reading order, for speech | ||
| #40: Flagged chapters that hold scripts, and gave embedded documents a box | ||
| f29e16d: Read media overlays, and found the page that holds a text fragment | ||
| Performance | #351: Opened one page of a book in KiteDocView(document, page) without laying out the whole book | |
| #377: Laid out a chapter that the memory budget dropped off the UI thread | ||
| #378: Kept one chapter loader running while the reader scrolls past unloaded chapters | ||
| #379: Took a bookmark or a page step on a chapter placeholder without a layout on the caller's thread | ||
| #388: Let iOS and macOS threads sleep while a chapter lays out, instead of spinning | ||
| 06781d4: Laid out far chapters in a browser only while the reader rests | ||
| Fixes | #331: Kept the app running when a chapter fails to lay out | |
#336: Let SinglePage show any valid page of a book that is still laying out | ||
| #337: Laid out a book in spreads behind the reader, off the UI thread, with no blank spreads | ||
| #341: Showed a chapter that was laid out outside the viewer's loader, instead of a blank placeholder | ||
| #347: Kept the reader in an empty chapter, instead of jumping to the last page of the book | ||
| #349: Found a page bookmark's page before the book is laid out | ||
| #396: Counted chapters that hold only an SVG toward the layout memory budget | ||
| #423: Honoured page breaks on containers, tables and images | ||
#424: Gave an image with display: none no box | ||
| #425: Resolved an inline SVG image's own links from its own folder | ||
| #426: Scaled a tall inline image to the page, so it is no longer cut off | ||
| #434: Restored a bookmark on the right page after the font family changes | ||
| #438: Copied a book's text without the layout's line breaks and hyphens | ||
| #442: Kept a page-tall image at the start of a paragraph on its page | ||
| Forms and scripts (16) | Performance | #368: Pumped script timers only while one waits, not on every frame |
| Fixes | #355: Kept each script engine on one thread of its own | |
| #356: Kept the caret in a tapped text field, so the reader can type | ||
| #357: Repainted the form when a check box, radio button or push button is tapped | ||
| #358: Drew live form values in every layout and render mode | ||
| #359: Acted on the widget under the finger, so a tap edits the right field | ||
| #360: Let a tap pass through a widget that a script hid | ||
| #361: Ran a push button's own action, so Reset, Submit and Print work | ||
| #362: Put the hidden form input inside the viewer, over its widget, with multi-line editing | ||
| #363: Ran keystroke scripts in typing order, so a refused key no longer drops later typing | ||
| #364: Guarded the form state that scripts write from their own thread | ||
| #365: Called a document's open scripts once, and kept the app running when a script fails | ||
| #366: Ran each page's open and close scripts as the reader lands on it | ||
| #367: Timed script timers on the runner's clock, so none fires at once | ||
| #439: Gave the default values back on a form reset | ||
| #440: Let a tap clear a selected radio button in a group that allows no selection | ||
| Images (1) | Performance | #381: Decoded a PDF's JPEG and JPEG 2000 images at the size they draw, and converted large images a band of rows at a time |
| Accessibility (3) | New Features | #208: Gave every page a reading order for a screen reader, from a tagged PDF's structure |
| 25506fe: Named pages, page buttons, thumbnails and colours for a screen reader | ||
| f4539f9: Gave a screen reader the text, links and form fields of each page | ||
| Rendering (8) | Performance | #384: Opened the two layers of a soft mask over the mask's box only |
| Fixes | #335: Applied each clip once on the Compose canvas, and capped the clips a page can open | |
| #412: Painted Multiply on Android 7 to 9 | ||
| #413: Drew an off-centre radial gradient on Android 7 to 11 | ||
| #414: Applied a soft mask's whole transfer table on Skia targets | ||
| #415: Stroked and clipped system-font text with real glyph outlines | ||
| #416: Kept shear and reflection in system-font text | ||
| #445: Applied a soft mask's whole transfer table on Android | ||
| XPS and SVG (2) | New Features | 8a4eea0: Drew SVG pattern paint servers and masks |
| Performance | #385: Read an XPS page's size from its start tag, and kept parsed pages under a budget | |
| CBZ (1) | Performance | #386: Read a comic page's size from its image header, and decoded each scan once |
| Tests and CI (4) | Tests | #212: Built a consumer project against the published artifacts in CI |
| #213: Put the timing-sensitive suites back into the gate | ||
| #328: Made scene tests fail on a timeout, and run effects in the order an app does | ||
| #443: Brought viewer effects back to the composition thread after a wait, so a scene test no longer fails now and then |
Dependencies
| Version | |
|---|---|
| Kotlin | 2.4.20 |
| Compose Multiplatform | 1.12.1 (kitepdf-compose-viewer, passed on to apps) |
| Android Gradle Plugin | 9.4.1 (built with) |
| Gradle | 9.8.0 (built with) |
| JDK | 21 |
| Android SDK | compileSdk 37, minSdk 21 (kitepdf-compose-viewer 24, kitepdf-native-renderer 29) |
| KiteImageCodec | 0.2.0 (kitepdf-core, kept inside it; it was KiteImage 0.1.0) |
| KiteJS | 0.2.0 (kitepdf-javascript) |
| Ktor | 3.6.0 (kitepdf-net) |
| Skiko | 0.150.1 (kitepdf-skia-renderer, kitepdf-compose-viewer) |
Targets: Android, JVM, iOS, tvOS, watchOS, macOS, Linux, Windows, Android Native, JS and Wasm. kitepdf-javascript has no tvOS, watchOS, Android Native or wasmWasi build. The viewer and the renderers build for fewer targets. The platforms page lists them.
Full changelog: v0.11.0...v0.12.0