3

I've got an Image Uri, retrieved using the following:

public Uri getImageUri(Context inContext, Bitmap inImage) {
  ByteArrayOutputStream bytes = new ByteArrayOutputStream();
  inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
  String path = Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null);
  return Uri.parse(path);
}

This works just amazing for Intents that require an Image URI, etc (so I know for sure the URI is valid).

But now I want to save this Image URI to a file on the SDCARD. This is more difficult because the URI does not really point at a file on the SDCARD or the app.

Will I have to create a bitmap from the URI first, and then save the Bitmap on the SDCARD or is there a quicker way (preferable one that does not require the conversion to a bitmap first).

(I've had a look at this answer, but it returns file not found - https://stackoverflow.com/a/13133974/1683141)

Community
  • 1
  • 1
Mdlc
  • 7,128
  • 12
  • 55
  • 98

1 Answers1

10

The problem is that the Uri you've been given by Images.Media.insertImage() isn't to an image file, per se. It is to a database entry in the Gallery. So what you need to do is read the data from that Uri and write it out to a new file in the external storage using this answer https://stackoverflow.com/a/8664605/772095

This doesn't require creating a Bitmap, just duplicating the data linked to the Uri into a new file.

You can get the data using an InputStream using code like:

InputStream in = getContentResolver().openInputStream(imgUri);

Update

This is completely untested code, but you should be able to do something like this:

Uri imgUri = getImageUri(this, bitmap);  // I'll assume this is a Context and bitmap is a Bitmap

final int chunkSize = 1024;  // We'll read in one kB at a time
byte[] imageData = new byte[chunkSize];

try {
    InputStream in = getContentResolver().openInputStream(imgUri);
    OutputStream out = new FileOutputStream(file);  // I'm assuming you already have the File object for where you're writing to

    int bytesRead;
    while ((bytesRead = in.read(imageData)) > 0) {
        out.write(Arrays.copyOfRange(imageData, 0, Math.max(0, bytesRead)));
    }

} catch (Exception ex) {
    Log.e("Something went wrong.", ex);
} finally {
    in.close();
    out.close();
}
Community
  • 1
  • 1
SDJMcHattie
  • 1,690
  • 1
  • 15
  • 21
  • Thank you, but now I've got to make the InputStream a byte[], which (as a quick google would suggest) would require the use of a library like IOUtils or a separate return method – Mdlc Feb 22 '14 at 21:26
  • IOUtils is only a convenience library ... I'll update my answer – SDJMcHattie Feb 22 '14 at 21:31
  • Thanks you so much for your time! I'm also getting a exception: java.io.IOException: open failed: ENOENT (No Such file or directory) at the line File.createnewfile() – Mdlc Feb 22 '14 at 21:33
  • Hi, what is `bytesRead`? – Azurespot Feb 22 '15 at 00:57
  • It is an `int` value that I forgot to declare in my example, I'll add it. It tells you how many bytes were actually read in the `read()` method – SDJMcHattie Mar 02 '15 at 11:22