I've found lots of answers related tothis in Java, supposedely a Kotlin solution would be very much like Java, but as in many other things, the devil is on the details, and there are some.
I have several Uris stores in the SQLite database I'm using, now I want to send this images to an API that will catch them along with other data. I'll send the info via POST.
So now, I want to load the Uri, as I do when I use an ImageView.setImageURI() that will take the Uri, convert to Bitmap and place it in the ImageView container.
How do I convert from that Uri to a Bitmap object, and then encode it to Base64 to send it to the API, using Kotlin code?
EDIT
I'm trying with Anupam's imageFileToBase64() which seems to be exactly what I want, now I'm having a problem, I got a FileNotFoundException. This is what I'm doing.
I recover the Uri string from the database, it is a string that reads: content://media/external/images/media/109, so I convert it to an Uri
val uri = Uri.parse(uri_string)
Then I get the real path, and convert it to File
val file = File(uri.path)
Finally I call the function
val base64 = imageFileToBase64(file)
I have tried both with uri.path and uri.toString() and got the same results.
uri.path = /external/images/media/109
uri.toString() = content:/media/external/images/media/109
So I got no idea on what to pass to the function.
These are Kotlin methods for the following -
1. Get the bitmap from assets
2. Save bitmap to a file
3. Get Base64 from bitmap
4. Encode File/Image to Base64
5. Decode Base64 to File/Image
// Get the bitmap from assets and display into image view
val bitmap = assetsToBitmap("tulip.jpg")
// If bitmap is not null
bitmap?.let {
image_view_bitmap.setImageBitmap(bitmap)
}
val imagePath = "C:\\base64\\image.png"
// Encode File/Image to Base64
val base64ImageString = encoder(imagePath)
println("Base64ImageString = $base64ImageString")
// Decoder Base4 to File/Image
decoder(base64ImageString, "C:\\base64\\decoderImage.png")
// Click listener for button widget
button.setOnClickListener{
if(bitmap!=null){
// Save the bitmap to a file and display it into image view
val uri = bitmapToFile(bitmap)
image_view_file.setImageURI(uri)
// Show a toast message
toast("Bitmap saved in a file.")
}else{
toast("bitmap not found.")
}
}
}
// Method to get a bitmap from assets
private fun assetsToBitmap(fileName:String):Bitmap?{
return try{
val stream = assets.open(fileName)
BitmapFactory.decodeStream(stream)
}catch (e:IOException){
e.printStackTrace()
null
}
}
// Method to save an bitmap to a file
private fun bitmapToFile(bitmap:Bitmap): Uri {
// Get the context wrapper
val wrapper = ContextWrapper(applicationContext)
// Initialize a new file instance to save bitmap object
var file = wrapper.getDir("Images",Context.MODE_PRIVATE)
file = File(file,"${UUID.randomUUID()}.jpg")
try{
// Compress the bitmap and save in jpg format
val stream:OutputStream = FileOutputStream(file)
bitmap.compress(Bitmap.CompressFormat.JPEG,100,stream)
stream.flush()
stream.close()
}catch (e:IOException){
e.printStackTrace()
}
// Return the saved bitmap uri
return Uri.parse(file.absolutePath)
}
// Method to get Base64 from bitmap
private fun imageFileToBase64(imageFile: File): String {
return FileInputStream(imageFile).use { inputStream ->
ByteArrayOutputStream().use { outputStream ->
Base64OutputStream(outputStream, Base64.DEFAULT).use { base64FilterStream ->
inputStream.copyTo(base64FilterStream)
base64FilterStream.flush()
outputStream.toString()
}
}
}
}
// Encode File/Image to Base64
private fun encoder(filePath: String): String{
val bytes = File(filePath).readBytes()
val base64 = Base64.getEncoder().encodeToString(bytes)
return base64
}
// Decode Base64 to File/Image
private fun decoder(base64Str: String, pathFile: String): Unit{
val imageByteArray = Base64.getDecoder().decode(base64Str)
File(pathFile).writeBytes(imageByteArray)
}
Related
I must upload image file by use retrofit
this is Api
#POST("/image")
suspend fun uploadImage(
#Body request: UploadImageRequest,
): Response<UploadImageResponse>
UploadImageRequest
data class UploadImageRequest(
#SerializedName("image") val image: String,
)
I implement get image in device storage
this is code that get image
private val imageResult = registerForActivityResult(
StartActivityForResult(),
) { result ->
if (result.resultCode == RESULT_OK) {
val imageUri = result.data?.data
imageUri?.let {
if (Build.VERSION.SDK_INT < 28) {
bitmap =
MediaStore.Images.Media.getBitmap(this.contentResolver, imageUri)
} else {
val source = ImageDecoder.createSource(this.contentResolver, imageUri)
bitmap = ImageDecoder.decodeBitmap(source)
}
}
binding.imageActivityChangeUserInformationUserProfile.setImageBitmap(bitmap)
}
}
I don't know how I can upload that image
I tried that image to string by use base64 encode
but encoding string is too long
I tried create temp image file in device storage.
But, changed policy, scoped storage?
I couldn't make a new file
my app sdk is 33
If you have a file and you want to upload that file then do not first make a bitmap out if it.
Certainly not if you then ask to save that bitmap to file as then you can start over again.
And pdf's and doc's let them convert to bitmap pretty bad.
So just upload the file.
Just the bytes of the file.
When I get the ImageURI from the edamam API and try to upload it it gives some errors, which I am not getting when I transform the BitMap I get when taking a picture and transform it into URI, I have tried to transform the ImageURI into Bitmap to pass it to the same function but that doesnt work. This below is the function that does work
fun bitmapToUri(imageBitmap: Bitmap, cacheDir: File): Uri {
val baos = ByteArrayOutputStream()
imageBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos)
data2 = baos.toByteArray()
val file = File(cacheDir, imageBitmap.toString())
// When calling it with imageBitmap.toString() each item has its image (before the same one repeated)
file.delete()
// Just in case there is another File
file.createNewFile()
val fileOS = FileOutputStream(file)
fileOS.write(data2)
fileOS.flush()
fileOS.close()
baos.close()
return file.toUri()
}
I am getting these errors
E/UploadTask: could not locate file for uploading:
https://www.edamam.com/food-img/28a/28ae0e32feff919253b2cd17c47d2f23.jpg
E/StorageException: StorageException has occurred.
An unknown error occurred, please check the HTTP result code and inner exception for server response.
Code: -13000 HttpResult: 0
E/StorageException: No content provider: https://www.edamam.com/food-img/28a/28ae0e32feff919253b2cd17c47d2f23.jpg
java.io.FileNotFoundException: No content provider: https://www.edamam.com/food-img/28a/28ae0e32feff919253b2cd17c47d2f23.jpg
This is the function I have to upload to Storage
private fun uploadImage() {
val name = binding.inputName?.editText?.text.toString()
val provider = binding.inputProvider?.editText?.text.toString()
val address = binding.inputStreet?.editText?.text.toString()
val fileName = "$name $provider $address"
Log.d("INFO IMAGE URI UPLOAD->>", imageUri.toString())
storage = FirebaseStorage.getInstance().getReference("images/$fileName")
storage.putFile(imageUri).addOnSuccessListener {
binding.imageButton.setImageURI(null)
}.addOnFailureListener {
Toast.makeText(this#NewItem, "Image Not Uploaded", Toast.LENGTH_SHORT).show()
}
}
And this is the value I'm passing to imageUri
imageUri = apiCallBody.listHints.first().food.image.toUri()
Which is this value
https://www.edamam.com/food-img/862/862434152a3191f30c889f10eb2989b0.jpg
The Firebase Storage SDK doesn't allow you to directly upload the contents of random http URLs like the one you're showing here. The putFile method requires a Uri from a ContentProvider that's serviced by an Android app on the device. That's not what you're doing here at all.
If you want to upload an image that exists outside your app, you will have to download it first locally, then upload the data that you downloaded using putBytes, putStream or putFile.
My Method of setting a selected Image to a image view to then be Uploaded is
private val ImageLauncher = registerForActivityResult(ActivityResultContracts.GetContent()){ uri: Uri? ->
uri?.let { binding.GroupImageAdd.setImageURI(uri)
ImageUri = uri
}
}
The Uri is a Local val
set when the images is selected from file
and then
fun UploadImage(UUid: String, uri: Uri, ImageType: String) {
val storageRef = FirebaseStorage.getInstance().reference
Log.d("URI", uri.toString())
val task = storageRef.child("**Image Directory").putFile(uri)
task.addOnSuccessListener {
Log.d("UploadImage", "Task Is Successful")
}.addOnFailureListener {
Log.d("UploadImageFail", "Image Upload Failed ${it.printStackTrace()}")
}
}
Unsure if this helps
I currently have a huge amount of PNGs in my assets folder. When i launch my app i retrieve the file path of each one and use it to convert to a bitmap when that specific png is needed like so
fun getImageBitmapFromAsset(assetManager: AssetManager, imagePath: String?): ImageBitmap {
val inputStream: InputStream
var bitmap: Bitmap
try {
inputStream = assetManager.open(imagePath!!)
bitmap = BitmapFactory.decodeStream(inputStream)
} catch (e: IOException) {
return emptyImageBitmap
}
return bitmap.asImageBitmap()
}
My question is can this be done with SVGs and how?
I want to send multiple images to my database using retrofit. I am using this code to select multiple images.
private val galleryLauncher =
registerForActivityResult(ActivityResultContracts.GetMultipleContents()) { list ->
//TODO convert all content uris to File
}
I have tried a bunch of image picker libraries but none of them works in my device (Android R).
How do I convert them to file? Please help.
Is there any other method to send images to server via Retrofit2?
I used this dependency
implementation "commons-io:commons-io:2.7"
And this method
private fun createFileFromUri(name: String, uri: Uri): File? {
return try {
val stream = context.contentResolver.openInputStream(uri)
val file =
File.createTempFile(
"${name}_${System.currentTimeMillis()}",
".png",
context.cacheDir
)
FileUtils.copyInputStreamToFile(stream, file) // Use this one import org.apache.commons.io.FileUtils
file
} catch (e: Exception) {
e.printStackTrace()
null
}
}
private val galleryLauncher =
registerForActivityResult(ActivityResultContracts.GetMultipleContents()) { list ->
//TODO convert all content uris to File
}
I have written a c# web service that returns a pdf in a stream of bytes as response. Once I make a call to the web-service from my android app, I will store the response in an array byte till here I will be able to do it. But after that I need to convert that byte array into pdf, I should be able to display that. I have a menu page in which once the button is pressed the call is made to the web service with file name and on click of button I should be able to open pdf. Is this possible? Or there is some other, better solution? I checked on the net for better understanding, but I was unable to find one that could help me understand better.
Thanks for the suggestion, but I don't have the pdf in hand, I just have the array bytes, which I got from the web service. So I now need to regenerate the pdf from this array of bytes and display it, but I am not getting how to do it.
Try following these steps
Convert byte array to InputStream
val inputStream = ByteArrayInputStream(byteArray)
Save InputStream as PDF file:
suspend fun saveInputStreamAsPdfFile(inputStream: InputStream, applicationContext: Context): File? {
var outputFile: File? = null
withContext(Dispatchers.IO) {
try {
val directory = ContextCompat.getExternalFilesDirs(applicationContext, "documents").first()
val outputDir = File(directory, "outputPath")
outputFile = File(outputDir, UUID.randomUUID().toString() + ".pdf")
if (!outputDir.exists()) {
outputDir.mkdirs()
}
val outputStream = FileOutputStream(outputFile, false)
inputStream.use { fileOut -> fileOut.copyTo(outputStream) }
outputStream.close()
} catch (e: Exception) {
// Something went wrong
}
}
return outputFile
}
Show PDF with PdfRenderer
var totalPdfPages: Int
fun showPdf(pdfFile: File) {
val input = ParcelFileDescriptor.open(pdfFile, MODE_READ_ONLY)
val renderer = PdfRenderer(input)
val wrapper = PdfRendererWrapper(renderer)
totalPdfPages = wrapper.getTotalPages()
showPdfPage(0)
}
fun showPdfPage(currentPageIndex: Int) {
val pageBitmap = wrapper.getBitmap(currentPageIndex)
imageView.setImageBitmap(pageBitmap) // Show current page
}