How to convert imageview to bytearray kotlin android
In java
Bitmap bitmap = ((BitmapDrawable)image.getDrawable()).getBitmap();
ByteArrayOutputStream stream=new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 90, stream);
byte[] image=stream.toByteArray();
return image
Here it is use java to kotlin converter.
val bitmap = (image.getDrawable() as BitmapDrawable).getBitmap()
val stream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.PNG, 90, stream)
val image = stream.toByteArray()
This may help you,
private fun imageToBitmap(image: ImageView): ByteArray {
val bitmap = (image.drawable as BitmapDrawable).bitmap
val stream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.PNG, 90, stream)
return stream.toByteArray()
}
Related
I get the following error when trying to iterate over the uploadTasks inside an addOnSuccessListener method.
java.lang.ClassCastException: com.google.firebase.storage.UploadTask$TaskSnapshot cannot be cast to com.google.firebase.storage.UploadTask
So how can i get the Download String of each Img inside addOnSuccessListener?
val baos = ByteArrayOutputStream()
val tasks = mutableListOf<UploadTask>()
listImg.forEach {
if(bitmap!!.byteCount != it.byteCount) {
val bitmap = it
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos)
val data = baos.toByteArray()
var uploadTask = spaceRef.putBytes(data)
tasks.add(uploadTask)
}
}
Tasks.whenAllSuccess<UploadTask>(tasks).addOnSuccessListener { uploadTasks ->
//uploadTasks has size of 2
val urls = mutableListOf<Uri>()
lifecycleScope.launch
{
//Error throws here
uploadTasks.forEach{
urls.add(it.await().storage.downloadUrl.await())
}
}
}
The type of whenAllSuccess is <TResult>, so you should use the result type of UploadTask (UploadTask.TaskSnapshot) instead:
Tasks.whenAllSuccess<UploadTask.TaskSnapshot>(tasks).addOnSuccessListener { uploadTasks ->
And then you can drop the the first await() on that last line:
urls.add(it.storage.downloadUrl.await())
Bonus: Don't block the main thread
Note that Tasks.whenAllSuccess() will block the main thread until all uploads succeed, meaning your UI might freeze while uploading files.
To avoid that, consider uploading your files with Coroutines:
val baos = ByteArrayOutputStream()
val urls = mutableListOf<Uri>()
lifecycleScope.launch {
listImg.forEach {
if(bitmap!!.byteCount != it.byteCount) {
val bitmap = it
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos)
val data = baos.toByteArray()
// Upload the image first
val taskSnapshot = spaceRef.putBytes(data).await()
// Get the download Url
val downloadUri = taskSnapshot.storage.downloadUrl.await()
// Add it to the list of Uris
urls.add(downloadUri)
}
}
}
I want to pick the images with the extension "bmp" through the intent. I have tried passsing the "image/bmp" but it didn't worked. So what's the working way to get the "bmp" extension images through the intent.
Convert it into a string. First you need to convert the file to a .jpg or .png file, (you will have to do this manually outside of code), then convert to bitmap:
Bitmap bmp = BitmapFactory.decodeFile( PathToFileString );
or
Bitmap bmp = BitmapFactory.decodeFileDescriptor( fileDescriptorObject );
then
fun encode(imageUri: Uri): String {
val input = activity.getContentResolver().openInputStream(imageUri)
val image = BitmapFactory.decodeStream(input , null, null)
// Encode image to base64 string
val baos = ByteArrayOutputStream()
image.compress(Bitmap.CompressFormat.JPEG, 100, baos)
var imageBytes = baos.toByteArray()
val imageString = Base64.encodeToString(imageBytes, Base64.DEFAULT)
return imageString
}
fun decode(imageString: String) {
// Decode base64 string to image
val imageBytes = Base64.decode(imageString, Base64.DEFAULT)
val decodedImage = BitmapFactory.decodeByteArray(imageBytes, 0,
imageBytes.size)
imageview.setImageBitmap(decodedImage)
}
Once you have your string, then put it into an intent:
val intent = Intent(this, YourClass::class.java)
intent.putExtra("image", yourString);
startActivity(intent)
i want request to Flask server.
so, i converted a img to JSON data in Kotlin(Android Studio)
Although JSON data is well sent and received from the server, the size of the transmitted data is five times larger than the original data.
what should i do to get exact data from server??
Simple Server Code(python)...
print(len(request.json['file']))
img_data = base64.b64decode(request.json['file'])
filename = 'received_now_starry_night.png'
with open(filename, 'wb') as f:
f.write(img_data)
dic = {
"msg":"hello"
}
return jsonify(dic)
Android Studio, kotlin Code...
val bitmap:Bitmap = BitmapFactory.decodeResource(resources, R.drawable.starry_night)
val bos:ByteArrayOutputStream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos)
val image:ByteArray = bos.toByteArray()
val base64Encoded = java.util.Base64.getEncoder().encodeToString(image)
val rootObject = JSONObject()
rootObject.put("file", base64Encoded)
To convert an image to Base64 String :
You can also create a resized Bitmap and compress it to decrease the size
private fun CreateImageStringFromBitmap(): String {
val bitmap:Bitmap = BitmapFactory.decodeResource(resources, R.drawable.starry_night)
val resized = Bitmap.createScaledBitmap(
bitmap:Bitmap, (desired width).toInt(),
(desired height).toInt(), true
)
val stream = ByteArrayOutputStream()
resized.compress(Bitmap.CompressFormat.PNG, 75, stream)
val byteArray: ByteArray = stream.toByteArray()
return Base64.encodeToString(byteArray, Base64.DEFAULT)
}
In android studio I used this code to convert image to byte array and send to server:
Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] byteArrayImage = baos.toByteArray();
String encodedImage = Base64.encodeToString(byteArrayImage, Base64.DEFAULT);
ServerService.sendProfileImage(encodedImage);
In node-js back-end I use this code to write data to file:
let imageBuffer = new Buffer.from(data.info, 'Base64');
fs.writeFile(fd, imageBuffer, (err, written) => {
if(err) {
callBack(err);
return;
} else{
fs.close(fd, () => {
callBack(null);
return;
});
}
})
Note: back-end works perfect with browser and saved images show correctly, > no problem; Android data is saved too, but image is not in correct format.
But some thing is wrong and Image is not a valid file.
The java code produces correct Base64 image String.
There might be an issue while sending this string to your server. Try to print your base64 string on the server end to check whether you are getting full string from the request or not. if the string is correct then try following code to save the image
app.post('/save-image', (req, res) => {
require("fs").writeFile("out.jpg", req.body.info, 'base64', function(err) {
console.log(err);
});
})
The above code uses body-parser package to access the info field.
This is my code which i've used in Android
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Bundle
import android.util.Base64
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
import okhttp3.*
import java.io.ByteArrayOutputStream
import java.io.IOException
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
submit.setOnClickListener {
val bitmap = BitmapFactory.decodeResource(resources, R.drawable.out)
val baos = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos)
val imageBytes: ByteArray = baos.toByteArray()
val imageString = Base64.encodeToString(imageBytes, Base64.DEFAULT)
send(imageString)
}
}
private fun send(imageString: String) {
val body = FormBody.Builder()
body.add("info",imageString)
val request = Request.Builder().url("http://192.168.1.4:3000/save-image").post(body.build())
OkHttpClient.Builder().build().newCall(request.build()).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
Log.e("Failure",Log.getStackTraceString(e))
}
override fun onResponse(call: Call, response: Response) {
Log.e("response",response.body?.string() ?: "failed")
}
})
}
}
I'm trying to use Kotlin Coroutines for better performance.
But I'm not sure is it the correct way to use it, so I'd like to have experts review.
After taking a photo with camera, the screen is the blackout for half second while the image processing I guess.
The original code was,
fun uploadPhoto(data: Intent): Observable<Response> {
val bitmap = data.extras.get("data") as Bitmap
val bytes = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytes)
val baseDir = Environment.getExternalStorageDirectory()
val file = File(baseDir, Calendar.getInstance().timeInMillis.toString() + ".jpg")
val fileOutputStream = FileOutputStream(file)
fileOutputStream.write(bytes.toByteArray())
fileOutputStream.close()
return uploadMedia(file)
}
and after I read this tutorial, https://kotlinlang.org/docs/tutorials/coroutines-basic-jvm.html
I changed it to,
fun uploadPhoto(data: Intent): Observable<Response> {
val baseDir = Environment.getExternalStorageDirectory()
val file = File(baseDir, Calendar.getInstance().timeInMillis.toString() + ".jpg")
launch {
val bitmap = data.extras.get("data") as Bitmap
val bytes = compressBitMap(bitmap).await()
val fileOutputStream = FileOutputStream(file)
fileOutputStream.write(bytes.toByteArray())
fileOutputStream.close()
}
return uploadMedia(file)
}
private fun compressBitMap(bitmap: Bitmap) = async(CommonPool) {
val bytes = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytes)
return#async bytes
}
But I don't see any difference.
What I want to do thing is, I want to run Compressing Bitmap and fileOutputStream jobs in Background to prevent bothering MainThread.
Does it make the better performance?
Coroutines are executed in "CoroutineContexts", you appear to be using an older version of the libs, in newer versions you should always specify the context by using launch(UI) or launch(CommonPool). I don't know by default which context is your "launch" using, but I guess is UI.
If that's correct, you are in deed waiting in the UI thread for the compressBitMap completion, blocking the UI thread (A pointless coroutine use)
Try to use launch(CommonPool) instead and see if the magic happens.