web-dev-qa-db-fra.com

Utilisation de Glide pour charger des images bitmap dans ImageView

Comment utiliser la bibliothèque Glide pour charger Bitmap dans mon ImageView? Je veux créer une image personnalisée avec text et la charger dans imageview à l’aide de Glide.

Ceci est ma méthode pour créer un bitmap personnalisé avec du texte

public Bitmap imageWithText(String text) {
    TextView tv = new TextView(context);
    tv.setText(text);
    tv.setTextColor(Color.WHITE);
    tv.setBackgroundColor(Color.BLACK);
    tv.setTypeface(null, Typeface.BOLD);
    tv.setGravity(Gravity.CENTER);
    tv.setTextSize(20);
    tv.setPadding(0, 25, 0, 0);
    Bitmap testB = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
    Canvas c = new Canvas(testB);
    tv.layout(0, 0, 100, 100);
    tv.draw(c);
    return testB;
}

Mais quand j'essaye de charger ce bitmap en utilisant glide, je reçois une erreur

Glide.with(getContext()).load(imageWithText("Random text")).into(holder.imgPhoto);
12
user3296088

@rookiedev a raison, il n'y a pas de load(Bitmap) dans Glide , pour une raison: acquérir une Bitmap prend généralement du temps et parfois, bloquer les entrées/sorties. Il n'est donc pas recommandé d'appeler imageWithText sur le thread d'interface utilisateur. Update: Cela étant dit, j'ai proposé cette fonctionnalité il y a quelque temps; et bien que les hacks soient plus faciles à faire, vous pouvez trouver la "manière de glisse" ci-dessous, que je recommande vivement.

Glide est conçu pour être flexible et ce problème démontre ce trait extrêmement bien. L’implémentation suivante peut sembler longue, mais toutes les pièces ont leur raison d’être. Compte tenu du gain de performances, la quantité de code nécessaire pour adapter votre générateur au monde de Glide n’est pas grande. J'ai essayé de le formater pour qu'il soit court, en regroupant les pièces non pertinentes et en utilisant des importations statiques pour être plus court (voir la fin pour les importations).

Le code inclut également une interface utilisateur générée par programme afin que vous puissiez simplement copier-coller tout le code ci-dessous dans GlideGeneratedImageListFragment.Java et l'exécuter. la seule dépendance externe est le support de RecyclerView de lib.

class GeneratingAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    // See https://docs.google.com/drawings/d/1KyOJkNd5Dlm8_awZpftzW7KtqgNR6GURvuF6RfB210g/edit?usp=sharing
    //                                  ModelType/A,    DataType/T,     ResourceType/Z, TranscodeType/R
    private final GenericRequestBuilder<GenerateParams, GenerateParams, Bitmap,         GlideDrawable> generator;

    public GeneratingAdapter(final Context context) {
        generator = Glide // this part should be cleaner in Glide 4.0, but that's not released yet
        .with(context)
        .using(new GenerateParamsPassthroughModelLoader(), GenerateParams.class)          // custom class
        .from(GenerateParams.class)
        .as(Bitmap.class)
        .transcode(new BitmapToGlideDrawableTranscoder(context), GlideDrawable.class)     // builtin
        .decoder(new GenerateParamsBitmapResourceDecoder(context))                        // custom class
        .encoder(new BitmapEncoder(Bitmap.CompressFormat.PNG, 0/*ignored for lossless*/)) // builtin
        .cacheDecoder(new FileToStreamDecoder<Bitmap>(new StreamBitmapDecoder(context)))  // builtin
        //.placeholder(new ColorDrawable(Color.YELLOW)) // you can pre-set placeholder and error
        .error(new ColorDrawable(Color.RED))            // so it's easier when binding
        //.diskCacheStrategy(DiskCacheStrategy.NONE)    // only for debugging to always regenerate
        //.skipMemoryCache(true)                        // only for debugging to always regenerate
        ;
    }
    @Override public int getItemCount() { return 1000; }

    private final float[] colorCache = new float[] {0, 1.0f, 0.5f};
    private final float[] bgCache = new float[] {0, 0.5f, 1.0f};
    @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        colorCache[0] = bgCache[0] = (position * 15) % 360; // just to have a fancy example :)
        GenerateParams params = new GenerateParams(
                // omit position to see Glide caching in action (every 24th item / 12th row is the same)
                "Android text"/* + " #" + position*/,
                Color.HSVToColor(colorCache),
                Color.HSVToColor(bgCache)
        );
        generator/*.clone() in case you see weird behavior*/.load(params).into((ImageView)holder.itemView);
    }

    @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        int height = parent.getContext().getResources().getDisplayMetrics().heightPixels / 3;
        ImageView view = new ImageView(parent.getContext());
        view.setLayoutParams(new RecyclerView.LayoutParams(MATCH_PARENT, height));
        view.setScaleType(ImageView.ScaleType.FIT_CENTER);
        return new RecyclerView.ViewHolder(view) {}; // anon class for brevity
    }
}

public class GlideGeneratedImageListFragment extends Fragment {
    @Override public @Nullable View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        RecyclerView view = new RecyclerView(container.getContext());
        view.setLayoutParams(new MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
        view.setLayoutManager(new GridLayoutManager(container.getContext(), 2 /*columns*/));
        view.setAdapter(new GeneratingAdapter(view.getContext()));
        return view;
    }
}

/** Extracted params from imageWithText, but left some hardcoded values like 20sp/bold/center in {@link Generators}. */
class GenerateParams {
    final String text;
    final int color;
    final int background;

    public GenerateParams(String text, int color, int bg) {
        this.text = text;
        this.color = color;
        this.background = bg;
    }

    public String getId() {
        // TODO make sure it's unique for every possible instance of GenerateParams
        // because it will affect how the resulting bitmap is cached
        // the below is correct correct for the current fields, if those change this has to change
        return String.format(Locale.ROOT, "%s-%08x-%08x", text, color, background);
    }
}

/** Boilerplate because of the degeneration in ModelType == DataType, but important for caching.
 *  @see GeneratingAdapter#generator */
class GenerateParamsPassthroughModelLoader implements ModelLoader<GenerateParams, GenerateParams> {
    @Override public DataFetcher<GenerateParams> getResourceFetcher(final GenerateParams model, int width, int height) {
        return new DataFetcher<GenerateParams>() {
            @Override public GenerateParams loadData(Priority priority) throws Exception { return model; }
            @Override public void cleanup() { }
            @Override public String getId() { return model.getId(); }
            @Override public void cancel() { }
        };
    }
}

/** Handles pooling to reduce/prevent GC lagging from too many {@link Bitmap#createBitmap}s */
class GenerateParamsBitmapResourceDecoder implements ResourceDecoder<GenerateParams, Bitmap> {
    private final Context context;
    public GenerateParamsBitmapResourceDecoder(Context context) { this.context = context; }
    @Override public Resource<Bitmap> decode(GenerateParams source, int width, int height) throws IOException {
        BitmapPool pool = Glide.get(context).getBitmapPool();
        Bitmap bitmap = pool.getDirty(width, height, Bitmap.Config.ARGB_8888);
        if (bitmap == null) {
            bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        }
        Generators.imageWithTextNoLayout(context, bitmap, source);
        return BitmapResource.obtain(bitmap, pool);
    }
    @Override public String getId() {
        // be careful if you change the Generator implementation you have to change this
        // otherwise the users may see a cached image; or clear cache on app update
        return "com.example.MyImageGenerator";
    }
}

class Generators {
    /** OP's original implementation fixed for real centering */
    public static Bitmap imageWithText(Context context, Bitmap bitmap, GenerateParams params) {
        TextView view = new TextView(context);
        view.setText(params.text);
        view.setTextColor(params.color);
        view.setBackgroundColor(params.background);
        view.setTypeface(null, Typeface.BOLD);
        view.setGravity(Gravity.CENTER);
        view.setTextSize(20 /*sp*/);
        Canvas canvas = new Canvas(bitmap);
        view.measure(makeMeasureSpec(canvas.getWidth(), EXACTLY), makeMeasureSpec(canvas.getHeight(), EXACTLY));
        view.layout(0, 0, canvas.getWidth(), canvas.getHeight());
        view.draw(canvas);
        return bitmap;
    }

    /** Generate centered text without creating a View, more lightweight.
     * Consider https://stackoverflow.com/a/8369690/253468 for multiline support. */
    public static Bitmap imageWithTextNoLayout(Context context, Bitmap bitmap, GenerateParams params) {
        Paint paint = new Paint();
        Paint.setColor(params.color);
        Paint.setTextAlign(Paint.Align.CENTER); // text's anchor for the x given in drawText
        Paint.setTextSize(applyDimension(COMPLEX_UNIT_SP, 20, context.getResources().getDisplayMetrics()));
        Paint.setTypeface(Typeface.DEFAULT_BOLD);

        Canvas canvas = new Canvas(bitmap);
        canvas.drawColor(params.background);
        canvas.drawText(params.text, canvas.getWidth() / 2, canvas.getHeight() / 2, Paint);
        return bitmap;
    }
}

// Here are the imports in case you need it;
// didn't want to put it in the beginning to keep the relevant code first.

import Java.io.IOException;
import Java.util.Locale;

import Android.content.Context;
import Android.graphics.*;
import Android.graphics.drawable.ColorDrawable;
import Android.os.Bundle;
import Android.support.annotation.Nullable;
import Android.support.v4.app.Fragment;
import Android.support.v7.widget.*;
import Android.view.*;
import Android.view.ViewGroup.MarginLayoutParams;
import Android.widget.*;

import static Android.util.TypedValue.*;
import static Android.view.View.MeasureSpec.*;
import static Android.view.ViewGroup.LayoutParams.*;

import com.bumptech.glide.*;
import com.bumptech.glide.load.ResourceDecoder;
import com.bumptech.glide.load.data.DataFetcher;
import com.bumptech.glide.load.engine.Resource;
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.model.ModelLoader;
import com.bumptech.glide.load.resource.bitmap.*;
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
import com.bumptech.glide.load.resource.file.FileToStreamDecoder;
import com.bumptech.glide.load.resource.transcode.BitmapToGlideDrawableTranscoder;

Voici à quoi ça ressemble (le défilement réel est beaucoup plus fluide, le format GIF est très faible en FPS):

 enter image description here

Remarquez comment il charge les premiers éléments, puis progressivement le reste. Il faut un peu pour que la mémoire cache et le pool se réchauffent, mais vous pouvez utiliser un préchargeur si vous souhaitez un affichage encore plus fluide. Une fois réchauffé, il défile bien. Le bouton de suppression de la barre d’action appelle Glide.clearDiskCache() et Glide.clearMemory() pour qu’il recommence à régénérer les éléments.

22
TWiStErRob

Je ne connais pas la performance, mais vous pouvez essayer ceci:

Commencez par transformer votre bitmap en tableau byte []:

private byte[] bitmapToByte(Bitmap bitmap){
    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
    byte[] byteArray = stream.toByteArray();
    return byteArray;
}

Ensuite, utilisez la glisse de cette manière:

Glide.with(holder.imagePhoto.getContext()).load(bitmapToByte(yourBitmap)).asBitmap().override(300, 300).fitCenter().into(holder.imagePhoto);

Dans ton cas:

Glide.with(holder.imagePhoto.getContext()).load(bitmapToByte(yourBitmap)).asBitmap().into(holder.imagePhoto); //>>not tested
8

Selon la documentation, je ne pense pas que la méthode load () puisse prendre un bitmap en paramètre. La source de l’image (c’est-à-dire le paramètre) peut être une URL, une ressource pouvant être dessinée et un fichier.

Toutefois, si vous souhaitez charger un bitmap dans un ImageView, vous n'avez pas besoin d'utiliser la bibliothèque Glide. Il suffit d'utiliser la déclaration ci-dessous

holder.imgPhoto.setImageBitmap(imageWithText("Random text"));
1
rookiedev

Vous pouvez essayer, Le code ci-dessous ajoute un ImageView et un TextView à FrameLayout:

FrameLayout frameLayout = new FrameLayout(mContext);
            TextView textView = new TextView(mContext);
            textView.setText("+" + (listImage.size() - countImage));
            textView.setBackground(
                    mContext.getResources().getDrawable(R.drawable.bg_border_tv));
            textView.setTextColor(Color.parseColor("#ffffffff"));
            textView.setGravity(Gravity.CENTER);
            textView.setTextSize(18);
            Glide.with(mContext)
                    .load(listImage.get(i))
                    .apply(new RequestOptions().override(size, size)
                            .transform(new RoundedCorners(20)))
                    .into(imageView);
            frameLayout.addView(imageView);
            frameLayout.addView(textView);
            holder.mItemListLnListImage.addView(frameLayout);

Le résultat sera comme ci-dessous:  enter image description here

0
Doan Bui