I'm trying to convert an image from the gallery into a bitmp and then store it in an array. Previously, however, I am getting a NullPointerException.
How can I convert the image from the gallery?
AddNewHomeFragment.kt:
...
else if(requestCode == GALLERY && resultCode == Activity.RESULT_OK && data != null)
{
//imgData = "content://media/external/images/media/100051...
val imgData = data.data!!
val inputStream = requireContext().contentResolver.openInputStream(imgData)
val exif = ExifInterface(inputStream!!)
val rotation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_UNDEFINED
)
val rotationInDegrees: Int = exifToDegrees(rotation)
//ERROR THROWS HERE
val bitmap = BitmapFactory.decodeStream(inputStream)
val bitmapReturn = rotateBitmap(bitmap,rotationInDegrees)
listImg[aktuellesBild] = bitmapReturn!!
adapter.notifyItemChanged(aktuellesBild)
}
Caused by: java.lang.NullPointerException: bitmap must not be null
You cannot reuse inputStream. ExifInterface will have consumed the stream already. You need to call openInputStream() again to get a fresh InputStream to pass to BitmapFactory.decodeStream().
Related
I am taking a photo using the camera in Android Studio and I would like to save the actual image that resulted from the action. I can access the URI just fine but I would like the actual image itself, as I need to send the photo to a database.
var image_uri: Uri? = null
lateinit var bitmap: Bitmap
private fun openCamera() {
val resolver = requireActivity().contentResolver
val values = ContentValues()
values.put(MediaStore.Images.Media.TITLE, "New Picture")
values.put(MediaStore.Images.Media.DESCRIPTION, "From the Camera")
image_uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
bitmap = MediaStore.Images.Media.getBitmap(resolver, image_uri)
val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, image_uri)
startActivityForResult(cameraIntent, IMAGE_CAPTURE_CODE)
}
I have read that the easiest way to do this is to create a bitmap but I can not get that to work. Running my overall program, the application crashes whenever openCamera is even called. If I comment out the bitmap line, then the function works fine (except I don't have the file saved like I want). How can I do this to where bitmap is an actual Bitmap Object that I can send to the backend of my program?
You can get image bitmap from Camera with this way:
// Open camera
val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
resultLauncher.launch(cameraIntent)
// Get your image
private val resultLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
if (result?.data != null) {
bitmap = result.data?.extras?.get("data") as Bitmap
}
}
}
Easiest way to get the Bitmap is in onActivityResult() like val imageBitmap = data.extras.get("data") as Bitmap. I suggest looking at the documentation for camera, maybe you'll find something useful here.
The way to get the actual image would be to pass the file object, you want to store the image at, to the intent - and that is where the full size image will be.
according to android developers documentation
you should create the file (assuming you've got the READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE permissions depending on the android version and the location of the file you create...) and then pass the file to intent
private fun dispatchTakePictureIntent() {
Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->
// Ensure that there's a camera activity to handle the intent
takePictureIntent.resolveActivity(packageManager)?.also {
// Create the File where the photo should go
val photoFile: File? = try {
createImageFile()
} catch (ex: IOException) {
// Error occurred while creating the File
...
null
}
// Continue only if the File was successfully created
photoFile?.also {
val photoURI: Uri = FileProvider.getUriForFile(
this,
"com.example.android.fileprovider",
it
)
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)
}
}
}
}
In the code snippet it refers to a method "createImageFile()" where the file is being created (The docs in the link provides some samples).
I'm currently trying to save whatever image the user picks into a room database, and it looks like the only way to do this is to first save it as a bitmap. However, I'm not sure how I would do this.
This is the code that I have right now: it lets the user pick an image and displays it in an imageview after. However, I don't know how I could convert my data?.data into a bitmap.
I apologize if this wasn't a very good question, I'm very new to dealing with images and image types in android apps. Any help would be greatly appreciated!
// Opens gallery when image button clicked, gets image
view.image_et.setOnClickListener {
readStorageTask()
//Intent to pick image
val intent = Intent(Intent.ACTION_PICK)
intent.type = "image/*"
startActivityForResult(intent, 1001)
}
// Handle result of picked image
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (resultCode == Activity.RESULT_OK && requestCode == 1001) {
preview_image.setImageURI(data?.data)
}
}
I've seen some StackOverflow questions similar to mine dealing with the same issue in Java, but the ones that I've tried just haven't worked for me. Any help would be greatly appreciated!
You can create a file in cache directory, then create bitmap
if (data != null && data.data != null) {
val uri = data.data!!
val inputStream = requireContext().contentResolver.openInputStream(uri)
val cursor = requireContext().contentResolver.query(uri, null, null, null, null)
cursor?.use { c ->
val nameIndex = c.getColumnIndex(OpenableColumns.DISPLAY_NAME)
if (c.moveToFirst()) {
val name = c.getString(nameIndex)
inputStream?.let { inputStream ->
// create same file with same name
val file = File(requireContext().cacheDir, name)
val os = file.outputStream()
os.use {
inputStream.copyTo(it)
}
val bitmap = BitmapFactory.decodeFile(file.absolutePath)
}
}
}
}
Open an input stream for the obtained uri and then use BitmapFactory.decodeStream().
In Java:
InputStream is = getContentResolver().openInputStream(data.getData());
Bitmap bitmap = BitmapFactory.decodeStream(is);
That's all.
I know it seems like a very basic question, but it's specifically for Android Q.
I just want to get an image from Gallery and compress it and send to the server. But because of the Android Q's Scoped Storage, it's harder than I thought. I'll first explain what I did with code:
First I send out the intent to pick the image.
fun openGallery(fragment: Fragment){
val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
intent.type = "*/*"
val mimeTypes = arrayOf("image/*")
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes)
fragment.startActivityForResult(intent, REQUEST_IMAGE_PICK)
}
It works fine, and I'm able to get the image in the onActivityResult method
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == REQUEST_IMAGE_PICK && resultCode == Activity.RESULT_OK && null != data) {
val selectedImage = data.data
val source = ImageDecoder.createSource(activity!!.contentResolver, selectedImage)
val bitmap = ImageDecoder.decodeBitmap(source)
mBinding.circularProfileImage.setImageBitmap(bitmap)
}
}
Okay now the question is how can I access this image in File format, so I can further process/compress it.
Following things I've tried:
val mImagePath = getImagePathFromUri(activity!!, selectedImage)
This is the path I've got:
/storage/emulated/0/DCIM/Camera/IMG_20191022_152437.jpg
I created a file from it, in the following way:
val file = File(mImagePath)
And Following is my custom logic to compress and upload image:
val mNewFile = MediaCompressor.compressCapturedImage(activity!!, file, "ProfilePictures")
uploadProfile(mNewFile)
In this custom logic, I have a method to handle sampling and rotation of the image as follows:
fun handleSamplingAndRotationBitmap(context: Context, selectedImage: File, reqWidth: Int, reqHeight: Int): Bitmap {
val mUri = Uri.fromFile(selectedImage)
// First decode with inJustDecodeBounds=true to check dimensions
val options = BitmapFactory.Options()
options.inJustDecodeBounds = true
var imageStream = context.contentResolver.openInputStream(mUri)
BitmapFactory.decodeStream(imageStream, null, options)
imageStream!!.close()
// Calculate inSampleSize
options.inSampleSize =
calculateInSampleSize(options, reqWidth, reqHeight)
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false
imageStream = context.contentResolver.openInputStream(mUri)
var img = BitmapFactory.decodeStream(imageStream, null, options)
img = rotateImageIfRequired(context, img!!, mUri)
return img
}
But when I'm trying to open the stream using context.contentResolver.openInputStream
I get the following error:
java.io.FileNotFoundException: /storage/emulated/0/DCIM/Camera/IMG_20191022_152437.jpg: open failed: EACCES (Permission denied)
I know I'm getting this because in Android 10 we don't have the permission to directly access files from external storage.
So, please help me figure this out, how can I use the image from external storage as a file in Android 10.
Note: I've all the required permissions, so that's not the issue
Following things I've tried:
There is no possible reliable getImagePathFromUri() implementation.
In this custom logic, I have a method to handle sampling and rotation of the image as follows:
You do not need a File in that function. After all, your very first statement in that function goes and creates a Uri from that File. So, replace the File parameter with the Uri that you have, and skip the Uri.fromFile() call.
how can I use the image from external storage as a file in Android 10.
You can't. And, as demonstrated above, you do not need it for what you are doing.
If you find yourself in some situation where you are stuck using some library or API that absolutely positively must have a File:
Open an InputStream on the content, using contentResolver.openInputStream(), as you are doing today
Copy the bytes from that InputStream to some FileOutputStream on a file that you can read/write (e.g., getCacheDir() on Context)
Use your copy with the library or API that requires a File
Create a Directory for data to be stored in Android/data/package name by:
private void createDir() {
String timeStamp = utils.currentTimeStamp();
File storageDir = getExternalFilesDir(null);
File image;
try {
image = File.createTempFile(timeStamp, ".png", storageDir);
Log.i("SANJAY ", "createDir: " + image.getPath());
} catch (IOException e) {
e.printStackTrace();
Log.i("SANJAY ", "createDir: " + e.getMessage());
}
}
now call the gallery intent:
intent = new Intent();
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
startActivityForResult(intent, 100);
In onActivityResult():
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (requestCode == 100) {
Uri mediaUri = data.getData();
//display the image
try {
InputStream inputStream = getBaseContext().getContentResolver().openInputStream(mediaUri);
Bitmap bm = BitmapFactory.decodeStream(inputStream);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
byte[] byteArray = stream.toByteArray();
bind.photo.setImageBitmap(bm);
//Log.i("SANJAY ", "onActivityResult: " + saveBitMap(this, bm));
uri = Uri.fromFile(saveBitMap(this, bm));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
}
the get the Uri from File using this method:
private File saveBitMap(Context context, Bitmap Final_bitmap) {
File pictureFileDir = new File(Environment.getExternalStorageDirectory()
+ "/Android/data/"
+ getApplicationContext().getPackageName()
+ "/"/*Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), ""*/);
if (!pictureFileDir.exists()) {
boolean isDirectoryCreated = pictureFileDir.mkdirs();
if (!isDirectoryCreated)
Log.i("SANJAY ", "Can't create directory to save the image");
return null;
}
String filename = pictureFileDir.getPath() + File.separator + System.currentTimeMillis() + ".jpg";
File pictureFile = new File(filename);
try {
pictureFile.createNewFile();
FileOutputStream oStream = new FileOutputStream(pictureFile);
Final_bitmap.compress(Bitmap.CompressFormat.PNG, 18, oStream);
oStream.flush();
oStream.close();
Log.i("SANJAY ", "saveBitMap :: Save Image Successfully..");
} catch (IOException e) {
e.printStackTrace();
Log.i("SANJAY", "There was an issue saving the image.");
Log.i("SANJAY", "Error :: " + e.getLocalizedMessage());
}
return pictureFile;
}
I trying to develop an android application that enables the user to add a picture from his gallery, it works fine and displays the picture in the image view.
the problem is I am trying to save this picture in MySQL database (not URL or path of it) I want to store as a blob.
I tried the below code to get the image from user's gallery and display it in the image view.
The attribute test2 is a string and it is what I save in the database
if (requestCode == GET_FROM_GALLERY && resultCode == Activity.RESULT_OK && data != null) {
Uri selectedImageUri = data.getData();
imagepath = getPath(selectedImageUri);
}
////// edit
Bitmap image = BitmapFactory.decodeFile(imagepath);
FinalBytes = getBytes(image); // this will be save in DB
Bitmap getIt = getBitmap(FinalBytes);
imgV.setImageBitmap(getIt);
imgV.setDrawingCacheEnabled(true);
imgV.buildDrawingCache();
Bitmap testbit = imgV.getDrawingCache();
ByteArrayOutputStream testbyte = new ByteArrayOutputStream();
testbit.compress(Bitmap.CompressFormat.JPEG, 100, testbyte);
testbyte2 = testbyte.toByteArray();
base64Image = Base64.encodeToString(testbyte2, Base64.DEFAULT);
I used below code for retrieving the image
byte[] decodedString = Base64.decode(Recipes[position].getRimage(), Base64.DEFAULT);
Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
holder.image.setImageBitmap(decodedByte);
But I am getting this message when decoding it.
illegalargumentexception bad base 64
please help I spent 2 days on this error
I am trying to display an image from a local URI when this activity begins.
The user selects an image, triggering the OnActivityResult() method. When I first obtain the URI, it displays the image with no problem:
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
if (requestCode == IMG_REQUEST_CODE && resultCode == Result.Ok)
{
Android.Net.Uri imageUri = null;
if (data != null)
{
imageUri = data.Data;
userPreferences.BackgroundImageURI = imageUri.ToString();
imgView.SetImageURI(imageUri);
imgView.Visibility = ViewStates.Visible;
}
}
}
As you can see, I am storing the URI as an encoded string in userPreferences. This is saved to the device, and can be loaded with no issue. In this case the string is content://com.android.providers.media.documents/document/image%3A38, and it is identical when loaded from memory (using Shared Preferences).
Here is my code for loading the encoded URI string, parsing the string to create a URI, and then setting URI of imgView to display that image.
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Preferences);
userPreferences = Helpers.LoadUserPreferences(this, new Shared.Model.UserPreferences());
imgView = FindViewById<ImageView>(Resource.Id.imgView);
if (!string.IsNullOrWhiteSpace(userPreferences.BackgroundImageURI))
{
var imgURI = Android.Net.Uri.Parse(userPreferences.BackgroundImageURI);
imgView.SetImageURI(imgURI);
imgView.Visibility = ViewStates.Visible;
}
else
{
imgView.Visibility = ViewStates.Invisible;
}
}
When it gets to the SetView(imgUri) line, I receive this output: resolveUri failed on bad bitmap uri: content://com.android.providers.media.documents/document/image%3A38
I have even tried hard-coding the URI to no avail. The main frustration is that the code is identical, just running in two different scenarios. Is it possible that it has to do with the Activity lifecycle? Or have I missed something bigger?
Try this:
if (!string.IsNullOrWhiteSpace(userPreferences.BackgroundImageURI))
{
var imgURI = Android.Net.Uri.Parse(userPreferences.BackgroundImageURI);
var input = Activity.ContentResolver.OpenInputStream(imgURI);
imgView.SetImageBitmap(BitmapFactory.DecodeStream(input));
imgView.Visibility = ViewStates.Visible;
}
else
{
imgView.Visibility = ViewStates.Invisible;
}
As alternative I have a class that get the real path for the image from a URI. It could be great if you want to give that path to a CropActivity for example.
You can download the class from here.
And use it like this:
if (!string.IsNullOrWhiteSpace(userPreferences.BackgroundImageURI))
{
var imgURI = Android.Net.Uri.Parse(userPreferences.BackgroundImageURI);
imgView.SetImageURI (Uri.Parse(PathUtils.PathUtils.GetPath(Activity, imgURI)));
imgView.Visibility = ViewStates.Visible;
}
else
{
imgView.Visibility = ViewStates.Invisible;
}