In October 2014, Jake Wharton wrote Coercing Picasso to Play With Palette. In it, there are 2 methods being pondered:
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.
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;
}
}
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.
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);