square / picasso

A powerful image downloading and caching library for Android
https://square.github.io/picasso/
Apache License 2.0
18.71k stars 3.97k forks source link

Support for VectorDrawables (API 21)? #1109

Open justingarrick opened 9 years ago

justingarrick commented 9 years ago

Is support for the new VectorDrawable type introduced in Lollipop planned as a possible enhancement?

Currently, when I attempt to load any VectorDrawable with Picasso, e.g. Picasso.with(context).load(R.drawable.ic_vector_drawable).into(imageView), the ImageView blanks out and nothing is rendered.

JakeWharton commented 9 years ago

No plans. Vectors, by definition, don't really need an image processing pipeline to change their size. Why are you wanting to use Picasso for this?

justingarrick commented 9 years ago

I think the use case here is for a project with mixed image asset types (i.e. PNGs and VectorDrawables). Rather than conditionally loading VectorDrawables with setImageDrawable, it would be nice to be able to use Picasso throughout the application and do something like the following, even if Picasso is just passing the VectorDrawable through:

Picasso.with(context).load(someBoolean ? R.drawable.ic_some_png : R.drawable.ic_vector_drawable).into(imageView)

This seems like it may become more common moving forward (API 21+).

kayvannj commented 8 years ago

I second on this feature.

austynmahoney commented 8 years ago

Now that Android Studio supports using VectorDrawable and generates pngs for backward compatibility, you now only provide a single resource for either one. On older platforms the image loads just fine, when VectorDrawable is used Picasso fails to load it.

Now you might say put an API level check around that code, but I am using the databinding library. It does not provide any context besides the drawable resource ID. If you put an API level check around it, any image that isn't an SVG would be loaded without Picasso also.

@BindingAdapter("android:src")
public static void setSrc(ImageView view, int res) {
    // Only the resource id is provided here
    Picasso.with(view.getContext()).load(res).into(view);
}

Even a simple passthrough by Picasso would be nice.

austynmahoney commented 8 years ago

@JakeWharton It seems the error handling code will load the vector drawable just fine after the load() call fails. I see --- SkImageDecoder::Factory returned null in the log for each image, but the vector drawable I have set is set just fine. If I remove error(), the image fails to load with the same message.

Why does the same vector drawable asset load if it's set in error(), but not load()? What is different about the error pipeline?

Picasso.with(context)
    .load(R.drawable.my_vector_drawable)
    .error(R.drawable.my_vector_drawable)
    .into(imageView);
JakeWharton commented 8 years ago

It just calls setImageResource and delegates to Android to load.

On Tue, Dec 1, 2015, 6:20 PM Austyn Mahoney notifications@github.com wrote:

@JakeWharton https://github.com/JakeWharton It seems the error handling code will load the vector drawable just fine after the load() call fails. I see --- SkImageDecoder::Factory returned null in the log for each image, but the vector drawable I have set is set just fine. If I remove error(), the image fails to load with the same message.

Why does the same vector drawable asset load if it's set in error(), but not load()? What is different about the error pipeline?

Picasso.with(context) .load(R.drawable.my_vector_drawable) .error(R.drawable.my_vector_drawable) .into(imageView);

— Reply to this email directly or view it on GitHub https://github.com/square/picasso/issues/1109#issuecomment-161128762.

MarcoNica commented 8 years ago

It would be very useful if vectors also work with the .placeholder function. Especially now where support library 23.2 makes it possible to use vectors in pre Lollipop versions.

alexodus commented 8 years ago

MarcoNica:"It would be very useful if vectors also work with the .placeholder function."

+1

martyglaubitz commented 8 years ago

Applying a round transformation to an Vector Image is the thing im trying right now.

ahaeber commented 8 years ago

Ref articles http://android-developers.blogspot.no/2016/02/android-support-library-232.html and https://medium.com/@chrisbanes/appcompat-v23-2-age-of-the-vectors-91cbafa87c88#.741bm31xn it is possible to use Vector drawables with Picasso. You need to wrap the drawable in e.g., a StateListDrawable. Then AppCompat's magic will kick in and fetch the drawable for Picasso.

A short example. First, code for a StateListDrawable - state_list_placeholder:

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:drawable="@drawable/placeholder" />
    </selector>

@drawable/placeholder obviously refers to a vector drawable asset.

Use the state list drawable with Picasso like this:

    final StateListDrawable placeholderList = (StateListDrawable) context.getResources().getDrawable(R.drawable.state_list_placeholder);
    Picasso.with(context)
                    .load(url)
                    .placeholder(placeholderList.getCurrent())
                    .resizeDimen(R.dimen.image_width, R.dimen.image_height)
                    .into(image);
clemp6r commented 8 years ago

The previous workaround does not work if using resource IDs because Picasso uses the Application Context (and this kind of context won't load vector drawables on 4.1). The load function does not accept drawables, only drawable IDs, so we cannot use vector drawables as the main image.

And contrary to what @JakeWharton says we may want to use Picasso with vector drawables to apply custom Bitmap transformations we already wrote for other image types.

martyglaubitz commented 8 years ago

@clemp6r that's what im talking about

austynmahoney commented 8 years ago

Another reason for implementing this is setImageResource() loads the VectorDrawable on the UI thread, not something you really want to do. It would be nice to use Picasso to offload this to a background thread.

adipascu commented 8 years ago

@austinmahoney setImageResource needs to be called from the ui thread but the actual image loading might happen on a different thread (this is an implementation detail of AOSP). In my experience setImageResource is very fast and non blocking. Edit: I am proven to be wrong :)

JakeWharton commented 8 years ago

It is definitely blocking

On Fri, Apr 15, 2016, 7:52 PM adi1133 notifications@github.com wrote:

@austinmahoney setImageResource needs to be called from the ui thread but the actual image loading might happen on a different thread (this is an implementation detail of AOSP). In my expetience setImageResource is very fast and non blocking.

— You are receiving this because you were mentioned.

Reply to this email directly or view it on GitHub https://github.com/square/picasso/issues/1109#issuecomment-210688888

austynmahoney commented 8 years ago

@adi1133 As Jake said, straight from the setImageResource documentation:

This does Bitmap reading and decoding on the UI thread, which can cause a latency hiccup.

Profile any code that loads a VectorDrawable using setImageResource and you'll see a ton of XML String parsing. Not a great thing to do in a RecyclerView because of the massive amount of object allocation.

Here is a sample trace of what a single call to setImageResource does when you give it a VectorDrawable. This is all happening on the main thread. screen shot 2016-04-15 at 7 09 00 pm

ogasimli commented 8 years ago

I am loading VectorDrawables in RecyclerView which leads to skipping of frames. I would be great if there will be a way to move the loading into a background thread.

martyglaubitz commented 8 years ago

Actually there could be meany reasons why loading of even non-vector drawable could take some time (example: nested layer-list). So rather than focusing on vector drawables, i'd recommend a simpler implementation for the current drawable loader of picasso (which afaik only delegates to android for loading the drawable) which is completely agnostic to the type of drawable. It goes something like this:

Bitmap loadDrawable(@DrawableRes int drawableRes) {
    final Drawable drawable = ContextCompat.getDrawable(context, drawableRes);
    drawable.setBounds(0,0, drawable.intrinsicWidth, drawable.intrinsicHeight);

    final Bitmap result = Bitmap.createBitmap(intrinsicWidth, intrinsicHeight, Bitmap.Config.ARGB_8888);
    final Canvas canvas = Canvas(bitmap);
    draw(canvas)

    return bitmap
}

Of course, this doesn't have cache & error handling but shows how it could be done. I'm using this very implementation in my app and it works fairly well

dstocking-ext commented 8 years ago

+1

In the mean time, I am trying to figure out how to disable the vector folder for anydpi-v21 by the support library in order to have all pngs.

ThanosFisherman commented 8 years ago

Any ideas? The workaround by @ahaeber Didn't work for me on android 4.4.2 I need a vector drawable as a placeholder

ncornette commented 8 years ago

This is a Java equivalent to the StateListDrawable solution from @ahaeber : Tested on platform 16 and 23, with Android Compat 23.4.0 then 24.0.0

// Initialize placeholder drawable once
mPlaceholderDrawable = ResourcesCompat.getDrawable(
                                    context.getResources(), 
                                    R.drawable.vector_placeholder, null);
// Use in Picasso
Picasso.with(context)
    .load(url)
    .placeholder(mPlaceholderDrawable)

It required some extra configuration : In gradle :

android {
    defaultConfig {
        vectorDrawables.useSupportLibrary = true

In Activity or Application :

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

References : https://medium.com/@chrisbanes/appcompat-v23-2-age-of-the-vectors-91cbafa87c88#.crrv88967 http://android-developers.blogspot.fr/2016/02/android-support-library-232.html

ncornette commented 8 years ago

You can use VectorDrawables for placeholders (and this is where VectorDrawable can be useful) on platforms that handle it natively (API 21+)

Backward compatibility is handled by both appcompat-v7 and support-v4. As Picasso by itself doesn't have a dependency with those libraries, it makes sense for me that the application has the responsibility to create a compatible Drawable for the API <20 platform and not Picasso.

ThanosFisherman commented 8 years ago

Thanks for the tip @ncornette it's working. And yes I agree it's the app's responsibility to deliver the apropriate drawable but it would come in handy to just do Picasso.with(context).load(url).placeholder(R.drawable.this_is_a_vector_drawable);

JakeWharton commented 8 years ago

Future versions of VectorDrawableCompat will reportedly handle that case, and we will update to use it when it does.

On Tue, Jun 28, 2016 at 1:11 PM Thanos Psaridis (Fisherman) < notifications@github.com> wrote:

Thanks for the tip @ncornette https://github.com/ncornette it's working. And yes I agree it's the app's responsibility to deliver the apropriate drawable but it would come in handy to just do Picasso.with(context).load(url).placeholder(R.drawable.this_is_a_vector_drawable);

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/square/picasso/issues/1109#issuecomment-229116140, or mute the thread https://github.com/notifications/unsubscribe/AAEEEY24gAgqFUbVl3PDawi7NLbrdBoeks5qQVXBgaJpZM4FqVvJ .

ghost commented 8 years ago

@JakeWharton Any update on this issue?

shomronh commented 7 years ago

it would be very nice is there any other option to handle svg properly in android devices ? what is going wrong with google people ?

brucexia commented 7 years ago

Is it possible to use a custom svg decoder with picasso? like overriding the decoding of input stream?

marcosalis commented 7 years ago

@ncornette tip is not working anymore with support library v. 25.1.0 on API 25.

Kolyall commented 7 years ago

@JakeWharton is any way to load image by url to .svg file? something like this: https://example.com/link_to_vector.svg

snowpong commented 7 years ago

To use vector drawables as placeholders in Picasso, load them with AppCompatResources.getDrawable(context, myVectorDrawableId) and use as normal. This method loads both bitmaps and vector drawables in a compatible way, so it'll eat anything - also on KitKat and lower.

pratikbutani commented 7 years ago

Is there any updates? @JakeWharton

P.S. Badly missing SVG Placeholders.:(

magneticflux- commented 7 years ago

@Kolyall Android does not have native support for SVG files period. It does support a limited subset of SVG features through VectorDrawables . You will need some separate library that decodes SVG files into a supported format such as PNG, JPEG, WEBP, etc. Theoretically, you could create a RequestHandler that decodes the SVG into a Bitmap.

teslacoil commented 7 years ago

I looked at if it was doable without modifying Picasso and it's not pretty. My attempt is at https://gist.github.com/teslacoil/c651c4607441a60a12ed7801953536bc , but it can't work with Requests for resourceId or SCHEME_ANDROID_RESOURCE, instead the scheme has to be modified to something else.

This is due to Picasso prioritizing the default ResourceRequestHandler over anything else https://github.com/square/picasso/blob/03ce090543b504a90a5f301fb93db50255539a53/picasso/src/main/java/com/squareup/picasso/Picasso.java#L183

Would a pull request to either modify ResourceRequestHandler to be more like my gist above where if it can't load a bitmap it tries loading the drawable and drawing it to a bitmap be acceptable? Or a pull request that puts an user supplies RequestHandler above the ResourceRequestHandler if it can handle SCHEME_ANDROID_RESOURCE be acceptable?

JakeWharton commented 7 years ago

We can modify Picasso now. The next version is 3.0.

On Thu, Jun 8, 2017, 6:10 AM Kevin notifications@github.com wrote:

I looked at if it was doable without modifying Picasso and it's not pretty. My attempt is at https://gist.github.com/teslacoil/c651c4607441a60a12ed7801953536bc , but it can't work with Requests for resourceId or SCHEME_ANDROID_RESOURCE, instead the scheme has to be modified to something else.

This is due to Picasso prioritizing the default ResourceRequestHandler over anything else https://github.com/square/picasso/blob/03ce090543b504a90a5f301fb93db50255539a53/picasso/src/main/java/com/squareup/picasso/Picasso.java#L183

Would a pull request to either modify ResourceRequestHandler to be more like my gist above where if it can't load a bitmap it tries loading the drawable and drawing it to a bitmap be acceptable? Or a pull request that puts an user supplies RequestHandler above the ResourceRequestHandler if it can handle SCHEME_ANDROID_RESOURCE be acceptable?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/square/picasso/issues/1109#issuecomment-307000107, or mute the thread https://github.com/notifications/unsubscribe-auth/AAEEEczYRbc9_17b3QGYjfyPlnahGg5rks5sB4JNgaJpZM4FqVvJ .

prithivraj commented 7 years ago

Yes, this would be very handy. https://example.com/link_to_vector.svg

Will Picasso 3.0 support this?

Kolyall commented 7 years ago

@prithivraj seems id of svg also should be supported https://example.com/link_to_vector.svg#id_of_svg

toanvc commented 6 years ago

In the time waiting for next 3.0 release, we can use https://bigbadaboom.github.io/androidsvg/

anonym24 commented 6 years ago

you need to support local files because we can use picasso in recyclerview and set for folders our local icons, and have to do it with recyclerview otherwise recyclerview won't cancel previous request and could load image into imageview which picasso should not supposed to load

anonym24 commented 6 years ago

simple example for loading video files' thumbnails

if you replace picasso with mImageView.setImageResource(R.drawable.ic_folder); for directories you will have problems with incorrect loading

private void bindItem(final FileItem fileItem) {

            if (fileItem.getFile().isDirectory()) {
                // if you replace picasso with mImageView.setImageResource(R.drawable.ic_folder); 
               // you will have problems with incorrect loadings
                mPicassoInstance
                        .load(R.drawable.ic_folder)
                        .placeholder(R.drawable.ic_folder)
                        .noFade()
                        .into(mImageView);
            } else {
                mPicassoInstance
                        .load("video:" + fileItem.getFile().getAbsolutePath())
                        .placeholder(R.drawable.ic_file_video)
                        .noFade()
                        .into(mImageView)
           };
JakeWharton commented 6 years ago

Use Picasso.cancel and setImageResource.

On Fri, Mar 9, 2018 at 7:44 AM anonym24 notifications@github.com wrote:

1109 https://github.com/square/picasso/issues/1109

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/square/picasso/issues/1109#issuecomment-371802837, or mute the thread https://github.com/notifications/unsubscribe-auth/AAEEEUHsHuFmDAaEOGNFIzWvlZ0f5EENks5tcnk9gaJpZM4FqVvJ .

anonym24 commented 6 years ago

@JakeWharton yes, thought about this myself https://github.com/square/picasso/issues/1807

retsetman commented 6 years ago

Hello, are you planning to release the support for xml drawables in a stable version soon?

soodkartik1993 commented 2 years ago

image URL vectors is not supporting here. There is an library in glide Glidetovector. which is working fine.