coil-kt / coil

Image loading for Android and Compose Multiplatform.
https://coil-kt.github.io/coil/
Apache License 2.0
10.63k stars 647 forks source link

Inconsistencies in SVG Image Sizing and Blurriness When Loaded from URLs Using Coil in Jetpack Compose #2048

Open NatashaIJ opened 7 months ago

NatashaIJ commented 7 months ago

Description: In a Jetpack Compose project utilizing Coil (version 2.4.0), SVG images loaded from URLs fail to retain their intrinsic dimensions, scaling up to the maximum size set with .sizeIn(maxWidth = 16.dp, maxHeight = 16.dp). This issue does not occur with SVGs loaded from drawable resources, which correctly maintain their intrinsic sizes. To ensure accurate sizing, Size.ORIGINAL is utilized in the image request, which leads to another problem: the images become blurry due to scaling from pixel-based sizes to dp in the UI.

Steps to Reproduce:

  1. Initiate a Jetpack Compose project with Coil for image loading.
  2. Load an SVG from a URL, which has smaller intrinsic dimensions than the maximum size, using .sizeIn(maxWidth = 16.dp, maxHeight = 16.dp) in the Image modifier
  3. Observe the SVG incorrectly scaling to the maximum set size.
  4. Apply Size.ORIGINAL to retrieve correct intrinsic dimensions for sizing in the Image modifier.
  5. Notice the correct sizing but with resultant blurriness.

Expected Behavior:

  1. SVG images from URLs should reflect their intrinsic dimensions without scaling to a set maximum, similar to drawable resource behavior.
  2. When employing Size.ORIGINAL, the images should remain clear, without the blurriness introduced by upscaling for the UI's dp dimensions.

Additional Context: A custom SvgDecoder was introduced to tackle the blurriness, altering the getDstSize function to translate SVG dimensions into dp for UI consistency. While this resolved the blurriness, modifying library components is risky, potentially leading to future compatibility issues. Ideally, default support for this scenario in the SVGDecoder would avoid the need for custom implementations.

Version: Coil version: 2.4.0 The problem has been noted on various API levels and Android devices.

Related Bug and Discussions:

  1. Issue #566 with a similar problem and discussion
  2. A related discussion on handling SVGs with Coil

Note: In my view, such intrinsic size handling should be natively supported by Coil's SVGDecoder to avoid the need for custom implementations that may introduce future maintenance challenges.

colinrtwhite commented 7 months ago

The svg decoder should already take into account the intrinsic size. Can you try setting useViewBoundsAsIntrinsicSize = false and see if that fixes your issue? Does it work properly if you use AsyncImage instead of rememberAsyncImagePainter?

Can you include sample code that reproduces the issue? It sounds like you might be using a specific combination of size modifiers.

colinrtwhite commented 7 months ago

If the ask is to multiply an SVG image's intrinsic width/height px to match its density similar to https://github.com/coil-kt/coil/issues/2048 then we could potentially add a new constructor param. Though, my understanding of the SVG specification was that values represented in px units shouldn't be scaled to a device's density. This change would add different behaviour from the specification.

NatashaIJ commented 7 months ago

Sample code: CoilImages.zip

  1. It works same with rememberAsyncImagePainter and with AsyncImage
  2. useViewBoundsAsIntrinsicSize = false - doesn't fix the issue
seanpont commented 7 months ago

https://github.com/coil-kt/coil/pull/2090