I am using `Modifier.scale()` on an Image() that ...
# compose
a
I am using
Modifier.scale()
on an Image() that has an ImageVector but the vector is really blurry (should be ultra crisp). Is this a bug or am i doing something wrong? Code in 🧵
👀 1
App code:
Copy code
fun main() = singleWindowApplication {
    Box(Modifier.scale(4f).fillMaxSize(), contentAlignment = Alignment.Center) {
        Image(Add, null)
    }
}
Image Vector:
Copy code
val Add: ImageVector by lazy {
    ImageVector.Builder(name = "add", defaultWidth = 40.0.dp, defaultHeight = 40.0.dp, viewportWidth = 40.0f, viewportHeight = 40.0f).apply {
        path(fill = SolidColor(Color(0xFF212121)), fillAlpha = 1f, stroke = null, strokeAlpha = 1f, strokeLineWidth = 1.0f, strokeLineCap = StrokeCap.Butt, strokeLineJoin = StrokeJoin.Miter, strokeLineMiter = 1f, pathFillType = PathFillType.NonZero) {
            moveTo(20f, 31.458f)
            quadToRelative(-0.542f, 0f, -0.917f, -0.396f)
            quadToRelative(-0.375f, -0.395f, -0.375f, -0.937f)
            verticalLineToRelative(-8.833f)
            horizontalLineTo(9.875f)
            quadToRelative(-0.583f, 0f, -0.958f, -0.375f)
            reflectiveQuadTo(8.542f, 20f)
            quadToRelative(0f, -0.583f, 0.375f, -0.958f)
            reflectiveQuadToRelative(0.958f, -0.375f)
            horizontalLineToRelative(8.833f)
            verticalLineTo(9.833f)
            quadToRelative(0f, -0.541f, 0.375f, -0.916f)
            reflectiveQuadTo(20f, 8.542f)
            quadToRelative(0.542f, 0f, 0.938f, 0.375f)
            quadToRelative(0.395f, 0.375f, 0.395f, 0.916f)
            verticalLineToRelative(8.834f)
            horizontalLineToRelative(8.792f)
            quadToRelative(0.583f, 0f, 0.958f, 0.395f)
            quadToRelative(0.375f, 0.396f, 0.375f, 0.938f)
            quadToRelative(0f, 0.542f, -0.375f, 0.917f)
            reflectiveQuadToRelative(-0.958f, 0.375f)
            horizontalLineToRelative(-8.792f)
            verticalLineToRelative(8.833f)
            quadToRelative(0f, 0.542f, -0.395f, 0.937f)
            quadToRelative(-0.396f, 0.396f, -0.938f, 0.396f)
            close()
        }
    }.build()
}
scale x1 vs scale x4 for comparison
s
If you use scale I think it rasterizes the image first and then scales the canvas. Try using modifier.size or modifier.weight on image
1
a
I don't have access to the Image composable in my app. I am setting the scaling from a parent composable
s
Where does the Image function come from?
a
the content of the parent is dynamic. video incoming
I am setting the
Modifier.scale()
to the preview composable. the contents of it are dynamic
i dont believe it matters. I set the scale to the Image itself and the result is the same
Copy code
fun main() = singleWindowApplication {
    Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
        Row {
            Image(Add, null, Modifier.scale(1f))
            Spacer(Modifier.width(40.dp))
            Image(Add, null, Modifier.scale(4f))
        }
    }
}
s
The issue is you are using scale, again it rasterizes the image to original size and then scales up accordingly ie. the pixelations.
☝️ 2
Change the Modifier.scale to Modifier.size on image
a
I don't understand how that would fix the issue. I need to scale the component. size will change the sizing of the parent but wont alter the children sizing
s
Can you share the content of the Image function?
If it is not from compose ui package
If it is from compose ui package just set size on the modifier
a
Image in foundation
s
Did you try setting size on modifier passed to Image function?
c
It’s not a bug 😅 it does what you tell it to do. scale an bitmap.
If it is a vector image you need to
size
.
s
That is what I’m trying to tell 😂
👍 1
a
if that was not true and it does scale a bitmap, how come any other piece of ui is ultra scrip when scaled?
what is special with image vectors?
c
the UI is not a bitmap.
its not special to vectors. it’s special to bitmaps.
a
i am using vectors. where do bitmaps come into play?
c
the
Image
composable takes the vector infomation and creates a bitmap out of it.
e
You can probably update the LocalDensity around the Image based on your scale value. That way if you at least use
.dp
for setting the sizes within the image components then it should just work ™️
Also this is not a bug. I would recommend to close the issue.
h
Give the image an initial size as a state using
.size
and then increase/decrease that size, you're using a vector as others have described, the scale modifier is like a zoom, the more you scale the blurrier it'll get Scale does scale the image within the bounds Hope it's more clear
a
thanks for the recommendations folks. I am sure I can get to the result I want. I'll keep the issue open and let the team decide if it is a bug or not. from my pov, I am using a vector, and I see a
scale()
modifier that doesn't scale the vector. the way image works internally sounds like an implementation detail to me. The same scenario using html + css is trivial to achieve
c
It’s actually not. If you scale the svg it’s fine if you scale the container holding the svg you see the same “issue” in html.
a
you mean like this right? this should scale it up 40 times and it looks crisp
c
I’ll try when I’m on a computer. The viewbox is quite big. I guess the icons vector icons in the library are much smaller. Maybe that’s why you do not see the effect.
a
If
scale
is a parameter of the
Image
, it may work like you want, but it’s instead an independent modifier and is transparent to the element it modifies.
a
Try the LocalDensity suggestion
scale creates a graphicsLayer into which the content is rendered, and then the layer is scaled
In any case, if it’s the same on Android then you can file a bug/feature request on the Google issue tracker. If it’s crisp on Android then it’s a bug in Compose Multiplatform and the issue you already reported is appropriate.
s
I’m pretty sure it is same in android and it was same in android’s view system(wo/ compose) with vector drawable.
a
Just tried on Android and the behavior is the same. I tried wrapping with `
Copy code
CompositionLocalProvider(LocalDensity provides Density(40f)) { }
and the
scaled()
vector is crisp 👌 @Alexander Maryanovsky I have never opened an issue to Google's issue tracker. is it this one https://issuetracker.google.com/issues?q=status:open%20componentid:856989&s=created_time:desc?
a
Yes
But you will likely be told that it’s the expected behavior.
e
Give the image an initial size as a state using
.size
and then increase/decrease that size,
I dont think they had access to the inner component (maybe the child composable set the image size internally). He mentions this is functionality at the parent level. Which is why I suggested manipulating LocalDensity.
I see a
scale()
modifier that doesn’t scale the vector
This makes sense but bear in mind there is nothing in the public API of scale modifier, vectors or image composable that suggests it will work in the way you wanted so the argument can be made that it is rightly not supported because undocumented Anyways glad you got it working with LocalDensity 👍🏾
a
Why does it work with the LocalDensity? had a look at the scale() -> graphicsLayer() code and I dont see the composition local being used
Opened a new issue on the Google Tracker: https://issuetracker.google.com/u/3/issues/342701234
e
Scale is not what “works” with LocalDensity.
LocalDensity
is what is used to resolve “density-independent pixel (dp)” units, eg. as long as you use
24.dp
for icon size, the final pixel value of that 24 will depend on the density, say if the pixel density was 3, then those 24dp will amount to 72 actual device pixels. Updating the density updates the amounts of raw pixels per dp.
today i learned 1
s
Interestingly, on Android, it works just as the author expects. When you scale the graphics layer, the vector graphics redraw as expected without becoming blurred. 🤔
3
scaling a widget that draws arbitrary vector graphics
a
That's definitely not the case. You can easily verify this. Here's the result of the following code.
Copy code
Image(
    Icons.Default.Close,
    contentDescription = null,
    modifier = Modifier
        .size(50.dp)
        .wrapContentSize()
        .scale(10f)
        .size(5.dp),
)
a
May be too many size modifiers here to understand what’s going on
a
It’s basically equal to:
Copy code
Box(
    contentAlignment = Alignment.Center,
    modifier = Modifier.size(50.dp)
) {
    Image(
        ...,
        modifier = Modifier
            .scale(10f)
            .size(5.dp),
    )
}
s
hah, that is surprising. I'm drawing graphics slightly differently in my project.
151 Views