Reputation: 45
I've followed the android documentation on photos (https://developer.android.com/training/camera/photobasics#kotlin) to try and take a photo and save it. If I don't use EXTRA_OUTPUT I can successfully get the small image from data.extra, but I need a bigger picture. Using extra_output the same way they do in that link, I never get an actual photo saved, only 0 byte files. So something is going wrong with my extra_output, but I have no idea what. Any ideas?
I did find other people with similar issues, but no actual solution
class CameraFragment2 : Fragment() {
private lateinit var binding: CameraFragment2FragmentBinding
private lateinit var textRecognizer: TextRecognizer
private lateinit var photoFile: File
private lateinit var photoUri: Uri
companion object {
fun newInstance() = CameraFragment2()
}
private lateinit var viewModel: CameraFragment2ViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = CameraFragment2FragmentBinding.inflate(inflater)
textRecognizer = TextRecognizer.Builder(context).build()
dispatchTakePictureIntent()
return binding.root
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProvider(this).get(CameraFragment2ViewModel::class.java)
// TODO: Use the ViewModel
}
private fun dispatchTakePictureIntent() {
val packageManager = context!!.packageManager
Intent(Intents.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
Log.wtf("creating file failed", "creating file failed")
null
}
// Continue only if the File was successfully created
photoFile?.also {
val photoURI: Uri = FileProvider.getUriForFile(
context!!,
//BuildConfig.APPLICATION_ID + ".provider",
"com.example.myapplication.fileprovider",
it
)
takePictureIntent.putExtra(EXTRA_OUTPUT, photoURI)
takePictureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
takePictureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
startActivityForResult(takePictureIntent, 1)
}
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
//super.onActivityResult(requestCode, resultCode, data)
//val file = File(currentPhotoPath)
//val bitmap = BitmapFactory.decodeFile(currentPhotoPath)
//scan(bitmap)
val filePathUri = Uri.parse(currentPhotoPath)
val myFile = File(filePathUri.path)
val file_size = (myFile.length() / 1024).toString().toInt()
Log.wtf("path", currentPhotoPath)
Log.wtf("size", file_size.toString())
//val image = File(currentPhotoPath)
val bmOptions = BitmapFactory.Options()
bmOptions.inJustDecodeBounds = false
bmOptions.inSampleSize = 4
//var bitmap = BitmapFactory.decodeFile(image.absolutePath, bmOptions)
//scan(bitmap)
var thing: Bitmap
BitmapFactory.decodeFile(currentPhotoPath, bmOptions)?.also { bitmap ->
scan(bitmap)
thing = bitmap
}
if (resultCode == Intents.RESULT_OK && requestCode == 1){
//val photo = data!!.extras!!.get(EXTRA_OUTPUT) as Bitmap
//scan(photo)
//val bitmap = BitmapFactory.decodeFile(photoFile.absolutePath)
//scan(bitmap)
}
}
lateinit var currentPhotoPath: String
@Throws(IOException::class)
private fun createImageFile(): File {
// Create an image file name
val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
val storageDir: File = context!!.getExternalFilesDir(Environment.DIRECTORY_PICTURES)!!
return File.createTempFile(
"JPEG_${timeStamp}_", /* prefix */
".jpg", /* suffix */
storageDir /* directory */
).apply {
// Save a file: path for use with ACTION_VIEW intents
currentPhotoPath = absolutePath
}
}
private fun scan(photo: Bitmap){
//val intent = Intent(ACTION_IMAGE_CAPTURE)
val imageFrame = Frame.Builder()
.setBitmap(photo)
.build()
val detections = textRecognizer.detect(imageFrame)
val builder = StringBuilder()
if (detections.size() != 0){
for (x in 0..detections.size()) {
builder.append(detections[x].value)
builder.append("\n")
}
}
binding.camFragResult.text = builder
}
}
in my manifest:
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.example.myapplication.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"></meta-data>
</provider>
provider_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-files-path
name="my_images"
path="." />
</paths>
Upvotes: 2
Views: 1351
Reputation: 1
private fun dispatchTakePictureIntent() {
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
// Create the File where the photo should go
photoFile = createImageFile()
// Continue only if the File was successfully created
if(photoFile != null){
val photoURI: Uri = FileProvider.getUriForFile(
requireContext(),
"com.billsAplication.fileprovider", // Your package
photoFile!!)
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
}
if (requireContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) {
// Start the image capture intent to take photo
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)
}
}
Upvotes: 0
Reputation: 1006819
Your primary bug is is that you did not add FLAG_GRANT_WRITE_URI_PERMISSION
to your Intent
. You granted the user's chosen camera app read access, not write access. So, the camera app cannot write to your designated location.
In addition:
You will lose the value of currentPhotoPath
if your process is terminated while the camera app is in the foreground, which happens quite a bit
You might also consider cleaning up provider_paths.xml
(you have two conflicting entries)
Upvotes: 1