I am making a project that generates qr code. When user generates a qr code, A download button appears on the screen. If the user clicks this button. Application should save the image(qr code) to external storage. I only want to create a function to save the qr code. But i could not find any useful source. How can i save a bitmap to external storage?
use this function and pass bitmap on button click
from fragment
saveBitmapInStorage(bitmap!!, requireContext())
from activity
saveBitmapInStorage(bitmap!!, this)
main function
open fun saveBitmapInStorage(bitmap: Bitmap, context: Context) {
val filename = "QR_"+"${System.currentTimeMillis()}.jpg"
var fos: OutputStream? = null
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
context.contentResolver?.also { resolver ->
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, filename)
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpg")
put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
}
val imageUri: Uri? =
resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
fos = imageUri?.let { resolver.openOutputStream(it) }
}
} else {
val imagesDir =
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
val image = File(imagesDir, filename)
fos = FileOutputStream(image)
}
fos?.use {
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, it)
}
}
why I share because I'm using this code in my current project and its working for me
hope helpful for you.
Related
I am working with Android version 10.
I have enabled Permissions to Read & Write Storage
Device Name : Poco F1
Scenario: I have to capture a screenshot of the current layout and save it to internalStorage and preview that image to the user. Here users have an option to delete the image.
Here are the codes I am using to save & delete
Saving a screenshot:
//I will pass the bitmap here
fun saveBitmapToInternalStorage(bitmap: Bitmap?) {
bitmap?.let {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
saveBitmapToOlderDevice(it)
} else {
saveBitmapToNewerDevice(it)
}
}
}
//This method is to save image to newerdevice >= Q
#RequiresApi(Build.VERSION_CODES.Q)
private fun saveBitmapToNewerDevice(bitmap: Bitmap) {
val uri = generateUri()
context.contentResolver.openOutputStream(uri ?: return).use { outputStream ->
outputStream?.let {
writeBitmapToJpeg(bitmap, outputStream, uri.toString())
}
}
}
//This is to generate the URI.
#RequiresApi(Build.VERSION_CODES.Q)
private fun generateUri(): Uri? {
val dateFormat = getDateFormat()
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, "${dateFormat}.jpg")
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
put(MediaStore.MediaColumns.RELATIVE_PATH, "Pictures/${context.resources.getString(R.string.app_name)}")
}
return context.contentResolver.insert(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
contentValues
)
}
// To save images to olderDevice
private fun saveBitmapToOlderDevice(bmp: Bitmap) {
val filename = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)?.absolutePath +
"/${context.resources.getString(R.string.app_name)}/${getDateFormat()}.jpg"
createDirectory(filename)
val outputStream = FileOutputStream(filename)
writeBitmapToJpeg(bmp, outputStream, filename)
}
//This method is to save the image to InternalStorage
private fun writeBitmapToJpeg(bmp: Bitmap, outputStream: OutputStream, imagePath: String) {
try {
val outputData = ByteArrayOutputStream()
bmp.compress(CompressFormat.JPEG, 100, outputData)
outputData.writeTo(outputStream)
outputStream.flush()
outputStream.close()
} catch (e: IOException) {
showBitmapWriteErrorMessage()
}
}
I save the path while storing the image in internalStorgae
the path looks like
/storage/emulated/0/Pictures/TGP AR/20211011142001.jpg
and i pass this path into below method
To delete the image :
private fun deleteImage(imagePath: String) {
val file = File(imagePath)
file.delete()
}
file.exists() is returning true.
file.delete() is returning false.
I think, there might be two different ways to delete ( > & < Q ).
Please help me
You can delete the image by modifying your method to the following:
private fun deleteImage(imagePath: Uri) {
getContentResolver().delete(imagePath, null, null)
}
Then pass the Uri created in generateUri() to delete the file.
My app has an extract button that takes the data from text view and paste it in a text file "Ledger.txt". It creates a folder in Mobile internal Storage Root Directory "WaterLedger" and place a Ledger.txt file in it and if the text file is already present it appends the text in the file. The code is only working till android 9 not above.
In Android 10 on pressing Extract button it asks "grant permission to write file in storage" but even if you press Yes it still wont create folder (WaterLerger) and paste/update data in Text File (Ledger.txt)
Here is the code
class WriteFile: AsyncTask<String, Int, String>() {
private val mFolder = "/WaterLedger"
lateinit var folder: File
internal var writeThis = "string to cacheApp.txt"
internal var cacheApptxt = "Ledger.txt"
override fun doInBackground(vararg writethis: String): String? {
val received = writethis[0]
if(received.isNotEmpty()){
writeThis = received
}
folder = File(Environment.getExternalStorageDirectory(),"$mFolder/")
if(!folder.exists() || folder.exists()){
folder.mkdir()
val readME = File(folder, cacheApptxt)
val file = File(readME.path)
val out: BufferedWriter
try {
out = BufferedWriter(FileWriter(file, true), 1024)
out.write("****Ledger Updated On Dated:$currentDate*****\n")
out.newLine()
out.write(writeThis)
out.newLine()
out.close()
Log.d("Output_Success", folder.path)
} catch (e: Exception) {
Log.d("Output_Exception", "$e")
}
}
return folder.path
}
// Driver Code
extract.setOnClickListener {
var pathToFileCreated = ""
val anRW = ReadandWrite().readAndwriteStorage(this, this)
if (anRW) {
pathToFileCreated = WriteFile().execute("$StringBuilder").get()
Log.d("pathToFileCreated", pathToFileCreated)
Toast.makeText(this,"File Saved",android.widget.Toast.LENGTH_LONG).show()
}
This will give you External Pictures directory URI (You can create your desirable directory into it):
private fun createTextURI(): Uri? {
val imageCollection = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
else
MediaStore.Video.Media.EXTERNAL_CONTENT_URI
val fileName = System.currentTimeMillis()
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, "$fileName.txt")
put(MediaStore.MediaColumns.MIME_TYPE, "text/plain")
}
val finalURI = contentResolver.insert(imageCollection, contentValues)
resultUri = finalURI
return finalURI
}
Use this URI for file creation like this:
new File(finalURI.getPath());
And write into this file which you created above. ✌
Make sure you have WRITE_EXTERNAL_STORAGE permission.
Ref. Demo App
I am try to take photo in private folder and save to public media store.
val takePictureContract = registerForActivityResult(ActivityResultContracts.TakePicture()) { success ->
if (success) {
uri?.let { fileUri ->
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, "pic_${System.currentTimeMillis()}")
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
}
val mediaUri = contentResolver.insert(
MediaStore.Images.Media.INTERNAL_CONTENT_URI,
contentValues
)
mediaUri?.let { mUri ->
contentResolver.openOutputStream(mUri)?.use { os ->
contentResolver.openInputStream(fileUri)?.use { inputStream ->
inputStream.copyTo(os)
}
}
}
}
}
}
fun takePic() {
val currentTimeMillis = System.currentTimeMillis()
val folder = File(filesDir, "images")
val file = File(folder, "pic_${currentTimeMillis}")
folder.mkdirs()
uri = FileProvider.getUriForFile(this, "${packageName}.provider", file)
takePictureContract.launch(uri)
}
But after take photo, I have this error message. What's wrong with my code?
Error message I get is :
java.lang.UnsupportedOperationException: Writing to internal storage is not supported
If change INTERNAL_CONTENT_URI to EXTERNAL_CONTENT_URI, and require permission WRITE_EXTERNAL_STORAGE, I can save photo success.
So I have the following code:
fun saveMediaToStorage(bitmap: Bitmap, context: Context) {
val filename = "${System.currentTimeMillis()}.jpg"
var fos: OutputStream? = null
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
context.contentResolver?.also { resolver ->
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, filename)
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpg")
put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
}
val imageUri: Uri? =
resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
fos = imageUri?.let { resolver.openOutputStream(it) }
}
} else {
val imagesDir =
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
val image = File(imagesDir, filename)
fos = FileOutputStream(image)
}
fos?.use {
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, it)
}
}
I have the permission in the manifest file:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
As well as the attribute:
android:requestLegacyExternalStorage="true"
I see the image saved in the proper location when using a FileExplorer app, but the Gallary app doesn't recognize it.
Does anyone notice something that I've done wrong or missed?
So, I need to save image to the Picture folder. There will be some subfolders too. But every time I want to save an image it is giving this error:
Failed to create new mediaStore record
This is what I tried:
#RequiresApi(Build.VERSION_CODES.Q)
#Throws(IOException::class)
fun saveMediaToStorage(context: Context, bitmap: Bitmap, format: CompressFormat, fName: String, folderName: String, extension: String) {
//Generating a file name
val filename = if (fName.contains("png")) fName.replace(".png", "") else fName.replace(".jpg", "")
//Output stream
var fos: OutputStream? = null
val relativePath = Environment.DIRECTORY_PICTURES + File.separator + folderName
Log.d(TAG, "saveMediaToStorage: Relative Path: $relativePath")
//getting the contentResolver
context.contentResolver?.also { resolver ->
//Content resolver will process the contentvalues
val contentValues = ContentValues().apply {
//putting file information in content values
put(MediaStore.MediaColumns.DISPLAY_NAME, filename)
put(MediaStore.MediaColumns.MIME_TYPE, "image/$extension")
put(MediaStore.MediaColumns.RELATIVE_PATH, relativePath)
}
//Inserting the contentValues to contentResolver and getting the Uri
val imageUri= resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues) ?:
throw IOException("Failed to create new mediaStore record") // This line is triggering every time
//Opening an outputstream with the Uri that we got
fos = imageUri.let { resolver.openOutputStream(it) }
}
fos?.use {
//Finally writing the bitmap to the output stream that we opened
bitmap.compress(format, 100, it)
}
}
What I can understand is, the imageUri is coming null. But why so, afaik I am doing ok..
What can be the reason, where I am doing wrong.. Any help would be highly appreciated.