How do I get a Palette for my bitmap once Picasso

2019-04-01 00:55发布

问题:

In October 2014, Jake Wharton wrote Coercing Picasso to Play With Palette. In it, there are 2 methods being pondered:

  1. Using a Transformation that generates the palette. The advantage of this is that the palette is generated on Picasso's worker thread and is ready when the image is loaded. The disadvantage, however, seems to be that I'm getting palettes that don't match the picture. At the moment I only run one of these transformations at a time.

  2. Using a Callback that onSuccess gets the bitmap from the ImageView and generates the Palette. I can't help but focus on the // Ew! that Jake puts at the end of this line and I quite agree with it.

The post mentioned above was written in October 2014. Now that we're months past the discussion, I'm wondering what is the recommended method? There was also a discussion about associating meta data with bitmaps. Is that implemented? How would I use it?

My Transformation code (not final, I've just started looking into this):

public final class PaletteGenerator
  implements Transformation {

    private final int numColors;
    @Getter private Palette palette;

    @Override public Bitmap transform (final Bitmap source) {
        palette = null;
        final Palette palette = numColors > 0
                                ? Palette.generate (source, numColors)
                                : Palette.generate (source);
        return source;
    }

    @Override public String key () {
        return String.format (Locale.ENGLISH, "%s:%d", getClass ().getCanonicalName (), numColors);
    }

    public PaletteGenerator () {
        this (0);
    }

    public PaletteGenerator (final int c) {
        numColors = c;
    }
}

回答1:

According to Jake Wharton there is no good way yet

What I ended up doing was that I went with the Transformation method, with the ugly code encapsulated & hidden in the attic.

public final class PaletteGeneratorTransformation
  implements Transformation {

    private static final Map<Bitmap, Palette> CACHE = new WeakHashMap<> ();
    private final int    numColors;

    @Override public Bitmap transform (final Bitmap source) {
        if (!CACHE.containsKey (source)) {
            final Palette palette = numColors > 0
                      ? Palette.generate (source, numColors)
                      : Palette.generate (source);
            CACHE.put (source, palette);
        }

        return source;
    }

    @Override public String key () {
        return getClass ().getCanonicalName () + ":" + numColors;
    }

    public PaletteGeneratorTransformation () {
        this (0);
    }

    public PaletteGeneratorTransformation (final int c) {
        numColors = c;
    }

    public static abstract class Callback
      implements com.squareup.picasso.Callback {
        private final ImageView target;

        public Callback (final ImageView t) {
            target = t;
        }

        @Override public void onSuccess () {
            onPalette (CACHE.get (((BitmapDrawable) target.getDrawable ()).getBitmap ()));
        }

        @Override public void onError () {
            onPalette (null);
        }

        public abstract void onPalette (final Palette palette);
    }
}

In my Activity, I do something along these lines:

Picasso.with(context)
    .load (getPhotoUri())
    .transform (new PaletteGeneratorTransformation (DEFAULT_NUM_COLORS))
    .into (photo, new PaletteGeneratorTransformation.Callback (photo) {
                        @Override public void onPalette (final Palette palette) {
                            themeWithPalette (palette);
                        }
                    });

The only problem remaining is that I know there's ugliness hidden in the attic and for now that has to remain my dirty little secret.



回答2:

Target target = new Target() {
        @Override
        public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
            viewHolder.mItemImage.setImageBitmap(bitmap);
            Drawable image = viewHolder.mItemImage.getDrawable();
        }

        @Override
        public void onPrepareLoad(Drawable placeHolderDrawable) {

        }

        @Override
        public void onBitmapFailed(Drawable errorDrawable) {

        }
    };
    Picasso.with(viewHolder.mItemImage.getContext()).load("url").into(viewHolder.mItemImage);