Мы захватываем несколько изображений с помощью CameraX, сохраняем их на устройстве и публикуем эти изображения и текстовые данные с помощью MultipartBody.Part и RequestBody. Мы обнаружили, что не получаем данные EXIF на стороне сервера. Это проблема с Retrofit 2 Multipart? Как мы можем получить изображения на стороне сервера, не теряя его данные EXIF?
Вот код, который мы используем
private lateinit var activityCaptureImageBinding: ActivityCaptureImageBinding
private var preview: Preview? = null
private var imageCapture: ImageCapture? = null
private var camera: Camera? = null
private lateinit var outputDirectory: File
private lateinit var cameraExecutor: ExecutorService
private lateinit var fusedLocationClient: FusedLocationProviderClient
private var metadata = ImageCapture.Metadata()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activityCaptureImageBinding = DataBindingUtil.setContentView(this@CaptureImageActivity, R.layout.activity_capture_image)
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return
}
fusedLocationClient.lastLocation
.addOnSuccessListener { location: Location? ->
metadata.apply {
setLocation(location)
}
}
activityCaptureImageBinding.btnCaptureImage.setOnClickListener {
takePhoto()
}
activityCaptureImageBinding.btnCancel.setOnClickListener {
val intent = Intent()
intent.putStringArrayListExtra(AppData.IMAGE_PATH, AppData.capturedCatsList)
setResult(Activity.RESULT_OK, intent)
finish()
}
outputDirectory = getOutputDirectory()
cameraExecutor = Executors.newSingleThreadExecutor()
}
private fun startCamera() {
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener(Runnable {
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
preview = Preview.Builder()
.build()
imageCapture = ImageCapture.Builder()
.build()
val cameraSelector = CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build()
try {
cameraProvider.unbindAll()
camera = cameraProvider.bindToLifecycle(
this, cameraSelector, preview, imageCapture)
preview?.setSurfaceProvider(viewFinder.createSurfaceProvider())
} catch (exc: Exception) {
showLog(TAG, "Use case binding failed" + exc)
}
}, ContextCompat.getMainExecutor(this))
}
private fun takePhoto() {
val imageCapture = imageCapture ?: return
val photoFile = File(
outputDirectory,
SimpleDateFormat(FILENAME_FORMAT, Locale.getDefault()
).format(System.currentTimeMillis()) + ".jpg")
showLog(TAG, "created file")
val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile)
.setMetadata(metadata)
.build()
imageCapture.takePicture(
outputOptions, ContextCompat.getMainExecutor(this), object : ImageCapture.OnImageSavedCallback {
override fun onError(exc: ImageCaptureException) {
showLog(TAG, "Photo capture failed: ${exc.message}")
}
override fun onImageSaved(output: ImageCapture.OutputFileResults) {
showLog(TAG, "on image saved")
val savedUri = Uri.fromFile(photoFile)
AppData.capturedCatsList.add(savedUri.toString())
}
})
}
Ниже приведен код модернизации
@Multipart
@POST("SimpleEncounterForm")
fun postCatImagesWithData(@Header("Cookie") cookie: String,
@Part catImages: List<MultipartBody.Part>,
@Part("datetime") dateTime: RequestBody,
@Part("lat") lat: RequestBody,
@Part("lon") lon: RequestBody,
@Part("locationID") locationId: RequestBody,
@Part("behavior") catBehaviour: RequestBody): Call<ResponseBody>
Метод, который мы используем для создания MultipartBody.Part из Uri сохраненных изображений
@NonNull
private fun postFiles(fileUri: Uri): MultipartBody.Part {
val file = FileUtils.getFile(this@DashboardActivity, fileUri)
val fileReqBody = RequestBody.create(MediaType.parse("image/jpeg"), file)
return MultipartBody.Part.createFormData("upload", file.name, fileReqBody)
}
Преобразование Uri в файл
public static File getFile(Context context, Uri uri) {
if (uri != null) {
String path = getPath(context, uri);
if (path != null && isLocal(path)) {
return new File(path);
}
}
return null;
}