FernandoPaiva
FernandoPaiva

Reputation: 4460

Saving image from url using Picasso?

I'm trying save an image using API Picasso. To do it I'm trying use Target to save but I can't do this work.

How could I do this ?

Trying

//save image
    public static void imageDownload(Context ctx){
        Picasso.with(ctx)
                .load("http://blog.concretesolutions.com.br/wp-content/uploads/2015/04/Android1.png")
                .into(getTarget("http://blog.concretesolutions.com.br/wp-content/uploads/2015/04/Android1.png"));
    }

    //target to save
    private static Target getTarget(final String url){
        Target target = new Target(){

            @Override
            public void onBitmapLoaded(final Bitmap bitmap, Picasso.LoadedFrom from) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        //Log.i("PRODUTOS_FOLDER", CreateAppFolder.getProdutosFolder());
                        File file = new File(Environment.getExternalStorageDirectory() + url);

                        try {
                            file.createNewFile();
                            FileOutputStream ostream = new FileOutputStream(file);
                            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, ostream);
                            ostream.flush();
                            ostream.close();
                        }
                        catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }).start();

            }

            @Override
            public void onBitmapFailed(Drawable errorDrawable) {

            }

            @Override
            public void onPrepareLoad(Drawable placeHolderDrawable) {

            }
        };
        return target;
    }

Exception

java.io.IOException: open failed: ENOENT (No such file or directory)

Upvotes: 29

Views: 39356

Answers (5)

ivoroto
ivoroto

Reputation: 1035

My kotlin solution, storing files into the internal storage and with no user permission needed:

since I had to download multiple images at once, had to create a MutableList<Target?> called shareTargetsArray and to fill it with the multiple targets otherwise the garbage collector would have removed them except the last one. Just remember to clean up that array once you're done.

    private var shareTargetsArray: MutableList<Target?> = ArrayList()

    fun downloadImage(context: Context, url: String?, slug: String) {

        val shareTarget = object : Target {
            override fun onBitmapLoaded(bitmap: Bitmap, from: LoadedFrom?) {

                    val contextWrapper = ContextWrapper(context)
                    val directory: File =
                        contextWrapper.getDir("customDirectory", Context.MODE_PRIVATE)
                    val file = File(directory, slug + ".png")

                    var outputStream: FileOutputStream? = null

                    try {
                        outputStream = FileOutputStream(file)

                        bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
                        outputStream.flush()
                    } catch (e: IOException) {
                        e.printStackTrace()
                    } finally {
                        try {
                            outputStream!!.close()
                        } catch (e: IOException) {
                            e.printStackTrace()
                        }
                    }
                }

            override fun onBitmapFailed(e: java.lang.Exception?, errorDrawable: Drawable?) {}

            override fun onPrepareLoad(placeHolderDrawable: Drawable?) {}
        }

        shareTargetsArray.add(shareTarget)
        Picasso.get().load(url).into(shareTarget)
    }
}

Files are downloaded in /data/data/com.***.***/customDirectory/ You can check them using View > Tool Windows > Device File Explorer

Upvotes: 1

Abhishek Sengupta
Abhishek Sengupta

Reputation: 3291

I Modified the solution to this, adding permissions and a button to load and save the Image,and PhotoLoader class remains the same !

private static final String[] STORAGE_PERMISSIONS = { Manifest.permission.WRITE_EXTERNAL_STORAGE};
    ImageView imageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        imageView = (ImageView) findViewById(R.id.imageView);

        verifyPermissions();
    }
    public void save(View view)
    {
        Picasso.with(this)
                .load("https://www.w3schools.com/howto/img_fjords.jpg")
                .into(new PhotoLoader("myImg.jpg" , imageView));
    }

    public void verifyPermissions()
    {
        // This will return the current Status
        int permissionExternalMemory = ActivityCompat.checkSelfPermission(MainActivity.this,Manifest.permission.WRITE_EXTERNAL_STORAGE);

        if(permissionExternalMemory != PackageManager.PERMISSION_GRANTED)
        {
            // If permission not granted then ask for permission real time.
            ActivityCompat.requestPermissions(MainActivity.this,STORAGE_PERMISSIONS,1);
        }
    }

Upvotes: 1

ram992
ram992

Reputation: 1

I think you need to check whether you are actually requesting the permission. In Android the permissions are dynamic starting from the version 6.0. Either you must request it at run time or just downgrade your targetSdk version to 22.

Upvotes: 0

FernandoPaiva
FernandoPaiva

Reputation: 4460

Solved. now works fine!

I did

//save image
    public static void imageDownload(Context ctx, String url){
        Picasso.with(ctx)
                .load("http://blog.concretesolutions.com.br/wp-content/uploads/2015/04/Android1.png")
                .into(getTarget(url));
    }

    //target to save
    private static Target getTarget(final String url){
        Target target = new Target(){

            @Override
            public void onBitmapLoaded(final Bitmap bitmap, Picasso.LoadedFrom from) {
                new Thread(new Runnable() {

                    @Override
                    public void run() {

                        File file = new File(Environment.getExternalStorageDirectory().getPath() + "/" + url);
                        try {
                            file.createNewFile();
                            FileOutputStream ostream = new FileOutputStream(file);
                            bitmap.compress(Bitmap.CompressFormat.JPEG, 80, ostream);
                            ostream.flush();
                            ostream.close();
                        } catch (IOException e) {
                            Log.e("IOException", e.getLocalizedMessage());
                        }
                    }
                }).start();

            }

            @Override
            public void onBitmapFailed(Drawable errorDrawable) {

            }

            @Override
            public void onPrepareLoad(Drawable placeHolderDrawable) {

            }
        };
        return target;
    }

Upvotes: 31

CkurtM
CkurtM

Reputation: 195

I can see 2 possible issues:

  1. trying to save to external storage without write permissions in your manifest
  2. try change the filename so its not the whole url, which could be your issue because of the characters in your url that arent valid as filename chars.

Upvotes: 3

Related Questions