Scaled down images look excessively pixelated on desktop
Describe the bug
Large AsyncImages scaled down (compared to their original size) look excessively pixelated (on at least) desktop. This doesn't seem to be an issue on Android, so I'm guessing this is not intended behaviour? I can only test these two platforms right now, so it is possible other platforms are also affected.
The effect is most noticeable with screenshots that contain lots of text, as the text becomes completely distorted and unreadable.
To Reproduce
Try to load a high-resolution image with medium-to-small text on it, as the issue is most apparent on images of this type, (e.g. a screenshot of an IDE window) and try to scale it down.
Version v3.1.0
Samples
Original image:
Android scaled down a lot (this is still just about readable!):
Desktop scaled down slightly (already falling apart):
Desktop scaled down a lot (unreadable):
I considered that this is simply due to the higher pixel density of a phone's screen, but the issue is also not reproducible in the emulator so I'm not sure anymore. 😅
Can you share the exact code you are using to scale the images down, it might be helpful for figuring out why this is happening.
Can you share the exact code you are using to scale the images down, it might be helpful for figuring out why this is happening.
Hi!
As far as I can tell, the only thing coil-related is ContentScale.Fit.
AsyncImage(
model = ImageRequest.Builder(LocalPlatformContext.current).data(url).crossfade(true).build(),
contentDescription = attachment.filename,
modifier =
Modifier.padding(top = 8.dp, end = 20.dp)
.widthIn(Dp.Unspecified, 500.dp)
.heightIn(Dp.Unspecified, 500.dp)
.clip(RoundedCornerShape(8.dp))
.clickable(null, indication = null) { component.onAttachmentClicked(attachment.id) }
.pointerHoverIcon(PointerIcon.Hand),
contentScale = ContentScale.Fit,
)
The ImageLoader is defined as follows:
setSingletonImageLoaderFactory { context ->
ImageLoader.Builder(context).crossfade(true).build()
}
The project I'm working on is open source, with this snippet originating from here, if that's of any use.
Android uses a scaler that does not perform anti-aliasing and does not follow frequency folding rules, due to performance reasons ( not only android, any typical 2D rendering engine as Skia ). This issue is not solvable without an external, correct resampler. You’ll need to build and integrate something like the following to make it work properly: https://github.com/Cykooz/fast_image_resize https://github.com/awxkee/pic-scale https://gist.github.com/awxkee/0b39f832b6a81e17f91c9ae6a7dd61c6
Btw OpenCV does the same incorrect scaling, there is only Box filter that works more correct, but not fully correct, because it is correct only for downscaling with factor 2.
Can you share the exact code you are using to scale the images down, it might be helpful for figuring out why this is happening.
https://apache-cordova73.github.io/ty/
Temporary solution generated by Gemini. @hypergonial
import coil3.compose.AsyncImage
import coil3.compose.LocalPlatformContext
import coil3.request.ImageRequest
import coil3.size.Precision
import coil3.size.Size
import androidx.compose.ui.graphics.FilterQuality
// Get the context for the current platform (e.g., JVM)
val context = LocalPlatformContext.current
val imageRequest = ImageRequest.Builder(context)
.data("https://your.image.url/image.jpg")
// Option A: Force the original size
.size(Size.ORIGINAL)
// Option B: Tell Coil not to use an 'inexact' (optimized) size
.precision(Precision.EXACT)
.build()
AsyncImage(
model = imageRequest,
contentDescription = "Description",
// Still use High quality for the draw-time scaling
filterQuality = FilterQuality.High,
modifier = Modifier.size(100.dp)
)