I want to convert a Uri from the .takePicture method to a Bitmap for later use, I searched for different methods but each gaved me an error saying that the bitmap is null and sometimes "int android.graphics.bitmap.getwidth()' on a null object reference".
var imageUri:Uri?=null
private fun takePhoto() {
val photofile = File(externalMediaDirs.firstOrNull(), "picture - ${System.currentTimeMillis()}.jpg")
val output = ImageCapture.OutputFileOptions.Builder(photofile).build()
var image_View = findViewById<ImageView>(R.id.imageView)
imageCapture?.takePicture(output, ContextCompat.getMainExecutor(this), object : ImageCapture.OnImageSavedCallback {
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
Toast.makeText(applicationContext, "Pic saved.", Toast.LENGTH_LONG).show()
imageUri = outputFileResults.savedUri
//image_View.setImageURI(imageUri)
}
override fun onError(exception: ImageCaptureException) {
Toast.makeText(applicationContext, "Error saving pic!", Toast.LENGTH_LONG).show()
}
})
}
Try this snippet
Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageUri);
Quoting the documentation for getSavedUri():
This field is only returned if the ImageCapture.OutputFileOptions is backed by MediaStore constructed with #Builder(ContentResolver, Uri, ContentValues)
That is not the constructor that you are using for OutputFileOptions. So, check to see if getSavedUri() is returning null. If it is, you will need to use photofile, including taking steps to save that in the saved instance state Bundle.
If getSavedUri() is returning a non-null value, you might want to edit your question and supply the complete stack trace associated with your crash (rather than using a pastebin).
Related
everyone. I have an app in which I want to take a photo. I followed Google's guide (https://developer.android.com/codelabs/camerax-getting-started#1). However, I cannot take a photo. I can't get to the error function nor the success function within takePicture(). I use SDK 30.
private fun takePhoto() {
// Get a stable reference of the modifiable image capture use case
//Here the return is called
val imageCapture = imageCapture ?: return
// Create time stamped name and MediaStore entry.
val name = SimpleDateFormat(FILENAME_FORMAT, Locale.GERMAN)
.format(System.currentTimeMillis())
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, name)
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/CameraX-Image")
}
}
// Create output options object which contains file + metadata
val outputOptions = ImageCapture.OutputFileOptions
.Builder(contentResolver,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
contentValues)
.build()
// Set up image capture listener, which is triggered after photo has
// been taken
imageCapture.takePicture(
outputOptions,
ContextCompat.getMainExecutor(this),
object : ImageCapture.OnImageSavedCallback {
//Will never be called
override fun onError(exc: ImageCaptureException) {
Log.e(TAG, "Photo capture failed: ${exc.message}", exc)
}
//Will never be called
override fun
onImageSaved(output: ImageCapture.OutputFileResults){
val msg = "Photo capture succeeded: ${output.savedUri}"
Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
Log.d(TAG, msg)
}
}
)}
I'm making a card holder app, the user is supposed to take a picture of his id, contacts, notes etc. so he can later use them digitally. Problem is how do I take a camera input and save it as an image inside the application so it stays there?
You can simply use the native Camera Application of your device to get the image and then save it to the device . Android Team has done much easy for developers to perform such task.
You need to make use of ActivityContracts and MediaStore to take the image and store it into your device respectively.
Step 1 :
First Generate a Uri for your Image , in the following manner
#RequiresApi(Build.VERSION_CODES.Q)
suspend fun createPhotoUri(source: Source): Uri? {
val imageCollection = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
} else {
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
}
val dirDest = File(
Environment.DIRECTORY_PICTURES,
context.getString(R.string.app_name) + File.separator + "CAMERA"
)
val date = System.currentTimeMillis()
val fileName = "$date.jpg"
return withContext(Dispatchers.IO) {
val newImage = ContentValues().apply {
put(MediaStore.Images.Media.DISPLAY_NAME, fileName)
put(MediaStore.MediaColumns.RELATIVE_PATH, "$dirDest${File.separator}")
}
return#withContext context.contentResolver.insert(imageCollection, newImage)
}
}
Step 2:
Then when you want to capture the Image , then on the OnClickListener perform the following :
binding.takePictureButton.setOnClickListener {
viewLifecycleOwner.lifecycleScope.launch {
viewModel.createPhotoUri(Source.CAMERA)?.let { uri ->
actionTakePicture.launch(uri)
}
}
}
Step 3 :
The actionTakePicture ActivityContract is as follows :
private val actionTakePicture = registerForActivityResult(TakePicture()) { success ->
if (!success) {
Log.d(tag, "Image taken FAIL")
return#registerForActivityResult
}
Log.d(tag, "Image taken SUCCESS")
}
And you are done with capturing you Image and storing it .
Make sure you declare permission's before using the above code ,else it wont work .
The answer mentioned by #StefanoSansone can also be used . But the issue with that is you need to perfectly setup CameraX library and that might be tedious for your useCase . One should use library like CameraX if they want to have more control on Camera with other camera capabilities , when you application is more of a Camera Application . Else using the above method is perfectly fine . Saves one from tedious work .
If you are using Kotlin and Jetpack libraries, I suggest you to take a look to CameraX library.
You can use the takePicture method to take a photo with camera and save it in the storage.
A complete example can be found in the CameraX codelab
private fun takePhoto() {
// Get a stable reference of the modifiable image capture use case
val imageCapture = imageCapture ?: return
// Create time-stamped output file to hold the image
val photoFile = File(
outputDirectory,
SimpleDateFormat(FILENAME_FORMAT, Locale.US
).format(System.currentTimeMillis()) + ".jpg")
// Create output options object which contains file + metadata
val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()
// Set up image capture listener, which is triggered after photo has
// been taken
imageCapture.takePicture(
outputOptions, ContextCompat.getMainExecutor(this), object : ImageCapture.OnImageSavedCallback {
override fun onError(exc: ImageCaptureException) {
Log.e(TAG, "Photo capture failed: ${exc.message}", exc)
}
override fun onImageSaved(output: ImageCapture.OutputFileResults) {
val savedUri = Uri.fromFile(photoFile)
val msg = "Photo capture succeeded: $savedUri"
Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
Log.d(TAG, msg)
}
})
}
I had some difficulties last week with saving images.
I finally used sharedPreferences files and saved bitmap as text.
From what I've heard it's not a good practice, It's better to save in files and save the path.
However the code is very compact and it's working really well (in my case never have to load more than 4 pictures)
var bm= MediaStore.Images.Media.getBitmap(this.getContentResolver(), selectedImageUri)
bm.compress(Bitmap.CompressFormat.PNG, 100, baos) //bm is the bitmap object
val b = baos.toByteArray()
val encoded: String = Base64.encodeToString(b, Base64.DEFAULT)
editor.putString("backgroundBitmap",encoded)//put the bitmap as text in sharedPref files, use to back the bitmap in mainActivity
editor.commit()
My application uses the camera to take pictures and then saves them in the MediaStore. I would like to put these pictures in my RecyclerView using Glide but I don't know how to do it.
A function that saves the image:
private fun imageCapture() {
// Set desired name and type of captured image
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, "${what_is_that_insect_tv.text}")
put(MediaStore.MediaColumns.DATE_MODIFIED.format("MM/dd/yyyy"), (Calendar.getInstance().timeInMillis / 1000L))
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpg")
}
// Create the output file option to store the captured image in MediaStore
val outputFileOptions = ImageCapture.OutputFileOptions
.Builder(resolver, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
.build()
// Initiate image capture
imageCapture?.takePicture(
outputFileOptions,
cameraExecutor,
object : ImageCapture.OnImageSavedCallback {
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
// Image was successfully saved to `outputFileResults.savedUri`
}
override fun onError(exception: ImageCaptureException) {
val errorType = exception.imageCaptureError
Toast.makeText(requireContext(), "$errorType", Toast.LENGTH_SHORT).show()
}
})
}
Function in Adapter
fun bind(insect: Insect){
with(itemView){
name_insect_item.text = insect.name
Glide.with(this)
.load()
.into(this.image_insect_item)
}
}
In order to use Glide you must obtain the URI of the saved image, in the onImageSaved I believe you can call .getSavedUri() like so :
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
val uri = ImageCapture.OutputFileResults.getSavedUri()
}
You should then be able to use the Uri in an ArrayList you feed to the adaptor. Got it from here :
https://developer.android.com/reference/androidx/camera/core/ImageCapture.OutputFileResults#getSavedUri()
I do this in my code like this:
Glide.with(holder.imageView.getContext())
.load(new File(hotel.imageId2))
.into(holder.imageView)
also this might help:
RecyclerView- Glide
I have an activity from which I launch the gallery, select an image, and want to display the selected image in another activity. I have referred to the following solution and implemented the same.
How to get Image URI from Gallery?
Though I am able to pass the URI to the next activity, I cannot see anything on the image view. Any help as to where I am going wrong, appreciated.
btn_launch_gallery.setOnClickListener {
val requestCode = 0
val launchGalleryIntent = Intent(Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
startActivityForResult(launchGalleryIntent, requestCode)
}
My OnActivityResult looks like this, basically implemented the same as given in the example cited above.
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode === 0 && resultCode === Activity.RESULT_OK ) {
val selectedImage: Uri? = data?.data
val picturePath = getRealPathFromURI(
selectedImage,
this
)
val intent = Intent(this, LogFoodDetail::class.java)
intent.putExtra("image_from_gallery", picturePath)
try {
startActivity(intent)
}
catch (e: Exception)
{
e.printStackTrace()
Log.e("Error",e.printStackTrace().toString())
}
}
}
fun getRealPathFromURI(contentURI: Uri?, context: Activity): String? {
val projection =
arrayOf(MediaStore.Images.Media.DATA)
val cursor = context.managedQuery(
contentURI, projection, null,
null, null
)
?: return null
val column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
return if (cursor.moveToFirst()) {
// cursor.close();
cursor.getString(column_index)
} else null
// cursor.close();
}
In my next activity, I getting the intent like this and passing the URI to ImageView. However, I cannot see the image. I get the following error - W/System.err: java.io.FileNotFoundException: No content provider: /storage/emulated/0/DCIM/Camera/***.jpg
val resId = intent.getStringExtra("image_from_gallery")
val imgThumbnail: ImageView = findViewById(R.id.food_thumbnail)
try{
val imageStream: InputStream? = contentResolver.openInputStream(Uri.parse(resId))
val bitmap = BitmapFactory.decodeStream(imageStream)
imgThumbnail.setImageBitmap(bitmap)
}
catch (e: Exception)
{
e.printStackTrace()
}
I see the following image in the next activity:
UPDATE:
As commented by #blackapps in his answer passing the URI as a string to the next activity on an intent.putExtra() and resolving the URI in the subsequent activity solved it, the updated code in OnActivityResult() is,
...
val selectedImage: Uri? = data?.data
val intent = Intent(this, LogFoodDetail::class.java)
intent.putExtra("image_from_gallery",
selectedImage.toString())
startActivity(intent)
Dont convert a nice uri to a file system path.
Uri uri = data.getData();
Pass the obtained uri directly to the next activity.
And there you can use it for
imageView.setImageUri(uri);
Instead of the uri you can also pass the uri as string with uri.toString().
You can directly load an local image Uri using:
imgThumbnail.setImageUri(yourUri);
Instead of sending the string path to the activity, you should send the raw uri and then set it directly to the imageView.
In general, my task is to get base64 from chosen file. In order to open File Browser, I call following function:
private fun showFileBrowser() {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.setType("*/*")
startActivityForResult(intent, FILE_CHOOSE_REQUEST_CODE)
}
It is successfully opened. When some file is chosen, onActivityResult is called. Here it is:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == FILE_CHOOSE_REQUEST_CODE) {
// not that data.data is Uri
if(data != null && data.data != null) {
val encodedBase64 = getBase64FromPath(data.data.path)
print(encodedBase64)
}
}
}
Here is how I convert File to base64:
private fun getBase64FromPath(path: String): String {
try {
val bytes = File(path).readBytes()
return Base64.encodeToString(bytes, Base64.DEFAULT)
} catch (error: IOException) {
error.printStackTrace() // This exception always occurs
}
}
Seems like I do everything right, but I get FileNotFoundException. I don't know what is the reason for this. I didn't add any permission, because I don't to write anything to scared, I just want a user to choose a file, I will convert it to base64 and send it to the server. So, what is the problem this my code?
my task is to get base64 from chosen file
Your code has little to do with files. ACTION_GET_CONTENT is not limited to files on the device, let alone files on the filesystem that you can access.
When some file is chosen, onActivityResult is called
You get a Uri via onActivityResult(). A Uri is not a file, and getPath() on a Uri only has meaning if the scheme of that Uri is file. Most Uri values will have a scheme of content.
Replace your function with:
private fun getBase64ForUriAndPossiblyCrash(uri: Uri): String {
try {
val bytes = contentResolver.openInputStream(uri).readBytes()
return Base64.encodeToString(bytes, Base64.DEFAULT)
} catch (error: IOException) {
error.printStackTrace() // This exception always occurs
}
The AndPossiblyCrash portion of the function name is because you are going to run out of memory if the content is too large. Also note that you are doing this work on the main application thread, so your UI will be frozen while you are reading this in.