My old implementation to upload image to Firebase Storage in JPEG format without any compression
private fun sendToFirebase() {
if (imgUri != null) {
val fileRef = storageRef!!.child(username+ ".jpg")
....
// code to upload and read image url
}
}
Decided to write a image compression technique to compress image and then upload to Firebase Storage
Result : Achieved image compression technique, see below
Newly added code to compress image
URI to Bitmap
val bitmap = MediaStore.Images.Media.getBitmap(activity?.contentResolver, imgUri)
Method to compress Bitmap
private fun compressBitmap(bitmap: Bitmap, quality:Int):Bitmap{
val stream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.WEBP, quality, stream)
val byteArray = stream.toByteArray()
return BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size)
}
Bitmap compression Implementation
compressBitmap(bitmap, 80)
Query: How to upload same compressed image to Firebase storage
private fun sendToFirebase() {
if (imgUri != null) {
// code to convert uri to bitmap <start>
val bitmap = MediaStore.Images.Media.getBitmap(activity?.contentResolver, imgUri)
compressBitmap(bitmap, 80)
// code to convert uri to bitmap <end>
// old implementation
.....
}
}
You don't seem to be passing anything into your function for sendtoFirebase. i am posting code i have done to successfully upload.
you looking at compressing first so you would need this;
private fun compressBitmap(bitmap: Bitmap, quality: Int): Bitmap {
val stream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.WEBP,quality,stream)
val byteArray = stream.toByteArray()
arrayByte = byteArray
uploadFile(arrayByte)
return BitmapFactory.decodeByteArray(byteArray,0,byteArray.size)
}
in the above, uploadFile is the call for the firebase upload. i am passing the compressed bitmap into the function. the functional for upload looks as follows:
in below mImageURI is a companion object which is part of the URI passed for compression. you can remove the if statement below if you dont want to do the check
private fun uploadFile(data:ByteArray) {
if (mImageUri != null){
val storageref = imageref.child("put your image id here")
storageref.putBytes(data).addOnSuccessListener {
Handler().postDelayed({
progressbar.setProgress(0)
Toast.makeText(activity, "Upload Successful", Toast.LENGTH_LONG).show()
}
, 1000)
}.addOnFailureListener{e->
Toast.makeText(activity,e.message,Toast.LENGTH_LONG).show()
}.addOnProgressListener {taskSnapshot ->
val progress = (100.0 * taskSnapshot.bytesTransferred/taskSnapshot.totalByteCount)
progressbar.setProgress(progress.toInt())
}
}
else if(mImageUri == null) {
Toast.makeText(activity,"No File Selected",Toast.LENGTH_LONG).show()
}
}
You do not need to have the progress bar above. its just a nice visual for the user to have to see the progress of the upload if the file is large.
your really only need to ensure that you passing data into .putbytes
Edit: For your onActivity result if your code is similar to mine then use;
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK
&& data != null && data.getData() != null) {
mImageUri = data.getData()!!
image1.setImageURI(data.getData())
}
}
in the above image1 is a imageView on the current page to show the image selected.
Hope this helps
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.
I am opening my phones camera, taking a photo, showing a 50px snippet then saving an image into FirebaseFireStore Storage.
The image is very pixelated when I download it from FireStore. Can someone have a look at my code to see were I am going wrong please?
Perhaps I am saving the 50px image, whereas I would like to save the image that was taken from the camera.
Variable
val REQUEST_CODECAM = 200
var bitmapPhoto: Bitmap? = null
Open the Camera
binding!!.galleryContainer.setOnClickListener { v: View? ->
val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
startActivityForResult(cameraIntent, REQUEST_CODECAM)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_CODECAM && data != null){
bitmapPhoto = data.extras?.get("data") as Bitmap
// Image is shown in 50px ListView cell
binding!!.issueImage.setImageBitmap(data.extras?.get("data") as Bitmap)
//imageUri = data.data
//Picasso.get().load(imageUri).into(binding!!.issueImage)
}
}
Save Button Pressed...
fun saveImage(action: GenericAction?) {
val imageName = UUID.randomUUID().toString()
val imageReference = FirebaseStorage.getInstance().reference.child("partInfoImagesFolder").child(imageName)
val baos = ByteArrayOutputStream()
bitmapPhoto.compress(Bitmap.CompressFormat.JPEG, 100, baos)
val data = baos.toByteArray()
var uploadTask = imageReference.putBytes(data)
uploadTask.addOnFailureListener {
// Handle unsuccessful uploads
}.addOnSuccessListener { taskSnapshot ->
// taskSnapshot.metadata contains file metadata such as size, content-type, etc.
// ...
imageReference.downloadUrl.addOnCompleteListener { task1: Task<Uri?>? ->
if (task1 != null) {
if (task1.isSuccessful()) {
saveCollOfURLString = task1.getResult().toString()
action?.onCallback()
}
}
}
}
}
I'm trying to use TensorImage.load() to load a bitmap of picture the user took with the camera app. When I pass in the bitmap I get this error:
java.lang.IllegalArgumentException: Only supports loading ARGB_8888 bitmaps
This is my code for when I call the load function. First, it starts with the onActivityResult:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == CAMERA_REQUEST_CODE) {
if(Build.VERSION.SDK_INT < 28) {
val foodBitmap = MediaStore.Images.Media.getBitmap(this.contentResolver, Uri.fromFile(photoFile))
// pass this bitmap to the classifier
val predictions = foodClassifier.recognizeImage(foodBitmap, 0)
} else {
val source = ImageDecoder.createSource(this.contentResolver, Uri.fromFile(photoFile))
val foodBitmap = ImageDecoder.decodeBitmap(source)
// pass this bitmap to the classifier
val predictions = foodClassifier.recognizeImage(foodBitmap, 0)
}
}
}
In the recognizeImage function, I call a variable named inputImageBuffer which is of type TensorImage. I call the load function and pass the bitmap. This is where the application crashes. Can someone tell me how do I fix this?
I solved the issue by changing the bitmap configuration in simplest way.
Bitmap bmp = imageBitmap.copy(Bitmap.Config.ARGB_8888,true) ;
Here
ii - Bitmap is immutable therefore I have make a copy with Bitmap.Config.ARGB_8888 configuration and a new Bitmap with refrence,
for further reference
https://developer.android.com/reference/android/graphics/Bitmap.Config
For anyone else this is how I solved the issue by changing the bitmap configuration.
// Convert the image to a Bitmap
var bitmap: Bitmap? = null
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
val source = ImageDecoder.createSource(requireContext().contentResolver, uri!!)
bitmap = ImageDecoder.decodeBitmap(source)
bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true)
} else {
bitmap = MediaStore.Images.Media.getBitmap(requireContext().contentResolver, uri!!)
}
} catch (e: Exception) {
println("Could not convert image to BitMap")
e.printStackTrace()
}
This question already has answers here:
onActivityResult's intent.getPath() doesn't give me the correct filename
(2 answers)
Getting the Absolute File Path from Content URI for searched images
(2 answers)
Android - Get real path of a .txt file selected from the file explorer
(1 answer)
Closed 3 years ago.
I have an activity where the user can select an image/video from gallery. For images everything is working fine, however i'm struggling with videos.
This is how i call to open the gallery in case of videos:
fun getVideoFromGallery() {
if (Build.VERSION.SDK_INT < 19) {
var intent = Intent()
intent.type = "video/*"
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
intent.action = Intent.ACTION_GET_CONTENT
startActivityForResult(
Intent.createChooser(intent, "Select Picture")
, GALLERY_VIDEO
)
} else {
var videopicker = Intent(Intent.ACTION_OPEN_DOCUMENT);
videopicker.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
videopicker.addCategory(Intent.CATEGORY_OPENABLE)
videopicker.type = "video/*"
startActivityForResult(videopicker, GALLERY_VIDEO);
}
}
I receive the notification when the user selected the video in:
public override fun onActivityResult(requestCode:Int, resultCode:Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if(requestCode == GALLERY_VIDEO)
{
if (data != null)
{
val contentURI = data.data
try {
if (data.getData() != null) {
var videoURI = data.getData()
val cR = this#EnviarMultimediaActivity.getContentResolver();
val type = cR.getType(videoURI);
if(!type.isNullOrEmpty() && type.contains("video/", true)){
val videopath = videoURI.getPath()
val file = File(videopath)
Log.d(TAG, "Video uri: "+videoURI)
Log.d(TAG, "Video path: "+file.getAbsolutePath())
var videoCopy = File(Environment.getExternalStorageDirectory().absolutePath+ IMAGE_DIRECTORY + ((Calendar.getInstance().getTimeInMillis()).toString() + ".mp4"))
//file.copyTo(videoCopy, true)
copyVideoFile(file, videoCopy)
Glide
.with(this#EnviarMultimediaActivity)
.asBitmap()
.load(videoURI)
.into(object : CustomTarget<Bitmap>(){
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
val thumbnail = saveImage(resource)
val thumbnailUri = Uri.parse(thumbnail);
val videoCopyURI = Uri.parse(videoCopy.getPath())
listaFicherosEnviar.add(EnviarMultimediaFichero(null, false, 3, videoCopyURI, thumbnailUri))
adapterEnviarMultimediaImagen.swapData(listaFicherosEnviar)
}
override fun onLoadCleared(placeholder: Drawable?) {
}
})
}
}
}
catch (e: IOException) {
e.printStackTrace()
Toast.makeText(this#EnviarMultimediaActivity, "Failed!", Toast.LENGTH_SHORT).show()
}
}
}
}
My onActivityResult is bigger but i just pasted the relevant part for videos.
If i don't try to make the copy Glide created the thumbnail and is displayed in the view.
The problem is that the copy don't work, i tried the File method copyTo and also another method implemented that receive a copy source and copy destination as parameter.
private fun copyVideoFile(sourceFile: File, destFile: File){
if (!sourceFile.exists()) {
return;
}
val source = FileInputStream(sourceFile).getChannel();
val destination = FileOutputStream(destFile).getChannel();
if (destination != null && source != null) {
destination.transferFrom(source, 0, source.size());
}
if (source != null) {
source.close();
}
if (destination != null) {
destination.close();
}
}
The problem is that sourceFile.exists() returns false, so no copy is done.
I tried to lod path and uri and is this:
Video uri: content://com.android.providers.downloads.documents/document/36
Video path: /document/36
I'm a bit lost as i don't understand why if the uri is correct (as Glide works) i can't create a File and make a copy to another File.
I requested permission and in my manifest i have:
android.permission.WRITE_EXTERNAL_STORAGE
android.permission.CAMERA
android.permission.INTERNET
android.permission.READ_EXTERNAL_STORAGE
Later i have retrofit2 api that creates a post to the server where sends as multipart:
val requestBody: RequestBody = RequestBody.create(MediaType.parse("video/*"), file)
val multiPart: MultipartBody.Part = MultipartBody.Part.createFormData("file", file.name, requestBody)
val name = RequestBody.create(MediaType.parse("text/plain"), file.name);
This is why i need an instance of File. As said the copy is just a test, but the File instance i think is required (unless i have a different code in the retrofir2 api to add the file to the post request).
Any help is appreciated.
I want to get some info from barcode using my camera.
It works when I use png image downloaded from site, but when I try to get it work with a photo I took, it outputs me the empty array. Seems like I need to make some preps with the image in order to make it work.
Here is my code:
fun getTheBarCode(bitmap: Bitmap) {
val options = FirebaseVisionBarcodeDetectorOptions.Builder()
.setBarcodeFormats(
FirebaseVisionBarcode.FORMAT_AZTEC)
.build()
val detector = FirebaseVision.getInstance().getVisionBarcodeDetector(options)
val bm = BitmapFactory.decodeResource(getResources(), R.drawable.barcode) //this is the place where I can load my downloaded barcode to make everything work!
val newBitmap = Bitmap.createScaledBitmap(bitmap, 300, 500, false)
val image = FirebaseVisionImage.fromBitmap(newBitmap)
photoImage.setImageBitmap(newBitmap)
detector.detectInImage(image)
.addOnSuccessListener {
Log.d("Success", "Success")
//empty array here, when I take picture.
}
.addOnFailureListener {
Log.d("Failed", it.message)
}
}
This is how I get the image from the camera
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == CAMERA_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
val photo = data.extras.get("data") as Bitmap
getTheBarCode(photo)
}
}
Edit:
I've take a picture with my phone, scale it down to 1500x1000px and put it inside my app directory, then loaded it as a bitmap.
Still not working.
The approach you're using will only give you back thumbnail of photo (as per https://developer.android.com/training/camera/photobasics) ...that may not be sufficient for what you're trying to do. That link also contains info on how to get access to full size photo.