I am using this code in Kotlin/Android to upload image to server:
fun uploadImageWithLambda(){
val file = File(filePath)
val retrofit = NetworkClient.getRetrofitObj()
val uploadApis = retrofit.create(UploadApis::class.java)
val requestBody = RequestBody.create(MediaType.parse("image/*"), file)
val part = MultipartBody.Part.createFormData("image", file.name, requestBody)
val call = uploadApis.uploadImage(imageRequest = part)
call.enqueue(object : Callback<ImageResponse> {
override fun onFailure(call: Call<ImageResponse>, t: Throwable) {
Log.e(TAG, t.toString())
}
override fun onResponse(call: Call<ImageResponse>, response: Response<ImageResponse>) {
Log.i(TAG, "success")
}
})
}
This is function in UploadApis
#Multipart
#POST("prod/res")
fun uploadImage(#Part imageRequest: MultipartBody.Part) : Call<ImageResponse>
The file that I received in Lambda cannot be open. When I removed some bytes from that file I got proper image file.
First lines of code in my lambda function:
const multipart = require('aws-multipart-parser')
exports.handler = async (event) => {
try {
CONSTANTS.logger.info("POST image in S3...")
let spotText = {}
const result = multipart.parse(event, spotText)
fs.writeFileSync('original.jpg', result.image.content)
const content = result.image.content;
console.log(result)
var newBuffer = new Buffer(content.length - 22);
content.copy(newBuffer, 0, 22, content.length);
// const sliced = content.slice(25);
console.log(newBuffer);
fs.writeFileSync('new.jpg', content);
....
I also made a small express application with one route to upload the image to S3 and I sent the image from Android in the same way and it worked, I could open the image.
Is there anyone having the same/similar issue?
Related
I'm trying to upload an image (in streams) on the s3 presignedURL. However, it's giving me 403. The same file when uploaded via POSTMAN works, but not when done via retrofit. What am I missing?
The following is my code:-
val stream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream)//bitmap is the bitmap of the image
val byteArray = stream.toByteArray()
val encodedImage = Base64.encodeToString(byteArray, Base64.DEFAULT)
val requestBody : RequestBody = encodedImage.toRequestBody()// for base64 format
val url = 'https://s3.presigned_url.com'
val baseUrl = url.split(".com").toTypedArray()[0] + ".com"
var queryUrl: String? = url.split(".com").toTypedArray()[1]
val client = OkHttpClient.Builder().build()
val retrofit_image_upload: Retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build()
var request1 = retrofit_image_upload.create(Api::class.java)
try {
request1.upload(
url,
fileSize,//size of the image
requestBody,
).enqueue(
object : retrofit2.Callback<Void> {
override fun onResponse(call: Call<Void>, response: Response<Void>) {
println(response.code().toString())
}
override fun onFailure(call: Call<Void>, t: Throwable) {
println(t.toString())
}
}
)
} catch (e: IOException) {
e.printStackTrace()
}
And here is the upload method:-
#PUT
fun upload(
#Url url: String,
#Header("content-length") contentlength: Int,
#Body image: RequestBody,
): Call<Void>
Also converted the request body into streams but the result is the same.
I referred below articles but still cannot resolve it.
Android HttpURLConnection PUT to Amazon AWS S3 403 error
PUT upload file to AWS S3 presigned url Retrofit2 Android
https://gutier.io/post/android-upload-file-to-aws-s3-bucket-with-retrofit2/
I am stuck in between a strange issue of uploading image file to server. Although I did upload file several times before, but this time I don't understand what is the issue.
I get the file path of respective file but RequestBody returns null. Below I mentioned what library I'm using.
I am using kotlin, MultiPart and RequestBody for file upload.
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.1'
Below is my code which I wrote for file upload. In which you can see GalleryCameraUtility.getImageRequestBody(imageFile) returns null for file.
File path from mobile device /storage/emulated/0/DCIM/Screenshots/test_image.jpg
fun addNewCompany(companyName: String, email: String,imageFile: File, ownerName: String, address: String, companyDetails: String){
val companyNameBody: RequestBody = companyName.toRequestBody("text/plain".toMediaType())
val emailBody: RequestBody = email.toRequestBody("text/plain".toMediaType())
val fileData: RequestBody? = GalleryCameraUtility.getImageRequestBody(imageFile)
val ownerNameBody: RequestBody = ownerName.toRequestBody("text/plain".toMediaType())
val addressBody: RequestBody = address.toRequestBody("text/plain".toMediaType())
val userIdBody: RequestBody = PreferenceHelper.readUserIdPref(Constants.USER_ID).toString()
.toRequestBody("text/plain".toMediaType())
addCompanyRepo.addNewCompanyApi(companyNameBody, emailBody, fileData, ownerNameBody, addressBody, userIdBody)
}
class GalleryCameraUtility {
companion object{
fun getImageRequestBody(sourceFile: File) : RequestBody? {
var requestBody: RequestBody? = null
Thread {
val mimeType = getMimeType(sourceFile);
if (mimeType == null) {
Log.e("file error", "Not able to get mime type")
return#Thread
}
try {
requestBody = sourceFile.path.toRequestBody("multipart/form-data".toMediaTypeOrNull())
/*MultipartBody.Builder().setType(MultipartBody.FORM)
.addFormDataPart(serverImageKey, uploadedFileName,sourceFile.asRequestBody(mimeType.toMediaTypeOrNull()))
.build()*/
} catch (ex: Exception) {
ex.printStackTrace()
Log.e("File upload", "failed")
}
}.start()
return requestBody;
}
// url = file path or whatever suitable URL you want.
private fun getMimeType(file: File): String? {
var type: String? = null
val extension = MimeTypeMap.getFileExtensionFromUrl(file.path)
if (extension != null) {
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
}
return type
}
}
}
I spent so many hours on this but not able to find solution. Please help me out on this.
I am trying to download an mp3 file from an http link and save the file to local storage. All the code I have tried saves a corrupt file that is slightly twice as large as it should be.
File should be 1,204,787
File saved is 2,478,272
The file I am trying to download is: rise-stage.bioinf.unc.edu/cue_audio/sampleaudio.mp3 –
It plays fine when downloaded manually.
fun downloadFilea(url:String , localFileName:String)
{
val request: Request = Request.Builder()
.url(url)
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
println("error"+e.toString())
}
#Throws(IOException::class)
override fun onResponse(call: Call, response: Response) {
if (!response.isSuccessful) throw IOException("Unexpected code $response")
var uri = dataMgr.getLocalURI(localFileName)
var file = File(uri)
val body = response.body
val contentLength = body!!.contentLength()
val source = body.source()
val DOWNLOAD_CHUNK_SIZE:Long = 2048
val sink: BufferedSink = file.sink().buffer()
var totalRead: Long = 0
var read: Long = 0
while (source.read(sink.buffer(), DOWNLOAD_CHUNK_SIZE).also {
read = it
} != -1L) {
totalRead += read
val progress = (totalRead * 100 / contentLength).toInt()
}
sink.writeAll(source)
sink.flush()
sink.close()
Log.d(logTag, "downloaded file")
}
})
}
I have written code to upload images to the server using okhttp and kotlin, that is, the user takes a picture through the camera then displays the image in the imageView when the user clicks the send button, I want the image from ImageView to be sent to the server, but I don't know how to change the image from ImageView be a file that can be sent to the server, please see my code for more details
this is my kotlin code
fun uploadImage(url:String, image:File, imageName:String){
val MEDIA_TYPE_PNG = MediaType.parse("image/png")
val client = OkHttpClient()
val requestBody = MultipartBody.Builder().setType(MultipartBody.FORM)
.addFormDataPart("file", imageName, RequestBody.create(MEDIA_TYPE_PNG, image))
.build()
val request = Request.Builder()
.url(url)
.post(requestBody)
.build()
client.newCall(request).enqueue(object:Callback{
override fun onFailure(call: Call, e: IOException) {
}
override fun onResponse(call: Call, response: Response) {
Log.i(TAG,"response ${response.body?.string()}")
}
})
}
the question is, how to convert image from imageView to "image:File" for uploadImage function?
Hope this help
val url = getString(R.string.urlUpload)
val MEDIA_TYPE_JPEG = MediaType.parse("image/jpeg")
val bitmap = (img_register.drawable as BitmapDrawable).bitmap
val baos = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos)
val bitmapByteArray = baos.toByteArray()
val file = Base64.encodeToString(bitmapByteArray,Base64.DEFAULT)
I am uploading a dynamic number of files in a single multipart request using Retrofit2. My retrofit interface looks like this -
public interface FileUploadService {
#Multipart
#POST("upload")
Call<ResponseBody> uploadMultipleFilesDynamic(
#Part List<MultipartBody.Part> files);
}
Now I want to track progress for this multi-file upload. This solution explains how to get progress while uploading a single file in a multipart request by extending RequestBody. Though I can't seem to comprehend how to apply this for my multiple files request. One solution I could think of was to create ProgressRequestBody by extending OkHTTP MultipartBody class instead of RequestBody but OkHTTP3 implements MultipartBody as a final class making it impossible to extend. Can anyone point me in the right direction as it's a huge blocker for me to not be able to show the progress to the user for files upload. Or are there any work arounds that I can implement to achieve this functionality?
I've followed this blogpost: https://medium.com/#PaulinaSadowska/display-progress-of-multipart-request-with-retrofit-and-rxjava-23a4a779e6ba and then made the following adjustments to display the total progression instead of progression of separate files:
private fun prepareFileParts(reportAttachments: MutableList<ReportAttachment>, emitter: FlowableEmitter<Double>): List<MultipartBody.Part> {
val multiPartBodyList = mutableListOf<MultipartBody.Part>()
var offset = 0L
var totalLength = 0L
// calculate the total length of all files
for (attachment in reportAttachments) {
val file = File(attachment.filePath)
totalLength += file.length()
}
// create requestbody for each file and calculate the progression offset
for (attachment in reportAttachments) {
val file = File(attachment.filePath)
val mimeType = attachment.mimeType
val countingRequestBody = createCountingRequestBody(file, mimeType, emitter, offset, totalLength)
offset += file.length()
val multipartBody = MultipartBody.Part.createFormData("file", file.name, countingRequestBody)
multiPartBodyList.add(multipartBody)
}
return multiPartBodyList
}
private fun createCountingRequestBody(file: File, mimeType: String, emitter: FlowableEmitter<Double>, offset: Long, totalLength: Long): RequestBody {
val requestBody = RequestBody.create(MediaType.parse(mimeType), file)
return CountingRequestBody(requestBody, object : CountingRequestBody.Listener {
override fun onRequestProgress(bytesWritten: Long, contentLength: Long) {
val progress: Double = 1.0 * (offset + bytesWritten) / totalLength
emitter.onNext(progress)
}
})
}
If you want, you can also create an interceptor and add it to your OkHttpClient. This would track all outgoing API calls by default. It would look something like this:
class UploadProgressInterceptor(private val progressListener: CountingRequestBody.Listener) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest = chain.request()
if (originalRequest.body() == null) {
return chain.proceed(originalRequest)
}
val requestBody = originalRequest.body()
requestBody?.let {
val progressRequest = originalRequest.newBuilder()
.method(originalRequest.method(), CountingRequestBody(it, progressListener))
.build()
return chain.proceed(progressRequest)
}
return chain.proceed(originalRequest)
}