BigBadaboom / androidsvg

SVG rendering library for Android
http://bigbadaboom.github.io/androidsvg/
Apache License 2.0
1.2k stars 227 forks source link

Large SVG(1000x1000) does not load on Software Layer #245

Closed DavidCorrado closed 2 years ago

DavidCorrado commented 2 years ago

Glide Version: 4.12.0

Integration libraries: https://github.com/BigBadaboom/androidsvg

Device/Android Version: Pixel 4 API 30 emulator and misc android physical devices

Issue details / Repro steps / Use case background: If you run on a Pixel 4 API 30 emulator in portrait the android image displays. In landscape it does not show the image but instead just the background.

Actual: Landscape with the sample project with aspect ratio 3:2 does not display image

Expected: Landscape with sample project with aspect ratio 3:2 does display android icon

Important Note: If you choose aspect ratio 3:1 it works

Glide load line / GlideModule (if any) / list Adapter code (if any): https://github.com/DavidCorrado/GlideSVGBug

        val requestBuilder = GlideApp.with(this)
            .`as`(PictureDrawable::class.java)
            .transition(withCrossFade())
            .listener(SvgSoftwareLayerSetter())
        requestBuilder.load(Uri.parse("https://upload.wikimedia.org/wikipedia/commons/d/d7/Android_robot.svg")).into(findViewById(R.id.articleHeaderImage))

All code copied from https://github.com/bumptech/glide/tree/master/samples/svg

Layout XML: <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent">

<ImageView
    android:id="@+id/articleHeaderImage"
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:contentDescription="@null"
    app:layout_constraintDimensionRatio="3:2"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    tools:background="#0289A0" />

</androidx.constraintlayout.widget.ConstraintLayout>

Stack trace / LogCat: N/A

BigBadaboom commented 2 years ago

Also posted on the Glide issue tracker here: https://github.com/bumptech/glide/issues/4710

BigBadaboom commented 2 years ago

Thanks for reporting this issue.

At first glance, it's hard to see how it could be AndroidSVG or Glide at fault here. Glide is just fetching an SVG and calling AndroidsSVG to parse it to a PictureDrawable. That behaviour will be identical for both portrait and landscape orientations. Those operations are both independent of the layout and the device dimensions. I don't see how the device orientation could affect the behaviour of either of our two libraries.

I am more inclined to suspect that the cause is a quirk, or perhaps bug, related to ConstraintLayout.

@DavidCorrado When you say that all that is displayed is "just the background", do you mean the app background? Your layout has no background colour. So I assume that is what you mean.

Are you sure that the ImageView is not just collapsing to zero size, because the constraints can't be met in landscape mode? Have you tried checking if that is the problem? You could, for instance:

Or perhaps try testing on an emulator device that would support a 3:2 aspect ratio. Such as a tablet.

DavidCorrado commented 2 years ago

Thanks for the reply.

Some things I have tried is I swapped out the svg with a png and it worked via glide. Also I tried the background color and it does appear on landscape when loading the svg in landscape the background color disappears. But interestingly enough if I remove the SVG loading code from glide it works. So something with running the glide svg loading code causes the imageview to goto 0 height or something.

I will continue exploring here and post what I find. So some interesting things to explore: 1) Do aspect ratio without constraint layout 2) Try landscape without aspect ratio 3) See why in landscape the image gets collapsed

DavidCorrado commented 2 years ago

Found out something interesting Tested with Pixel 4 emulator, Pixel 5, Samsung20+ all with same results as above.

Pixel C tablet emulator works.

Also found an warning in the logs related to landscape W/View: AppCompatImageView not displayed because it is too large to fit into a software layer (or drawing cache), needs 10422744 bytes, only 9849600 available

So I commented .listener(SvgSoftwareLayerSetter())

It worked. Still not sure root cause but it does appear something with the landscape image that gets generated is over the maximum of the software layer.

So the image gets computed to be 10MB it seems. I am not sure what is expected here or the root cause but something to dig into.

DavidCorrado commented 2 years ago

Also I am able to replicate with portrait if I change the imageview to 1000x1000. So I removed the constraintlayout and pushed out to my repo. So it definitely has to do with software layer not supporting larger sizes.

BigBadaboom commented 2 years ago

Ah interesting.

I haven't ever come across that software layer memory restriction before. For a long time setting a layer to be software was necesary due to the fact that many Canvas methods were not supported in hardware accelerated layers. That is no longer the case for more recent versions of Android.

I have no idea if that limit was always there or not. We may just be hitting it now due to how high screen resolutions are getting. The Pixel4 screen is 1080x2280. So in landscape, at 3:2, the ImageView could potentially end up at something like:

2200 x 1466 x 4 = 12,900,800 bytes

If that 10422744 is right, that would make your ImageView 1977 x 1318 - if my algebra is correct.

In any case, you found the right solution. You would only need to worry if you need to support old versions of Android. If you do, you may want to consider switching from the ImageView/PictureDrawable solution that the Glide demo users. The alternative is to render directly to the Canvas.

Thanks for the doing the follow-up work.

Paul

DavidCorrado commented 2 years ago

Cool so it seems according to https://developer.android.com/guide/topics/graphics/hardware-accel#unsupported If you set your min sdk to 23 you should be ok to remove it right?

Thanks. Appreciate your support in helping point me in a good direction

DavidCorrado commented 2 years ago

Actually can you clarify what the min sdk is to remove the software layer. Not sure what exactly canvas APIs you are using. Seems like some things are 28

DavidCorrado commented 2 years ago

Is this something where it works or doesnt work? So I can test. Or depending on the SVG it might hit a different code path where some SVGs fail

BigBadaboom commented 2 years ago

I think 23 should be fine - to support drawPicture().

AndroidSVG uses Paint.setPathEffect() for dashed lines. That's listed as SDK 28. But I think that just means that the path effects are calculated on the GPU. The dashes should still render on SDK 23-27 devices, via software on the CPU side.

DavidCorrado commented 2 years ago

Thanks so much. I appreciate your time.