All I want to do is allow users to take a photo and then after they've finished filling out a form submit that photo and upload to server.
I think I need the image in bitmap form so I can convert to Base64 string.
I've tried multiple different things I've found but none of them are working. I either get directory errors or intent null errors.
class Register : AppCompatActivity(), View.OnClickListener {
var PlayerID = ""
var mCurrentPhotoPath = ""
var stuff: File? = null
private var filePath: Uri? = null
private val PICK_IMAGE_REQUEST = 1
#RequiresApi(Build.VERSION_CODES.O)
override fun onClick(v: View?) {
if(v === buttonLoadPicture)
showFileChooser()
else if (v == btn_register)
uploadFile()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
if (resultCode != RESULT_CANCELED) {
if (requestCode == PICK_IMAGE_REQUEST) {
val thumbnail = MediaStore.Images.Media.getBitmap(getContentResolver(), filePath)
PhotoImageView.setImageBitmap(thumbnail)
filePath = getRealPathFromURI(Uri.parse(filePath.toString()))
}
}
}
//////////////
fun getImageUri(inContext: Context , inImage: Bitmap): Uri {
val bytes = ByteArrayOutputStream()
inImage.compress(Bitmap.CompressFormat.PNG, 100, bytes)
val path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null)
return Uri.parse(path)
}
fun getRealPathFromURI(uri: Uri): Uri? {
val proj = arrayOf(MediaStore.Images.Media.DATA)
val cursor = getContentResolver().query(uri, proj, null, null, null)
cursor.moveToFirst()
val idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA)
return Uri.parse(cursor.getString(idx))
}
////////////////
#RequiresApi(Build.VERSION_CODES.N)
private fun showFileChooser() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.CAMERA),
1)
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
1)
}
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
startActivityForResult(intent, 1)
}
val jsonobject = JSONObject()
#RequiresApi(Build.VERSION_CODES.O)
private fun uploadFile() {
val progress: ProgressBar = progressBarR
progress.visibility= View.VISIBLE
val iStream = contentResolver.openInputStream(filePath)
val bitmap = BitmapFactory.decodeStream(iStream)
val baos = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos)
val m = baos.toByteArray()
val imageString = Base64.encodeToString(m,Base64.DEFAULT)
//get form data from register layout
jsonobject.put("FirstName", input_fname.text)
jsonobject.put("LastName", input_lname.text)
jsonobject.put("UserName", input_username.text)
jsonobject.put("Phone", input_phone.text)
jsonobject.put("DOB", input_DOB.text)
jsonobject.put("Photo", imageString)
jsonobject.put("Profile", input_profile.text)
jsonobject.put("Email", input_email.text)
jsonobject.put("Password", input_password.text)
jsonobject.put("ConfirmPassword", input_confirm.text)
var url = "https://elimination.azurewebsites.net/api/Account/Post"
val que = Volley.newRequestQueue(this#Register)
val req = JsonObjectRequest(Request.Method.POST, url, jsonobject,
Response.Listener<JSONObject>{
response -> response.toString()
//save PlayerID to val PlayerID
PlayerID = response.get("PlayerID").toString()
//save to sharedPreferences
val email = input_email.text.toString()
val mypref = getSharedPreferences(email, Context.MODE_PRIVATE)
val editor = mypref.edit()
editor.putString(email, PlayerID)
editor.apply()
val intent = Intent(this, Login::class.java)
startActivity(intent)
},
Response.ErrorListener{
response ->
Log.e("Something went wrong", response.toString())
})
//if server is slow
val socketTimeout = 30000 // 30 seconds
val policy = DefaultRetryPolicy(socketTimeout,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT)
req.setRetryPolicy(policy)
// Adding request to request queue
que.add(req)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_register)
buttonLoadPicture.setOnClickListener(this)
btn_register.setOnClickListener(this)
}
}
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
startActivityForResult(intent, 1)
You are invoking ACTION_IMAGE_CAPTURE without EXTRA_OUTPUT.
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
if (resultCode != RESULT_CANCELED) {
if (requestCode == PICK_IMAGE_REQUEST) {
val thumbnail = MediaStore.Images.Media.getBitmap(getContentResolver(), filePath)
PhotoImageView.setImageBitmap(thumbnail)
filePath = getRealPathFromURI(Uri.parse(filePath.toString()))
}
}
}
You are not using the Bitmap that you get back from ACTION_IMAGE_CAPTURE when you do not supply EXTRA_OUTPUT. Instead, you are looking in a filePath value that may well be null and certainly has nothing to do with the photo that the user's chosen camera app may have taken.
If you want to tell the camera app where to put a full-size photo, use EXTRA_OUTPUT. However, then, bear in mind that you are unlikely to be able to convert a full-size photo to base64, as you will run out of memory.
Related
I've recently started programming in Kotlin and cannot seem to add a profile picture to a user when registering it.
According to the code here, I can access to the gallery and retrieve the image information. The picture will appear on screen, but after registering the user the image url will not appear anywhere.
class RegisterUser : AppCompatActivity() {
private val database = FirebaseDatabase.getInstance()
private val auth: FirebaseAuth = FirebaseAuth.getInstance()
private val UserCreation = database.getReference("Usuarios")
private val pickImage = 100
private var imageUri: Uri? = null
lateinit var imageView: ImageView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_register_user)
Goback.setOnClickListener {
val Gobackou = Intent(this, MainActivity::class.java)
startActivity(Gobackou)
}
RegisterConfirm.setOnClickListener {
val SetUser = SetUser.text.toString()
val SetPass = setPass.text.toString()
val SetEmail = SetEmail.text.toString()
if (SetUser.isEmpty() && SetPass.isEmpty() && SetEmail.isEmpty()) {
Toast.makeText(this, "Faltan Campos", Toast.LENGTH_SHORT).show()
} else {
RegisterUserv2(SetEmail, SetPass, SetUser)
}
}
selectPP.setOnClickListener {
val intent = Intent(Intent.ACTION_PICK)
intent.type = "image/*"
startActivityForResult(intent, pickImage)
}
}
var selectedPhotoUri: Uri? = null
//guardar la foto de perfil
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK && requestCode == pickImage) {
val selectedPhotoUri = data?.data
val bitmap = MediaStore.Images.Media.getBitmap(contentResolver, selectedPhotoUri)
val bitmapDrawable = BitmapDrawable(bitmap)
userimg.setBackgroundDrawable(bitmapDrawable)
}
}
private fun RegisterUserv2(email: String, password: String, user: String) {
auth.createUserWithEmailAndPassword(email, password).addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
uploadimage()
UltrasaveUsuario(Usuarios(auth.currentUser!!.uid, user, password, email))
val Gobackou = Intent(this, MainActivity::class.java)
startActivity(Gobackou)
} else {
Toast.makeText(this, "Registro ERROR", Toast.LENGTH_LONG).show()
}
}
}
private fun UltrasaveUsuario(usuario: Usuarios) {
val mensajeFirebase = UserCreation.push()
usuario.id = mensajeFirebase.key ?: ""
mensajeFirebase.setValue(usuario)
}
private fun uploadimage(imageurl: String){
if (selectedPhotoUri == null) return
val filename = UUID.randomUUID().toString()
val ref = FirebaseStorage.getInstance().getReference("/images/$filename/")
ref.putFile(selectedPhotoUri!!)
.addOnSuccessListener {
ref.downloadUrl.addOnSuccessListener{
}
}
}
}
Since you are using firebase I will show you how to save firebase storage.
private fun uploadImage() {
if (mSelectedImageFileUri != null) {
val sRef: StorageReference = FirebaseStorage.getInstance().reference.child(
"users/ $uid/profile.jpg"
)
sRef.putFile(mSelectedImageFileUri!!)
.addOnSuccessListener { taskSnapshot ->
taskSnapshot.metadata!!.reference!!.downloadUrl
.addOnSuccessListener { url ->
}
}.addOnFailureListener {
//error
}
} else {
}
}
then you will take this picture using the user id to take .
firebase>storage to view the image
getImage
val sRef: StorageReference = FirebaseStorage.getInstance().reference.child(
"users/ $uid/profile.jpg"
)
sRef.downloadUrl.addOnSuccessListener {
Picasso.get().load(it).into(globalprofileImage)
}
Build.gradle
implementation 'com.squareup.picasso:picasso:2.71828'
https://www.youtube.com/watch?v=nNYLQcmB7AU&t=449s&ab_channel=SmallAcademy
I have a function that takes file name and its Uri then send that file to the server.
Here it is
private fun uploadFile(pdfname: String, anyfile: Uri) {
var iStream: InputStream? = null
val myurl = "https://apiurl"
var rQueue = Volley.newRequestQueue(this)
try {
iStream = contentResolver.openInputStream(anyfile)
val inputData = getBytes(iStream)
val volleyMultipartRequest: VolleyMultipartRequest = object : VolleyMultipartRequest(
Method.POST, myurl,
Response.Listener { response ->
try {
val jsonobject = JSONObject(String(response.data))
val returnmsg = jsonobject.getString("hua ki nhi")
if(returnmsg == "aish kro ho gya")
{
Toast.makeText(this, "File Uploaded Successfully", Toast.LENGTH_SHORT).show()
}
else{
Toast.makeText(this, "File Not Uploaded", Toast.LENGTH_SHORT).show()
}
dialog.cancel()
}catch (e: JSONException){
e.printStackTrace()
dialog.cancel()
}
},
Response.ErrorListener { error ->
Toast.makeText(
applicationContext,
error.message,
Toast.LENGTH_SHORT
).show()
dialog.cancel()
}) {
#Throws(AuthFailureError::class)
// override fun getParams(): Map<String, String>? {
// // params.put("tags", "ccccc"); add string parameters
// return HashMap()
// }
override fun getByteData(): Map<String, DataPart> {
val params: MutableMap<String, DataPart> = HashMap()
params["evidence_image"] = DataPart(pdfname, inputData)
return params
}
}
volleyMultipartRequest.retryPolicy = DefaultRetryPolicy(
0,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT
)
rQueue.add(volleyMultipartRequest)
} catch (e: FileNotFoundException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
}
}
#Throws(IOException::class)
fun getBytes(inputStream: InputStream?): ByteArray {
val byteBuffer = ByteArrayOutputStream()
val bufferSize = 1024
val buffer = ByteArray(bufferSize)
var len = 0
while (inputStream!!.read(buffer).also { len = it } != -1) {
byteBuffer.write(buffer, 0, len)
}
return byteBuffer.toByteArray()
}
But I have to pass the Uri 1 by 1 to upload to the server. That means I have to call for API every time to upload multiple files.
This is my code where I take multiple files from the user.
attachbtn.setOnClickListener {
val mimeTypes = arrayOf("image/*", "application/pdf")
val intent = Intent()
intent.type = "image/* | application/pdf"
intent.action = Intent.ACTION_GET_CONTENT
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes)
startActivityForResult(Intent.createChooser(intent, "Choose Picture"), 111)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 111 && resultCode == Activity.RESULT_OK) {
if (data?.clipData != null) {
Toast.makeText(this, "Multiple file selected", Toast.LENGTH_SHORT).show()
val mulfile = data.clipData!!
val itemcount = mulfile.itemCount
}
}
}
I have already Included VolleyMultipartRequest Class.
Please tell me a Way where I can send Multiple Files in one Request.
Thankyou.
So after searching Stackoverflow for hours I tried loads of methods and library's but not ONE of them was the answer to my problem.
The problem is as follows:
val videoPath = getVideoPathFromURI(getSelectedVideoUri(requestCode, data))
val videoBytes = FileInputStream(File(videoPath)).use { input ->
input.readBytes()
}
This part is what I've had in my code before I found out about the bug.
Two of the many methods I tried are as follows:
#Throws(IOException::class)
private fun InputStream.readAllBytes(): ByteArray {
val bufLen = 4 * 0x400 // 4KB
val buf = ByteArray(bufLen)
var readLen: Int = 0
ByteArrayOutputStream().use { o ->
this.use { i ->
while (i.read(buf, 0, bufLen).also { readLen = it } != -1)
o.write(buf, 0, readLen)
}
return o.toByteArray()
}
}
private fun getByteArray(videoPath: String): ByteArray {
val inputStream = FileInputStream(File(videoPath))
val buffer = ByteArrayOutputStream()
var nRead: Int
val byteData = ByteArray(16384)
while (inputStream.read(byteData, 0, byteData.size).also { nRead = it } != -1) {
buffer.write(byteData, 0, nRead)
}
return buffer.toByteArray()
}
The way I obtain my video's is through either one of the following two intents:
private fun selectMultipleVideos() {
globalContext.checkPersmissions(Arrays.asList(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.CAMERA)){ response ->
if(response){
showCameraChoiceDialog(options, DialogInterface.OnClickListener{ dialog, which ->
when(which){
0 -> {
val takeVideoIntent = Intent(MediaStore.ACTION_VIDEO_CAPTURE)
startActivityForResult(takeVideoIntent, ACTION_TAKE_VIDEO)
}
1 -> {
val intent = Intent(Intent.ACTION_PICK)
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
intent.setType("video/mp4")
startActivityForResult(intent, SELECT_VIDEOS)
}
}
})
}
}
}
My onActivityResult:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if(resultCode == RESULT_OK) {
if (requestCode == ACTION_TAKE_VIDEO) {
val videoUri = data!!.data
val filePath = getPath(globalContext, videoUri!!)
amountOfVideosUploaded++
val videoBytes = FileInputStream(File(filePath)).use { input -> input.readBytes() }
videoByteArray.add(LocalFile(filePath, videoBytes))
if (contentReminder.num_required_videos != amountOfVideosUploaded) {
if (localVideoArray.size != contentReminder.num_required_videos) {
localVideoArray.add("")
}
localVideoArray[amountOfVideosUploaded] = filePath
} else {
localVideoArray[0] = filePath
}
setupList()
videosDelivered.text = DataStorage.generalData.translations?.app__contentinbox__submit_video_label + " (" + amountOfVideosUploaded + "/" + contentReminder.num_required_videos + ")"
} else {
selectedVideos = getSelectedVideos(requestCode, data!!)
selectedVideo = getSelectedVideo(requestCode, data)
amountOfVideosUploaded++
val videoPath = getVideoPathFromURI(getSelectedVideoUri(requestCode, data))
val videoBytes = FileInputStream(File(videoPath)).use { input -> input.readBytes() }
videoByteArray.add(LocalFile(selectedVideo, videoBytes))
if (contentReminder.num_required_videos != amountOfVideosUploaded) {
if (localVideoArray.size != contentReminder.num_required_videos) {
localVideoArray.add("")
}
localVideoArray[amountOfVideosUploaded] = selectedVideos[i]
} else {
localVideoArray[0] = selectedVideos[i]
}
setupList()
videosDelivered.text = DataStorage.generalData.translations?.app__contentinbox__submit_video_label + " (" + amountOfVideosUploaded + "/" + contentReminder.num_required_videos + ")"
}
}
}
Some of my helper methods:
private fun getSelectedVideoUri(requestCode: Int, data: Intent): Uri {
return data.data!!
}
private fun getSelectedVideo(requestCode: Int, data:Intent): String {
var result : String = ""
val videoURI = data.data!!
val filePath = getPath(globalContext, videoURI)
result = filePath
return result
}
private fun getSelectedVideos(requestCode: Int, data:Intent): MutableList<String> {
val result : MutableList<String> = mutableListOf()
val videoURI = data.data!!
val filePath = getPath(globalContext, videoURI)
result.add(filePath)
return result
}
If it does NOT get an error I upload it to the server with the following method:
fun uploadVideoFiles(module: String, file: LocalFile, completionHandler: (path: String) -> Unit){
val params = HashMap<String, String>()
params["module"] = module
params["action"] = "uploadFiles"
val request = object : MultipartRequest(Method.POST, Router.getUploadUrl(), Response.Listener { response ->
try {
completionHandler(Gson().fromJson(String(response.data), FileResponse::class.java).data.file_path)
} catch (ignore: Exception){
showSnackbar("Er is iets fout gegaan", ERROR)
}})
{
override fun getParams(): MutableMap<String, String> {
return params
}
override fun getByteData(): MutableMap<String, DataPart> {
val attachment = HashMap<String, DataPart>()
val extension = ".mp4"
attachment["files"] = DataPart(generateCustomString() + extension, file.byteArray!!, MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.replace(".", ""))!!)
return attachment
}
}
request.retryPolicy = DefaultRetryPolicy(600000, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT)
volleyHelper.addToRequestQueue(request)
}
Now the error I get (for each of the methods shown + my own / and all the other methods I tried):
2021-08-13 11:57:19.726 31911-31911/nl.mycontent E/AndroidRuntime: FATAL EXCEPTION: main
Process: nl.mycontent, PID: 31911
java.lang.OutOfMemoryError: Failed to allocate a 268435472 byte allocation with 25165824 free bytes and 124MB until OOM, target footprint 163389616, growth limit 268435456
at java.util.Arrays.copyOf(Arrays.java:3161)
at java.io.ByteArrayOutputStream.grow(ByteArrayOutputStream.java:118)
at java.io.ByteArrayOutputStream.ensureCapacity(ByteArrayOutputStream.java:93)
at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:153)
at nl.mycontent.controller.video.VideoDetail.readAllBytes(VideoDetail.kt:199)
at nl.mycontent.controller.video.VideoDetail.onActivityResult(VideoDetail.kt:169)
at androidx.fragment.app.FragmentActivity.onActivityResult(FragmentActivity.java:170)
at android.app.Activity.dispatchActivityResult(Activity.java:8300)
at android.app.ActivityThread.deliverResults(ActivityThread.java:5353)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:5401)
at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:51)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2267)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:237)
at android.app.ActivityThread.main(ActivityThread.java:8167)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:496)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1100)
Now I'm hoping there is anyone who can tell me for all Android Versions (since each version has different access requirements for external storage and stuff nowadays) how I can read a file without getting the OOM exception but also most importantly WHY the solution works and WHERE it went wrong on my end.
If you're only trying to upload the video files, why not use a custom RequestBody which means you're not reading the entire file into memory? Like so:
class InputStreamRequestBody(
private val contentResolver: ContentResolver,
private val uri: Uri) : RequestBody()
{
override fun contentType(): MediaType? {
val contentType = contentResolver.getType(uri)
return contentType?.toMediaTypeOrNull()
}
override fun writeTo(sink : BufferedSink)
{
val input = contentResolver.openInputStream(uri)
input?.use { sink.writeAll(it.source()) }
?: throw IOException("Could not open URI")
}
}
Then in onActivityResult():
val reqBody = InputStreamRequestBody(requireContext().contentResolver, videoFileUri)
viewModel.uploadVideo(reqBody)
Then, depending on design pattern, upload your video in lets say a ViewModel:
fun uploadVideo(video: RequestBody) {
viewModelScope.launch(Dispatchers.IO + someExceptionHandler) {
val videoRequestBody = MultipartBody.Part.createFormData("video", "some_video", video)
val response = someRetrofitService.uploadVideo(videoRequestBody)
}
}
Where the Retrofit service method looks something like this:
#Multipart
#POST("api/v1/files/videos") suspend fun uploadVideo(
#Part video: MultipartBody.Part? = null)
On my app, users can save some notes with image. But, users can not save their notes without image. Thus image is compulsory to save their data. But ı want to change it. I want to allow them to save their note without image. How can ı do this ? This is my saveclcikbutton codes;
class TakeNotesActivity : AppCompatActivity() {
var selectedPicture: Uri? = null
var selectedBitmap: Bitmap? = null
private lateinit var db: FirebaseFirestore
private lateinit var auth: FirebaseAuth
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_take_notes)
auth = FirebaseAuth.getInstance()
db = FirebaseFirestore.getInstance()
}
fun putPictureClick(view: View) {
val popupMenu = PopupMenu(this, view)
val inflater = popupMenu.menuInflater
inflater.inflate(R.menu.secondmenu, popupMenu.menu)
popupMenu.show()
popupMenu.setOnMenuItemClickListener {
if (it.itemId == R.id.galleryImage) {
if (ContextCompat.checkSelfPermission(
this,
android.Manifest.permission.READ_EXTERNAL_STORAGE
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this,
arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE),
1
)
} else {
val intentToGallery =
Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
startActivityForResult(intentToGallery, 2)
}
}
if (it.itemId == R.id.capturePhoto) {
if (ContextCompat.checkSelfPermission(
this,
android.Manifest.permission.CAMERA
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this,
arrayOf(android.Manifest.permission.CAMERA),
10
)
} else {
openCamera()
}
}
if (it.itemId == R.id.cancel) {
Toast.makeText(applicationContext, "Canceled", Toast.LENGTH_LONG).show()
}
true
}
}
fun openCamera() {
val values = ContentValues()
values.put(MediaStore.Images.Media.TITLE, "New Picture")
values.put(MediaStore.Images.Media.DESCRIPTION, "From the Camera")
selectedPicture =
contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
// Camera Intent
val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, selectedPicture)
startActivityForResult(cameraIntent, 20)
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
if (requestCode == 1) {
if (grantResults.size > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
val intentToGallery =
Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
startActivityForResult(intentToGallery, 2)
}
}
if (requestCode == 10) {
if (grantResults.size > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
openCamera()
} else {
Toast.makeText(this, "Permission Denied", Toast.LENGTH_LONG).show()
}
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == 2 && resultCode == Activity.RESULT_OK && data != null) {
selectedPicture = data.data
try {
if (selectedPicture != null) {
if (Build.VERSION.SDK_INT >= 28) {
val source =
ImageDecoder.createSource(this.contentResolver, selectedPicture!!)
selectedBitmap = ImageDecoder.decodeBitmap(source)
imageButton.setImageBitmap(selectedBitmap)
} else {
selectedBitmap =
MediaStore.Images.Media.getBitmap(this.contentResolver, selectedPicture)
imageButton.setImageBitmap(selectedBitmap)
}
}
} catch (e: Exception) {
}
}
//called when image was captured from camera intent
if (requestCode == 20 && resultCode == Activity.RESULT_OK && data != null) {
imageButton.setImageURI(selectedPicture)
}
super.onActivityResult(requestCode, resultCode, data)
}
fun saveClick(view: View) {
//UUID -> Image Name
val uuid = UUID.randomUUID()
val imageName = "$uuid.jpg"
val storage = FirebaseStorage.getInstance()
val reference = storage.reference
val imagesReference = reference.child("images").child(imageName)
if (selectedPicture != null) {
imagesReference.putFile(selectedPicture!!).addOnSuccessListener { taskSnapshot ->
// take the picture link to save the database
val uploadedPictureReference =
FirebaseStorage.getInstance().reference.child("images").child(imageName)
uploadedPictureReference.downloadUrl.addOnSuccessListener { uri ->
val downloadUrl = uri.toString()
println(downloadUrl)
val noteMap = hashMapOf<String, Any>()
noteMap.put("downloadUrl", downloadUrl)
noteMap.put("userEmail", auth.currentUser!!.email.toString())
noteMap.put("noteTitle", titleText.text.toString())
noteMap.put("yourNote", noteText.text.toString())
noteMap.put("date", Timestamp.now())
db.collection("Notes").add(noteMap).addOnCompleteListener { task ->
if (task.isComplete && task.isSuccessful) {
finish()
}
}.addOnFailureListener { exception ->
Toast.makeText(
applicationContext,
exception.localizedMessage?.toString(),
Toast.LENGTH_LONG
).show()
}
}
}
}
}
}
I also try to add on saveClick fun the codes below but did not work. What should I do ?
fun saveClick(view: View) {
//UUID -> Image Name
val uuid = UUID.randomUUID()
val imageName = "$uuid.jpg"
val storage = FirebaseStorage.getInstance()
val reference = storage.reference
val imagesReference = reference.child("images").child(imageName)
if (selectedPicture != null) {
imagesReference.putFile(selectedPicture!!).addOnSuccessListener { taskSnapshot ->
// take the picture link to save the database
val uploadedPictureReference =
FirebaseStorage.getInstance().reference.child("images").child(imageName)
uploadedPictureReference.downloadUrl.addOnSuccessListener { uri ->
val downloadUrl = uri.toString()
println(downloadUrl)
val noteMap = hashMapOf<String, Any>()
noteMap.put("downloadUrl", downloadUrl)
noteMap.put("userEmail", auth.currentUser!!.email.toString())
noteMap.put("noteTitle", titleText.text.toString())
noteMap.put("yourNote", noteText.text.toString())
noteMap.put("date", Timestamp.now())
db.collection("Notes").add(noteMap).addOnCompleteListener { task ->
if (task.isComplete && task.isSuccessful) {
finish()
}
}.addOnFailureListener { exception ->
Toast.makeText(
applicationContext,
exception.localizedMessage?.toString(),
Toast.LENGTH_LONG
).show()
}
}
}
}else {
val noteMap = hashMapOf<String, Any>()
noteMap.put("userEmail", auth.currentUser!!.email.toString())
noteMap.put("noteTitle", titleText.text.toString())
noteMap.put("yourNote", noteText.text.toString())
noteMap.put("date", Timestamp.now())
db.collection("Notes").add(noteMap).addOnCompleteListener { task ->
if (task.isComplete && task.isSuccessful) {
finish()
}
}
}
}
}
So all your logic is basically wrapped up in that putFile success callback, which requires an image to be successfully stored and retrieved (?) before anything will be added to the database.
You need to break that logic up, so you can only run the parts you want to - like just running the database update part if you don't have an image, or running that part later once your image is successfully handled.
So really, you need a "store in database" function to handle the final writing - call that directly if you don't have an image, call it in the success callbacks if you do. I'm just going to pseudocode this but:
saveData(noteMap: Map) {
add note to DB
}
saveClick() {
create noteMap with basic, non-image details (email, title etc)
if image is null, call saveData(noteMap)
else do the image stuff:
onSuccess:
add the downloadUrl to noteMap
call saveData(noteMap)
}
I see you've made an edit with an else branch which creates the map sans url and writes it - you're basically almost there, just make it a function instead, and pass the map in!
I'm trying to upload an image to the server after clicking from the camera but the server returns
($_File) JSON Response after clicking the image from server and uploading
{
"data":78,
"status":true,
"files":
{
"photo":
{
"name":"IMG_20191108_115642_5386652903586463966.jpg",
"type":"",
"tmp_name":"",
"error":1,
"size":0
}
}
}
($_File) JSON Response after picking the image from Gallery and uploading
{
"data":79,
"status":true,
"files":
{
"photo":
{
"name":"Screenshot_20191108_081937_com.instagram.android.jpg",
"type":"*\/*",
"tmp_name":"C:\\xampp\\tmp\\php50A6.tmp",
"error":0,
"size":518164
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_pharmacy)
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) !=
PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) !=
PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(this, permission, REQUEST_PERMISSION)
}
next.setOnClickListener {
if (prescriptionid == "") {
Toast.makeText(
applicationContext,
"Select/Upload Prescription First",
Toast.LENGTH_LONG
).show()
} else {
intent = Intent(applicationContext, SelectAddressActivity::class.java)
imageFilePath = ""
imageView.setImageResource(R.drawable.ic_image)
imagedisplay.visibility = View.GONE
startActivity(intent)
}
}
if (imageFilePath == "") {
imagedisplay.visibility = View.GONE
} else {
imagedisplay.visibility = View.GONE
}
}
Camera Intent
private fun openCameraIntent() {
val pictureIntent = Intent(
MediaStore.ACTION_IMAGE_CAPTURE)
if (pictureIntent.resolveActivity(getPackageManager()) != null)
{
try
{
photoFile = createImageFile()
}
catch (ex:IOException) {}// Error occurred while creating the File
if (photoFile != null)
{
val photoURI = FileProvider.getUriForFile(this, packageName+".provider", photoFile)
pictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,photoURI)
startActivityForResult(pictureIntent,CAMERA_REQUEST_CODE)
}
}
}
GalleryIntent
private fun pickFromGallery() {
//Create an Intent with action as ACTION_PICK
val intent = Intent(Intent.ACTION_PICK)
// Sets the type as image/*. This ensures only components of type image are selected
intent.type = "image/*"
//We pass an extra array with the accepted mime types. This will ensure only components with these MIME types as targeted.
val mimeTypes = arrayOf("image/jpeg", "image/png")
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes)
// Launching the Intent
startActivityForResult(intent, GALLERY_REQUEST_CODE)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
imagedisplay.visibility = View.VISIBLE
when (requestCode) {
CAMERA_REQUEST_CODE -> {
if (resultCode == Activity.RESULT_OK) {
correct.visibility = View.VISIBLE
imageView.setImageBitmap(setScaledBitmap())
}
}
GALLERY_REQUEST_CODE -> {
//data.getData returns the content URI for the selected Image
if (resultCode == Activity.RESULT_OK) {
correct.visibility = View.VISIBLE
var selectedImage = data!!.data as Uri
var filePathColumn = arrayOf(MediaStore.Images.Media.DATA)
// Get the cursor
var cursor = getContentResolver().query(
selectedImage,
filePathColumn, null, null, null
);
// Move to first row
cursor!!.moveToFirst();
//Get the column index of MediaStore.Images.Media.DATA
var columnIndex = cursor.getColumnIndex(filePathColumn[0])
//Gets the String value in the column
var imgDecodableString = cursor.getString(columnIndex)
cursor.close()
// Set the Image in ImageView after decoding the String
Log.i("filepath", imgDecodableString)
imageFilePath = imgDecodableString
imageView.setImageBitmap(BitmapFactory.decodeFile(imgDecodableString))
}
}
else -> {
Toast.makeText(this, "Unrecognized request code", Toast.LENGTH_SHORT).show()
}
}
}
Code To Create image file
#Throws(IOException::class)
private fun createImageFile(): File {
// Create an image file name
val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
val storageDir: File = getExternalFilesDir(Environment.DIRECTORY_PICTURES) as File
return File.createTempFile(
"IMG_${timeStamp}_", /* prefix */
".jpg", /* suffix */
storageDir /* directory */
).apply {
// Save a file: path for use with ACTION_VIEW intents
imageFilePath = absolutePath
}
}
Code To Upload Image To Server
val file = File(imageFilePath)
//creating request body for file
var requestBody = file.asRequestBody("*/*".toMediaTypeOrNull())
// val requestFile = file.asRequestBody("*/*".toMediaTypeOrNull())
var photo = MultipartBody.Part.createFormData("photo", file.name, requestBody)
// RequestBody descBody = RequestBody.create(MediaType.parse("text/plain"), desc);
Log.e("requestFile", imageFilePath)
val uploadImage =
RetrofitCall.provideRetrofit().create(uploadPrescriptionApi::class.java)
uploadImage.uploadPrescription("Bearer ".plus(sharedPreference!!.token.toString()), photo)
.enqueue(object : Callback<UploadPhototPOJO> {
override fun onResponse(
call: Call<UploadPhototPOJO>,
response: Response<UploadPhototPOJO>
) {
if (response.body()!!.status!!) {
progressDialog!!.dismiss()
prescriptionid = response.body()!!.id.toString()
Log.i("id", prescriptionid.toString())
} else {
Toast.makeText(
applicationContext,
"Oops Something Went Wrong!! Try again",
Toast.LENGTH_LONG
).show()
progressDialog!!.dismiss()
}
}
override fun onFailure(call: Call<UploadPhototPOJO>, t: Throwable) {
// handle execution failures like no internet connectivity
Log.i("Faliure", t.toString())
}
})
}
The maximum allowed size for uploading files is 2Mb. As you mentioned in your comment the size of the photo being uploaded is 4Mb.
If you want to upload files greater than the size set, just open the php.ini file to increase the size.
Open C:/xampp/php/php.ini file in any one of your favorite text editors. Search for upload_max_filesize and change it the size. For example, 50Mb
upload_max_filesize = 50M
And also the maximum size of POST data that PHP will accept is 8Mb. If you want to extend it, search for post_max_size and increase the size.
Finally, don't forget to restart the Apache server.