https://kotlinlang.org logo
#compose-desktop
Title
# compose-desktop
m

Michael Paus

09/22/2023, 3:16 PM
I am experimenting with SkikoGraphics2D at the moment together with Apache PDFBox to create a PDF viewer for JetBrains Compose Desktop. This works astonishingly well. See attached screen shot. (This is vector graphics rendered directly into a Skia canvas and not an embedded image inside the PDF!) I noticed however a sometimes strange behaviour of the rendering for which I do not really have an explanation and where I could use some help. More details inside the thread.
🔥 5
👀 3
❤️ 1
This is the core PDF viewer code:
Copy code
@Stable
class PDFContext(pdf: String) {
    val pdfFile = File(pdf)
    val document = Loader.loadPDF(pdfFile)
    val pdfRenderer = PDFRenderer(document)
}

@Composable
fun DocumentView(pdfContext: PDFContext, pageIndex: Int, modifier: Modifier = Modifier) {
    Box(modifier.fillMaxSize().drawWithCache {
        onDrawBehind {
            drawIntoCanvas {
                val w = size.width
                val h = size.height
                clipRect(0f, 0f, w, h){
                    with (it.nativeCanvas) {
                        SkikoGraphics2D(this).also { g2 ->
                            g2.background = java.awt.Color.LIGHT_GRAY
                            g2.clearRect(0, 0, w.toInt(), h.toInt())
                            with(pdfContext) {
                                val page = document.getPage(pageIndex)
                                val cb = page.cropBox
                                val scale = min(w/cb.width, h/cb.height)
                                val sx = cb.lowerLeftX*scale
                                val sy = cb.lowerLeftY*scale
                                val sw = cb.width*scale
                                val sh = cb.height*scale
                                if (sw <= w) g2.translate(0.5 * (w - sw), 0.0) // center horizontally on canvas.
                                if (sh <= h) g2.translate(0.0, 0.5 * (h - sh)) // center vertically on canvas.
                                g2.background = java.awt.Color.WHITE
                                g2.clearRect(sx.toInt(), sy.toInt(), sw.toInt(), sh.toInt())
                                pdfRenderer.renderPageToGraphics(pageIndex, g2, scale)
                                log.debug { "pdfRenderer.renderPageToGraphics" }
                            }
                        }
                    }
                }
            }
        }
    })
}
At the moment I see two main problems: 1. When I just move the mouse (no buttons pressed) over the buttons at the top of the app or over the document area then I can see that the graphics seems to be constantly re-rendered. I thought that exactly this should not happen when I use the drawWithCache modifier and even without it I would not expect that. 2. During the procedure above I see lots of strange rendering artefakts popping up which mostly disappear as soon as I leave the mouse untouched but not always. Somehow it looks like there might be concurrency problems but can that be with this setup? I have to admit that I am a bit lost here and don’t know where to look. Is there any documentation on how one should deal with heavy rendering jobs like this in compose to get the best performance?
k

Kirill Grouchnikov

09/22/2023, 3:27 PM
I wonder if there’s any weird interaction between Swing’s UI thread and however Compose is configured to draw on canvas on desktop.
m

Michael Paus

09/22/2023, 4:02 PM
At least all the logging happens on
AWT-EventQueue-0
.
k

Kirill Grouchnikov

09/22/2023, 4:21 PM
Is
PDFRenderer
doing synchronous rendering?
a

Albert Chang

09/22/2023, 4:22 PM
I think you might be misunderstanding
Modifier.drawWithCache
. What it caches is not the drawing result but the objects created inside it. See here for details. If you want to prevent redraw, try adding
Modifier.graphicsLayer()
to the box (before the drawing modifier).
m

Michael Paus

09/22/2023, 5:31 PM
@Kirill Grouchnikov I think so because this is for AWT and it would be strange if this is not rendering synchronously. @Albert Chang You are right. Although I actually did read this chapter in the documentation I have completely misunderstood it. Adding graphicsLayer() does make a big difference concerning the redraws which now only happen when they are really necessary. But I still see these drawing glitches. The difference now is that they are frozen in the cached image and don’t disappear so easily anymore. I have to cause a redraw several times to get a correct image. See the following examples.
m

mohamed rejeb

09/23/2023, 7:36 AM
Can you provide a minimal reproducible with the pdf file that you are using so I can check this issue
m

Michael Paus

09/23/2023, 8:55 AM
@mohamed rejeb This should contain all you need.
thank you color 1
5 Views