Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

accompanist-drawablepainter: PictureDrawable doesn't scale #1766

Closed
theojarrus opened this issue Apr 1, 2024 · 4 comments
Closed

accompanist-drawablepainter: PictureDrawable doesn't scale #1766

theojarrus opened this issue Apr 1, 2024 · 4 comments

Comments

@theojarrus
Copy link

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.

@theojarrus
Copy link
Author

theojarrus commented Apr 16, 2024

@bentrengrove Check this issue please

@PrimoDev23
Copy link

@theojarrus I created a PR for this #1771
As soon as the review is done, it can be merged

@bentrengrove
Copy link
Collaborator

I mentioned this in the PR, but it is up to the drawable implementation how it scales, not the painter. So in this example you shouldn't be using fixed coords for defining your picture, you should be using the sizing information.

Something like:

val halfWidth = width/2f
val pictureCanvas = picture.beginRecording(width, height)
pictureCanvas.drawCircle(halfWidth, halfWidth, halfWidth, Paint())

@theojarrus
Copy link
Author

theojarrus commented May 23, 2024

@bentrengrove Understood your point, but I'm using PictureDrawable to store and share picture data through code. In this case, it is impossible to know exact size of final view. And also it can be changed, for example, by switching landscape orientation, so, in my opinion, the image size should be also changed, like ImageView does

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants