crop image save in internal storage and get bitmap from uri - android

I write a code crop image.The image maybe a little big,so I use intent.putExtra("return-data", false); and intent.putExtra("output", outputUri); So I should decode the uri to get bitmap.Just like this(omActivityResult)
InputStream is = null;
is = getContentResolver().openInputStream(outputUri);
Bitmap avatar = BitmapFactory.decodeStream(is);
I first make External Storage to store the crop image.It work well.
outputUri = Uri.fromFile(new File("/storage/emulated/0/upload.jpg"));
But I need to store it in Internal Storage.I follow the Android developer
to save in Internal Storage.The code follow.
FileOutputStream os = null;
try
{
os = openFileOutput("upload.jpg", 0);
}
catch (FileNotFoundException e)
{
}
finally
{
if (os != null)
{
try
{
os.close();
}
catch (IOException e)
{
}
}
}
outputUri = Uri.fromFile(new File(getFilesDir().getAbsolutePath(), "upload.jpg"));
the avatar will be null.I have read many questions in stackoverflow but it doesn't work. Can you help me?

Related

Problems saving and retrieving images

Ok i'm completely editing this post... I have made it so that I can save the file path to my data base. this works and is saved as /storage/emulated/0/1508blah blah.jpg . Now i cannot get my code to read this item back into a picture.
imagePhoto = (ImageView)findViewById(R.id.detail_recipe_image);
Toast.makeText(this, recipe.image, Toast.LENGTH_SHORT).show();
Bitmap bmp = BitmapFactory.decodeFile(String.valueOf(recipe.image));
imagePhoto.setImageBitmap(bmp);
am I missing something here? cause the Toast Is reading the recipe.image just fine and is displaying the path. why Is the rest not displaying the image?
Storage Code
private void onCaptureImageResult(Intent data) {
Bitmap thumbnail = (Bitmap) data.getExtras().get("data");
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
thumbnail.compress(Bitmap.CompressFormat.JPEG, 90, bytes);
File destination = new File(Environment.getExternalStorageDirectory(),
System.currentTimeMillis() + ".jpg");
String picturePath = destination.toString();
FileOutputStream fo;
try {
destination.createNewFile();
fo = new FileOutputStream(destination);
fo.write(bytes.toByteArray());
fo.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
textImagePath.setText(picturePath.toString());
ImageView img = (ImageView)findViewById(R.id.addphotoview);
img.setImageBitmap(thumbnail);
}
Adding in the files paths seem to be the best solution to the problem i am having so that you #ModularSynth for your help with this. Always making sure all the info is your code to make the file paths work helps.

Writing EXIF data to image saved with DocumentFile class

I need to get a File from DocumentFile or Uri with correct scheme not the one with content://com.android.externalstorage.documents/tree/primary: if the device's main memory is selected.
To get File or absolute path of the image i need the one with file:///storage/emulated/0 or storage/emulated/0 but i could not find a way to get correct Uri for building a File to write EXIF data to image.
My scenario is:
User chooses a path to save images which returns Uri with content://com.android.externalstorage.documents onActivityResult(). I save this path with treeUri.toString() to SharedPreferences for using later.
User takes a picture and image is saved with DocumentFile.fromTreeUri(MainActivity.this, Uri.parse(uriString));
This where i fail, getting a File that correctly points to image, Uri with content:// does not return the existing image.Correct Uri should file:///storage/emulated/ and i can convert this Uri to file using File filePath = new File(URI.create(saveDir.getUri().toString()));
How can i get the Uri needed for consturcting File or File using Uri i got from SAF UI?
EDIT: ExifInterface Support Library is introduced for Android 7.1+ that can use InputStream or FileDescriptor.
Uri uri; // the URI you've received from the other app
InputStream in;
try {
in = getContentResolver().openInputStream(uri);
ExifInterface exifInterface = new ExifInterface(in);
// Now you can extract any Exif tag you want
// Assuming the image is a JPEG or supported raw format
} catch (IOException e) {
// Handle any errors
} finally {
if (in != null) {
try {
in.close();
} catch (IOException ignored) {}
}
}
Note: ExifInterface will not work with remote InputStreams, such as those returned from a HttpURLConnection. It is strongly recommended to only use them with content:// or file:// URIs.
Snippet above is reading data obviously since it opens an InputStream to read data. I need to be able to write EXIF data to JPEG files.
Answer for writing Exif data to an image previously saved and with known content Uri using FileDescriptor if Api is 24 or above
private void writeEXIFWithFileDescriptor(Uri uri) {
if (Build.VERSION.SDK_INT < 24) {
showToast("writeEXIFWithInputStream() API LOWER 24", Toast.LENGTH_SHORT);
return;
}
ParcelFileDescriptor parcelFileDescriptor = null;
try {
parcelFileDescriptor = mContext.getContentResolver().openFileDescriptor(uri, "rw");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
showToast("writeEXIFWithFileDescriptor(): " + fileDescriptor.toString(), Toast.LENGTH_LONG);
ExifInterface exifInterface = new ExifInterface(fileDescriptor);
// TODO Create Exif Tags class to save Exif data
exifInterface.saveAttributes();
} catch (FileNotFoundException e) {
showToast("File Not Found " + e.getMessage(), Toast.LENGTH_LONG);
} catch (IOException e) {
// Handle any errors
e.printStackTrace();
showToast("IOEXception " + e.getMessage(), Toast.LENGTH_LONG);
} finally {
if (parcelFileDescriptor != null) {
try {
parcelFileDescriptor.close();
} catch (IOException ignored) {
ignored.printStackTrace();
}
}
}
}
If Api is lower than 24 it's necessary to use a buffer file and save that buffer file to actual location with DocumentFile after writing Exif data is finished.
private boolean exportImageWithEXIF(Bitmap bitmap, DocumentFile documentFile) {
OutputStream outputStream = null;
File bufFile = new File(Environment.getExternalStorageDirectory(), "buffer.jpg");
long freeSpace = Environment.getExternalStorageDirectory().getFreeSpace() / 1048576;
double bitmapSize = bitmap.getAllocationByteCount() / 1048576d;
showToast("exportImageWithEXIF() freeSpace " + freeSpace, Toast.LENGTH_LONG);
showToast("exportImageWithEXIF() bitmap size " + bitmapSize, Toast.LENGTH_LONG);
try {
outputStream = new FileOutputStream(bufFile);
// Compress image from bitmap with JPEG extension
if (mCameraSettings.getImageFormat().equals(Constants.IMAGE_FORMAT_JPEG)) {
isImageSaved = bitmap.compress(CompressFormat.JPEG, mCameraSettings.getImageQuality(), outputStream);
showToast("isImageSaved: " + isImageSaved, Toast.LENGTH_SHORT);
}
if (isImageSaved) {
writeEXIFWithFile(bufFile);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
OutputStream os = null;
InputStream is = null;
try {
int len;
byte[] buf = new byte[4096];
os = mContext.getContentResolver().openOutputStream(documentFile.getUri());
is = new FileInputStream(bufFile);
while ((len = is.read(buf)) > 0) {
os.write(buf, 0, len);
}
os.close();
is.close();
if (bufFile != null) {
bufFile.delete();
bufFile = null;
}
} catch (IOException e) {
e.printStackTrace();
}
return isImageSaved;
}
Both methods can be used to write Exif data to image saved to device's memory or SD card. You can also save image to SD card using valid Uri from Storage Access Framework.
I also found a way to get absolute path for memory and SD card from content Uri but it's irrelevant for this question and using Uri instead of absolute path is encouraged and does not lead to unnoticed errors, i also wasn't able to save image to SD card with absolute path, only able to read from it.

Get Exif data using Uri

I want to get Exif data for an image that I pick from Android gallery or similar apps like Google Photos. Here are the methods that I am using for getting image file from Uri:
public static String getActualPathFromUri(#NonNull Context context, #NonNull Uri selectedImageUri) {
Bitmap bitmap = null;
try {
bitmap = getBitmapFromUri(context, selectedImageUri);
} catch (IOException e) {
e.printStackTrace();
}
if (bitmap == null) {
return null;
}
File imageFileFolder = new File(context.getCacheDir(), "example");
if (!imageFileFolder.exists()) {
imageFileFolder.mkdir();
}
FileOutputStream out = null;
File imageFileName = new File(imageFileFolder, "example-" + System.currentTimeMillis() + ".jpg");
try {
out = new FileOutputStream(imageFileName);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.flush();
out.close();
} catch (IOException e) {
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return imageFileName.getAbsolutePath();
}
private static Bitmap getBitmapFromUri(#NonNull Context context, #NonNull Uri uri) throws IOException {
ParcelFileDescriptor parcelFileDescriptor =
context.getContentResolver().openFileDescriptor(uri, "r");
assert parcelFileDescriptor != null;
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
parcelFileDescriptor.close();
}
The reason I am opting for Bitmap from the Uri instead of getting system filename is because the method is fragmented for different versions of Android. Plus, in apps like Google Photos, some photos are shown directly from server and are not stored on the device, so getting filename is not possible. Even if I get the filename, I get Security Exception when trying to use that in my app.
The problem with this approach is, when I get the Bitmap, I don't get the Exif data. But I need the Exif data and attach it to the file that I save in my cache folder so that when I upload the image to server, it gets the image along with Exif so that it can do some further processing. The reason, I need to save it as a file or at least get the file, if it already exists in the system is because Retrofit needs a File object which then gets converted to TypedFile and sent to server using Multipart request.
So, how can I accurately get the Exif information from any kind of image Uri(local or on server) and then save the image along with it's Exif data so that I can send it to the server.

take screenshot from layout and share via android

I use below code to take screen shot from my layout and share it via android intent but the captured screen shot in the selected app is not showing any thing.
#Override
public void onClick(View view) {
shareBitmap(this,takeScreenshot());
}
public Bitmap takeScreenshot() {
try{
View rootView = getWindow().getDecorView().findViewById(R.id.lyt_main_report_activity);
rootView.setDrawingCacheEnabled(true);
return rootView.getDrawingCache();
}catch (Exception ex){
ex.printStackTrace();
}
return null;
}
public static void shareBitmap(Context context, Bitmap bitmap){
//save to sd card
try {
File cachePath = new File(context.getCacheDir(), "images");
cachePath.mkdirs(); // don't forget to make the directory
FileOutputStream stream = new FileOutputStream(cachePath + "/image.png"); // overwrites this image every time
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
stream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try{
//start share activity
File imagePath = new File(context.getCacheDir(), "images");
File newFile = new File(imagePath, "image.png");
Uri contentUri = Uri.fromFile(newFile); //FileProvider.getUriForFile(context, "com.persianswitch.apmb.app.fileprovider", newFile);
if (contentUri != null) {
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
//shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // temp permission for receiving app to read this file
// shareIntent.setDataAndType(contentUri, context. getContentResolver().getType(contentUri));
shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
shareIntent.setType("image/*");
context.startActivity(Intent.createChooser(shareIntent, context.getResources().getString(R.string.share_using)));
}
}catch (Exception ex){
ex.printStackTrace();
}
}
Please use this code this is tested code :
public static void takeScreenshot(Context context, View view) {
String path = Environment.getExternalStorageDirectory().toString() +
"/" + "test.png";
View v = view.findViewById(android.R.id.content).getRootView();
v.setDrawingCacheEnabled(true);
v.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(v.getDrawingCache());
v.setDrawingCacheEnabled(false);
OutputStream out = null;
File imageFile = new File(path);
try {
out = new FileOutputStream(imageFile);
// choose JPEG format
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
} catch (FileNotFoundException e) {
// manage exception
} catch (IOException e) {
// manage exception
} finally {
try {
if (out != null) {
out.close();
}
} catch (Exception exc) {}
}
// onPauseVideo();
Intent share = new Intent(Intent.ACTION_SEND);
share.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(imageFile));
share.setType("image/png");
((Activity) context).startActivityForResult(
Intent.createChooser(share, "Share Drawing"), 111);
}
Since DrawingCache() deprecated above 28 so using Canvas will sort the issues for many. below answer can be used for share Screenshot including text without requesting for permissions.
To take the Screenshot
private Bitmap takeScreenShot(View view) {
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
return bitmap;
}
To share the Screenshot
private void shareContent(Bitmap bitmap) {
String bitmapPath = MediaStore.Images.Media.insertImage(
binding.getRoot().getContext().getContentResolver(), bitmap, "title", "");
Uri uri = Uri.parse(bitmapPath);
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("image/*");
shareIntent.putExtra(Intent.EXTRA_SUBJECT, "App");
shareIntent.putExtra(Intent.EXTRA_TEXT, "Currently a new version of KiKi app is available.");
shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
binding.getRoot().getContext().startActivity(Intent.createChooser(shareIntent, "Share"));
}
if nothing happens it means your Bitmap is null kindly check that. or you could also fall on View.buildDrawingCache(); which will draw the View to Bitmap and then call your View.getDrawingCache();
also When hardware acceleration is turned on, enabling the drawing cache has no effect on rendering because the system uses a different mechanism for acceleration which ignores the flag. If you want to use a Bitmap for the view, even when hardware acceleration is enabled, see setLayerType(int, android.graphics.Paint) for information on how to enable software and hardware layers.
the quote was taken from the documented page
hope it helps
Tipp:The checked answer works when your device has external storage. On the Samsung 6 for example, it doesnt. Therefore you need to work with fileprovider.
Just incase somebody fell into this trap like me. The problem is that you are putting the name of the image twice.
FileOutputStream stream = new FileOutputStream(cachePath + "/image.png");
and than again.
File newFile = new File(imagePath, "image.png");
Change The seconed one to
File newFile = new File(imagePath);
Otherwise the contentUri give you the bitmap of your screenshot. I hope this helps someone. Took me 3 hours to figure it out :)

How to retrieve images stored in Gallery folder of Android device

Hi
I am writing an Android application in which I want to retrieve the images stored in Gallery folder of Device/emulator. Can any one give me sample code regarding how to achieve this.
Thanks and Regards
If you have path where your images are stored, use this code to get image as bitmap.
FileInputStream in;
BufferedInputStream buf;
try {
in = new FileInputStream("/sdcard/test2.png");
buf = new BufferedInputStream(in);
Bitmap bMap = BitmapFactory.decodeStream(buf);
image.setImageBitmap(bMap);
if (in != null) {
in.close();
}
if (buf != null) {
buf.close();
}
} catch (Exception e) {
Log.e("Error reading file", e.toString());
}
You need to iterate through the path: ex
File f=new File("path of dir");
Now get all files using: f.listFiles();
This is s fair idea..........
Hope it will help........
Just for picking them?. If so, you can use this intent:
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
Ger

Categories

Resources