chuanpham
chuanpham

Reputation: 469

Resize image file before uploading to server using Retrofit2

I'm trying to uploading image to server using Retrofit, but now i'm facing a problem that the image's size is too large. Here is my code:

private fun uploadImageFileToApiServer(){
    Log.e("api", "start")
    var file: File?= null
    try{

        file = File(Common.getFilePath(this, selectedUri!!))
        Log.e("FilePath", file.toString())

    }catch(e: URISyntaxException) {e.printStackTrace()}


    if(file != null)
    {
        val requestBody = ProgressRequestBody(file, this)

        //how can i resize the image here before uploading it to server???


        val body = MultipartBody.Part.createFormData("image", file.name, requestBody)
        Thread(Runnable {
            mService.uploadFile(body) 
                .enqueue(object: Callback<String> {
                    override fun onFailure(call: Call<String>, t: Throwable) {
                        Toast.makeText(this@ApiProcessing, t.message, Toast.LENGTH_LONG).show()
                        Log.e("api", t.message!!)
                    }

                    override fun onResponse(call: Call<String>, response: Response<String>) {
                        val stringResponse = response.body()?.toString()

                        try {
                            val jsonObject = JSONObject(stringResponse)
                            val label = jsonObject.getString("label")
                            val width = jsonObject.getString("width")
                            val height = jsonObject.getString("height")
                            HaveFruitResult.label = label
                            HaveFruitResult.width = width
                            HaveFruitResult.height = height
                 
                        }
                        catch (e: NullPointerException){
                            Toast.makeText(this@ApiProcessing, e.message, Toast.LENGTH_LONG).show()
                            //moveToMainActivity()
                            val handler = Handler()
                            handler.postDelayed({
                                moveToMainActivity()
                            }, 4000)
                        }
                    }
                })

        }).start()
    }
    else
    {
        Toast.makeText(this@ApiProcessing, "Fail!!", Toast.LENGTH_LONG).show()
    }
    Log.e("api", "end")
}

Because the image's size is too large and it takes a lot of time to be uploaded so sometimes i cant get back the responses from API server. Here is my IUploadAPI

interface IUploadAPI {
@Multipart
@POST("/fruit_vision_api")
fun uploadFile(@Part file: MultipartBody.Part) : Call<String>
}

How can i solve this problem? Thanks very much for your help!!!!!!!!!

Upvotes: 1

Views: 1594

Answers (1)

Bruno
Bruno

Reputation: 4007

I'm using this object to compress an image to 1Mo max. You can use it or adjust it to your needs

/**
 * Definition of the BitmapUtils object.
 */
object BitmapUtils {
    const val ONE_KO = 1024
    const val ONE_MO = ONE_KO * ONE_KO

    /**
     * Compress, if needed, an image file to be lower than or equal to 1 Mo
     *
     * @param filePath Image file path
     *
     * @return Stream containing data of the compressed image. Can be null
     */
    fun compressedImageFile(filePath: String): InputStream? {
        var quality = 100
        var inputStream: InputStream? = null
        if (filePath.isNotEmpty()) {
            var bufferSize = Integer.MAX_VALUE
            val byteArrayOutputStream = ByteArrayOutputStream()
            try {
                val bitmap = BitmapFactory.decodeFile(filePath)
                do {
                    if (bitmap != null) {
                        byteArrayOutputStream.reset()
                        bitmap.compress(Bitmap.CompressFormat.JPEG, quality, byteArrayOutputStream)
                        bufferSize = byteArrayOutputStream.size()
                        logD { "quality: $quality -> length: $bufferSize" }
                        quality -= 10
                    }
                } while (bufferSize > ONE_MO)
                inputStream = ByteArrayInputStream(byteArrayOutputStream.toByteArray())
                byteArrayOutputStream.close()
            } catch (e: Exception) {
                logE { "Exception when compressing file image: ${e.message}" }
            }
        }
        return inputStream
    }
}

To create a file from the InputStream, you can use this extension:

fun File.copyInputStreamToFile(inputStream: InputStream) {
    this.outputStream().use { fileOut ->
        inputStream.copyTo(fileOut)
    }
}

And to use it:

var file = File(YOUR_PATH)
file.copyInputStreamToFile(BitmapUtil.compressedImageFile(filePath))

Upvotes: 1

Related Questions