Convert data from image picker intent into bitmap (Kotlin)? - android

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.

Related

Convert image from gallery to bitmap. I get a NullPointerException

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().

How do I get the actual image taken from a camera in Android Studio?

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).

Save image path from gallery to Room DB, then load with Picasso not working

I've tried various solutions on SO for this problem, but so far not one of them has worked :/
I'm letting users pick a photo from a gallery, have the app display a preview, save the image with a caption to a Room DB and then display multiple images in a RecyclerView using Google's Material Design Card Views.
Picking an image and showing it in the preview is not a problem. But displaying the images in the RecyclerView using Picasso is not working. It only shows my error image (broken image vector).
The following code is used to pick an image from the gallery and display the preview image:
private fun choosePicture() {
var chooseFile = Intent(Intent.ACTION_GET_CONTENT)
chooseFile.type = MIME_TYPE_IMAGE
chooseFile = Intent.createChooser(chooseFile, resources.getString(R.string.choose_file))
startActivityForResult(chooseFile, PICK_FILE_RESULT_CODE)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
PICK_FILE_RESULT_CODE -> if (resultCode == -1) {
data!!.data?.let { returnUri ->
loadPicture(returnUri)
binding.constraintLayout.visibility = View.VISIBLE
viewModel.imagePath.value = returnUri
}
}
}
}
private fun loadPicture(uri: Uri) {
Picasso.get()
.load(uri)
.error(R.drawable.ic_broken_image_gray_24dp)
.into(binding.placeImage)
}
In my ViewHolder I'm using the following code to display the image (image path saved in Room DB as String):
fun bind(location: Location) {
textViewLocationName.text = location.name
Picasso.get()
.load(Uri.parse(location.imagePath!!))
.error(R.drawable.ic_broken_image_gray_24dp)
.into(imageViewLocation)
}
When debugging the URI looks like this: content://com.android.providers.media.documents/document/image%3A4569
Is there some kind of formatting issue with the URI? Or is there another problem?
Thanks!
Just in case anyone else has this problem, here's my solution:
Change the intent from ACTION_GET_CONTENT to ACTION_OPEN_DOCUMENT
Set the following flags for the intent:
chooseFile.flags = (Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
In onActivityResult use the following line of code before using the URI for anything else:
context?.contentResolver?.takePersistableUriPermission(returnUri, Intent.FLAG_GRANT_READ_URI_PERMISSION)

How can I automate taking and returning a pic

I've the below code working fine, that upon button click, the Camera intent is opened, allowing me to take a photo, then confirm the photo is ok, i.e. 2 interfaces from the user after clicking the button, till the pic is loaded in the image view.
Can I automate it, i.e. once the user click the button on the activity, camera intent is opened directly, take a photo of whatever there, and return what had been captured to the user.
mm, i.e. something like the apps working with take a selfie voice command.
My typical code for opening the camera intent is:
btnCamera.setOnClickListener { // I need this click to be the only thing done by the user
if(isPermissionGranted(permission.CAMERA)) startCamera()
else requestCameraPermission(this)
}
private fun startCamera() {
val fileName = System.currentTimeMillis().toString() + ".jpeg"
output = File(
this.getExternalFilesDir(Environment.DIRECTORY_PICTURES),
fileName
)
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
outPutFileUri = this.let { it ->
FileProvider.getUriForFile(
it,
BuildConfig.APPLICATION_ID,
output!!
)
}
intent.putExtra(MediaStore.EXTRA_OUTPUT, outPutFileUri)
startActivityForResult(intent, REQUEST_IMAGE_CAPTURE)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) = runBlocking {
super.onActivityResult(requestCode, resultCode, data)
val activity = this
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == Activity.RESULT_OK) {
val bitmap = outPutFileUri?.let { getCapturedImage(it) }
imageView.setImageBitmap(bitmap)
}
}
private fun getCapturedImage(selectedPhotoUri: Uri): Bitmap =
when {
Build.VERSION.SDK_INT < 28 -> MediaStore.Images.Media.getBitmap(
contentResolver, selectedPhotoUri)
else -> {
val source = ImageDecoder.createSource(contentResolver, selectedPhotoUri)
ImageDecoder.decodeBitmap(source)
}
}
The Camera will be opened, picture will be taken, user will see what is going on the screen,, mm if there is a way to take a pic without opening the camera app it will be welcomed as well. thanks
Can I automate it, i.e. once the user click the button on the activity, camera intent is opened directly, take a photo of whatever there, and return what had been captured to the user.
No.
You would need to implement your own camera app functionality for automated image capture, whether using the camera APIs directly or via a wrapper library (CameraX, Fotoapparat, CameraKit-Android, etc.).

How to convert a content Uri into a File

I know there are a ton of questions about this exact topic, but after spending two days reading and trying them, none seamed to fix my problem.
This is my code:
I launch the ACTION_GET_CONTENT in my onCreate()
Intent selectIntent = new Intent(Intent.ACTION_GET_CONTENT);
selectIntent.setType("audio/*");
startActivityForResult(selectIntent, AUDIO_REQUEST_CODE);
retrieve the Uri in onActivityResult()
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == AUDIO_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
if ((data != null) && (data.getData() != null)) {
audio = data.getData();
}
}
}
pass the Uri to another activity and retrieve it
Intent debugIntent = new Intent(this, Debug.class);
Bundle bundle = new Bundle();
bundle.putString("audio", audio.toString());
debugIntent.putExtras(bundle);
startActivity(debugIntent);
Intent intent = this.getIntent();
Bundle bundle = intent.getExtras();
audio = Uri.parse((String) bundle.get("audio"));
The I have implemented this method based on another SO answer. To get the actual Path of the Uri
public static String getRealPathFromUri(Activity activity, Uri contentUri) {
String[] proj = { MediaStore.Audio.Media.DATA };
Cursor cursor = activity.managedQuery(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
and in the Debug activity's onCreate() I try to generate the file:
File audioFile = new File(getRealPathFromUri(this, audio));
This is how the error looks like:
Caused by: java.lang.NullPointerException
at java.io.File.(File.java:262)
at com.dancam.lietome.Debug.onCreate(Debug.java:35)
When I run the app I get a NPE on this last line. The audio Uri, isn't NULL though so I don't understand from what it is caused.
I'd really appreciate if you helped me out.
This is the library I'm trying to work with.
Note: I know exactly what NPE is, but even debugging I couldn't figure out from what it is caused in this specific case.
pass the Uri to another activity and retrieve it
Your other activity does not necessarily have rights to work with the content identified by the Uri. Add FLAG_GRANT_READ_URI_PERMISSION to the Intent used to start that activity, and pass the Uri via the "data" facet of the Intent (setData()), not an extra.
To get the actual Path of the Uri
First, there is no requirement that the Uri that you get back be from the MediaStore.
Second, managedQuery() has been deprecated for six years.
Third, there is no requirement that the path that MediaStore has be one that you can use. For example, the audio file might be on removable storage, and while MediaStore can access it, you cannot.
How to convert a content Uri into a File
On a background thread:
Get a ContentResolver by calling getContentResolver() on a Context
Call openInputStream() on the ContentResolver, passing in the Uri that you obtained from ACTION_GET_CONTENT, to get an InputStream on the content identified by the Uri
Create a FileOutputStream on some File, where you want the content to be stored
Use Java I/O to copy the content from the InputStream to the FileOutputStream, closing both streams when you are done
I ran into same problem for Android Q, so I end up creating a new file and use input stream from content to fill that file
Here's How I do it in kotlin:
private var pdfFile: File? = null
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (resultCode == Activity.RESULT_OK) {
if (data != null) {
when (requestCode) {
REQUEST_CODE_DOC -> {
data.data?.let {
if (it.scheme.equals("content")) {
val pdfBytes =
(contentResolver?.openInputStream(it))?.readBytes()
pdfFile = File(
getExternalFilesDir(null),
"Lesson ${Calendar.getInstance().time}t.pdf"
)
if (pdfFile!!.exists())
pdfFile!!.delete()
try {
val fos = FileOutputStream(pdfFile!!.path)
fos.write(pdfBytes)
fos.close()
} catch (e: Exception) {
Timber.e("PDF File", "Exception in pdf callback", e)
}
} else {
pdfFile = it.toFile()
}
}
}
}
}
}
}
Daniele, you can get path of file directly from data like below in onActivityResult():
String gilePath = data.getData().getPath();

Categories

Resources