29

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)
FernandoPaiva
  • 4,410
  • 13
  • 59
  • 118
  • 1
    And what exactly is your problem, callback doesn't work, or your Bitmap isn't saved, or anything else? – Vasyl Glodan Sep 26 '15 at 16:37
  • 1
    @VasylGlodan does throws exception `java.io.IOException: open failed: ENOENT (No such file or directory)` – FernandoPaiva Sep 26 '15 at 16:45
  • Hm, I'm not sure but path of your file should look like this `/storage/emulated/0/http://blog.concretesolutions.com.br/wp-content/uploads/2015/04/Android1.png`, and system tries to found directory named `/storage/emulated/0/http://blog.concretesolutions.com.br/wp-content/uploads/2015/04/`, but there is no such directory. Try to remove all special characters from file name. – Vasyl Glodan Sep 26 '15 at 16:51
  • @FernandoPaiva had the same problem. try to make your file name something else, the problem is when you want to create file name with your url. try to use current time or something. – Mahdi Giveie Apr 06 '16 at 12:49

5 Answers5

30

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;
    }
FernandoPaiva
  • 4,410
  • 13
  • 59
  • 118
  • it gives me error: open failed: EACCES (Permission denied). on manifest i have declared – AEMLoviji Feb 18 '16 at 06:08
  • @AEMLoviji Check the external storage state first using `Environment.getExternalStorageState == Environment.MEDIA_MOUNTED` – NineToeNerd Jul 19 '16 at 21:21
  • Why not hash the image url and convert it into a long integer, for purposes of generating a filename? – zyamys Apr 21 '17 at 16:56
3

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.
CkurtM
  • 195
  • 6
  • i used this code. And on my android manifest i have decalred permision as: . and filename is simle: "simpleFileName". And now when i am trying to save it it gives me error: java.io.IOException: open failed:EACCES(Permission denied). what can i do? – AEMLoviji Feb 18 '16 at 06:14
1

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);
        }
    }
Abhishek Sengupta
  • 2,938
  • 1
  • 28
  • 35
1

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

ivoroto
  • 925
  • 12
  • 12
0

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.

ᗩИᎠЯƎᗩ
  • 2,122
  • 5
  • 29
  • 41
ram992
  • 1
  • 1
  • 1