google/accompanist

accompanist-drawablepainter: PictureDrawable doesn't scale

theojarrus opened this issue · 4 comments

Describe the bug

PictureDrawable displayed using Compose Image and Accompanist DrawablePainter doesn't scale

To Reproduce

  1. Create PictureDrawable
val picture = Picture()
val pictureCanvas = picture.beginRecording(100, 100)
pictureCanvas.drawCircle(50f, 50f, 50f, Paint())
picture.endRecording()
val drawable = PictureDrawable(picture)
  1. Show using Compose Image and Accompanist DrawablePainter
Image(
   painter = rememberDrawablePainter(drawable),
   contentDescription = null,
   contentScale = ContentScale.FillHeight,
   modifier = Modifier.height(200.dp).border(2.dp, color = Color.Cyan)
)
  1. See the image is not scaled

Expected behavior

Image scales depending on available size and scale strategy

Screenshots

Actual Expected (fixed using canvas#scale)
Screenshot 2024-04-01 at 16 30 03 Screenshot 2024-04-01 at 16 30 22

Environment

  • Android OS version: API 34
  • Device: Emulator, Google Pixel 4
  • Accompanist version: 0.34.0

Additional context

Thoughts about fixing

In search of the reason why my image does not scale, I deepened into the source code. I found, that picture receives size in Picture#beginRecording, then getting long value from Picture#nativeBeginRecording, which also receives picture size, and saves this long value to PictureCanvas. After that, inside Picture#draw, which is called to draw picture on some canvas, Picture#nativeDraw is called. Don't know what magic happens then, but as the result picture is rendered using size recieved in Picture#beginRecording and not Drawable#setBounds. I managed to achieve the desired result using Canvas#scale, I don't know if that can cause performance problems, but at least it works. So, it can be fixed by overwriting DrawablePainter#onDraw for PictureDrawable, here's the example of working code:

// Create canvas with size bigger than picture size
Canvas(Modifier.height(200.dp).width(200.dp).border(2.dp, color = Color.Cyan)) {
   // Create simple PictureDrawable
   val picture = Picture()
   val pictureCanvas = picture.beginRecording(100, 100)
   pictureCanvas.drawCircle(50f, 50f, 50f, Paint())
   picture.endRecording()
   val drawable = PictureDrawable(picture)
   // Render PictureDrawable on canvas
   drawIntoCanvas { canvas ->
      // Set PictureDrawable bounds
      drawable.setBounds(0, 0, size.width.roundToInt(), size.height.roundToInt())
      // Scale canvas
      val scalex = size.width / drawable.intrinsicWidth
      val scaley = size.height / drawable.intrinsicHeight
      canvas.scale(scalex, scaley)
      // Draw PictureDrawable
      drawable.draw(canvas.nativeCanvas)
   }
}

Why found this bug

I'm writing library with runtime image generation, it uses Picture to render graphics and pass through app. As the result I want to show it somewhere using Compose Image, so I used accompanist-drawablepainter, but faced this issue.

@bentrengrove Check this issue please