How to save/read inline images in html content to internal/extrenal memory
Asked Answered
P

1

11

According to this question I used a custom ImageGatter class to display images that I'm getting from a server in TextView using Picasso

    public class PicassoImageGetter implements Html.ImageGetter {

    private TextView textView = null;
    Context mContext;

    public PicassoImageGetter() {

    }

    public PicassoImageGetter(TextView target, Context context) {
        textView = target;
        mContext = context;
    }

    @Override
    public Drawable getDrawable(String source) {

        BitmapDrawablePlaceHolder drawable = new BitmapDrawablePlaceHolder();
        Picasso.get().load(source).into(drawable);
        return drawable;

    }

    private class BitmapDrawablePlaceHolder extends BitmapDrawable implements com.squareup.picasso.Target {

        protected Drawable drawable;

        @Override
        public void draw(final Canvas canvas) {
            if (drawable != null) {
                drawable.draw(canvas);
            }
        }

        public void setDrawable(Drawable drawable) {
            this.drawable = drawable;
            int width = drawable.getIntrinsicWidth();
            int height = drawable.getIntrinsicHeight();
            drawable.setBounds(0, 0, width, height);
            setBounds(0, 0, width, height);
            if (textView != null) {
                textView.setText(textView.getText());
            }
        }

        @Override
        public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
            setDrawable(new BitmapDrawable(mContext.getResources(), bitmap));
        }

        @Override
        public void onBitmapFailed(Exception e, Drawable errorDrawable) {
            setDrawable(errorDrawable);
        }

        @Override
        public void onPrepareLoad(Drawable placeHolderDrawable) {

        }

    }
}

and used like this

imageGetter = new PicassoImageGetter(contentTextView, this);
    Spannable html;
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
        html = (Spannable) Html.fromHtml(content, Html.FROM_HTML_MODE_LEGACY, imageGetter, null);
    } else {
        html = (Spannable) Html.fromHtml(content, imageGetter, null);
    }

    contentTextView.setText(html);

I need to catch this images into internal or external storage to display it if there's no connection, but I don't know the path or file name.

Padgett answered 7/2, 2019 at 11:16 Comment(4)
Maybe look at #33040502 to see if it helpsIntuition
Could you please clarify: do you need to read out the image from the cache if the connection is not available or do you want to show some default image if there is no required image in the cache and connection is not available?Surtout
@Igor Khvostenkov the "content" contains blog page content that contains images links like this <a href="1.bp.blogspot.com/-PhotHZJrpfQ/XEbV2_e_9YI/AAAAAAAAHLo/…" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="380" src="1.bp.blogspot.com/-PhotHZJrpfQ/XEbV2_e_9YI/AAAAAAAAHLo/…" /> yes I want caching this images if the connection is not availablePadgett
Intercept your HTTP and handle all image request additionally.Talanta
S
4

You need to implement picasso cache by your own. This should be like this:

public class PicassoCache {

    private static Picasso picassoInstance = null;

    private PicassoCache(Context context) {

        Downloader downloader = new OkHttp3Downloader(context, Integer.MAX_VALUE);
        Picasso.Builder builder = new Picasso.Builder(context);
        builder.downloader(downloader);

        picassoInstance = builder.build();
    }

    public static Picasso getPicassoInstance(Context context) {

        if (picassoInstance == null) {

            new PicassoCache(context);
            return picassoInstance;
        }

        return picassoInstance;
    }
}

Then in your code:

    @Override
    public Drawable getDrawable(String source) {

        BitmapDrawablePlaceHolder drawable = new BitmapDrawablePlaceHolder();
        PicassoCache.getPicassoInstance(getContext()).load(source).into(drawable);
        return drawable;

    }

OkHttp3Downloader will install an image cache into your application cache directory. You can also use another constructor with your own provided directory public OkHttp3Downloader(final File cacheDir, final long maxSize)

As an alternative, you can use Glide. This is like picasso but also allows you to show gifs with animation and cache strategy IMHO is a bit easier.

Glide.with(context)
     .load(source)
     .apply(RequestOptions().diskCacheStrategy(DiskCacheStrategy.ALL))
     .into(drawable)
Surtout answered 13/2, 2019 at 20:51 Comment(7)
thank you, this working good, but some images returns "java.lang.NullPointerException: Attempt to invoke virtual method 'int android.graphics.drawable.Drawable.getIntrinsicWidth()' " when there's no connections in setDrawable methodPadgett
@MarkDeSpain Could you please post the full stack trace?Surtout
E/AndroidRuntime: FATAL EXCEPTION: main Process: www.pro_cs_is.com, PID: 10595 java.lang.NullPointerException: Attempt to invoke virtual method 'int android.graphics.drawable.Drawable.getIntrinsicWidth()' on a null object reference at www.pro_cs_is.com.PicassoImageGetter$BitmapDrawablePlaceHolder.setDrawable(PicassoImageGetter.java:49) at www.pro_cs_is.com.PicassoImageGetter$BitmapDrawablePlaceHolder.onBitmapFailed(PicassoImageGetter.java:65) at com.squareup.picasso.TargetAction.error(TargetAction.java:49) at com.squareup.picasso.Picasso.deliverActPadgett
@MarkDeSpain I can explain that, as in some case you try to load with no connection and without an image in the cache. So, my proposal will be in this case show some placeholder image from local device: PicassoCache.getPicassoInstance(getContext()).load(source).placeholder(R.placeholder_image_on_local_device).into(drawable)Surtout
@MarkDeSpain Should be error not placeholder, messed up here:PicassoCache.getPicassoInstance(getContext()).load(source).error(R.placeholder_image_on_local_device).into(drawable)Surtout
@MarkDeSpain if this answer has solved your question please consider accepting it by clicking the check-mark. This indicates to the wider community that you've found a solution and gives some reputation to both the answerer and yourself. There is no obligation to do this.Surtout
Khvostenko don't worry, I'll do that at last day of bounty If there's no new answersPadgett

© 2022 - 2024 — McMap. All rights reserved.