Загрузка изображения в качестве изображения base64, но запрос отправлен с пустым изображением base64

#kotlin #ktor

Вопрос:

Я создал API-интерфейс flask, который может принимать изображение в качестве входных данных в виде строки Base64. Теперь я хочу отправить запрос на этот API из приложения для Android с помощью Ktor. Я использую Jetpack Compose для пользовательского интерфейса здесь. Мне удалось отправить запрос в этот api, но есть проблема, строка Base64 отправляется в api как пустая строка. Теперь, чтобы преобразовать изображение в base64, я использую этот код.

 if (imageUri.value!=null){
            val file = File(imageUri.value.toString()).readBytes()
            imageStr = Base64.encodeToString(file, Base64.DEFAULT)
            println(imageStr)
        }
 

Может ли кто-нибудь сказать, что этот код правильный или нет. Я хочу выбрать изображение из галереи и преобразовать его в строку base64. Я также даю код файла MainActivity.kt и свой код файла составной функции.

Основная активность.тыс. т

 
class MainActivity : ComponentActivity() {

    private var imageUri = mutableStateOf<Uri?>(null)
    private var imageStr: String = ""
    
    private var post: ImageResponse? = null
    
    private var cropActivityResultContracts = object : ActivityResultContract<Any?, Uri?>() {
        override fun createIntent(context: Context, input: Any?): Intent {
            return CropImage.activity()
                .getIntent(this@MainActivity)
        }

        override fun parseResult(resultCode: Int, intent: Intent?): Uri? {
            return CropImage.getActivityResult(intent)?.uri
        }

    }

    private val launcher = registerForActivityResult(cropActivityResultContracts) { uri ->
        imageUri.value = uri
    }

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        if (imageUri.value!=null){
            val file = File(imageUri.value.toString()).readBytes()
            imageStr = Base64.encodeToString(file, Base64.DEFAULT)
            println(imageStr)
        }


        setContent {
            val scope = rememberCoroutineScope()
            UploadImageTheme {
                ImagePickerDesign(
                    onSelect = {
                        launcher.launch("image/*")
                    },
                    imageUri = imageUri,
                    onUpload = {
                        scope.launch {
                            post = service.postImage(
                                ImageRequest(imageStr)
                            )
                        }
                    },
                    result = post.pred_percentage
                )
            }
        }
    }
}
 

и еще кое-что! может ли кто-нибудь сказать, как отобразить ответ с сервера в приложении. В приведенном выше коде параметр result примет ответ от сервера и отобразит его. Но по какой-то причине я не могу обновить это значение в пользовательском интерфейсе. пожалуйста, помогите в этом случае.

ImagePickerDesign.kt

 package com.example.uploadimage

import android.net.Uri
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.unit.dp
import com.skydoves.landscapist.glide.GlideImage
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.sp

@Composable
fun ImagePickerDesign(
    imageUri: MutableState<Uri?>,
    onUpload: () -> Unit,
    onSelect: () -> Unit,
    result: String
) {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        verticalArrangement = Arrangement.SpaceEvenly,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {

        if (imageUri.value != null) {
            GlideImage(
                imageModel = imageUri.value,
                modifier = Modifier
                    .size(350.dp)
                    .clickable(onClick = onSelect),
                contentScale = ContentScale.Fit
            )
        }else{
            Image(
                painter = painterResource(id = R.drawable.placeholder_image),
                contentDescription = "placeholder",
                modifier = Modifier
                    .size(350.dp)
                    .clickable(onClick = onSelect),
                colorFilter = ColorFilter.tint(Color.Black)
            )
        }

        Text(text = result, fontSize = 16.sp)

        Button(onClick = onUpload) {
            Text(text = "Upload Image")
        }
    }
}
 

Я с нетерпением жду вашего ответа.

вы также можете ознакомиться с моим проектом по этой ссылке https://github.com/srang992/Pancard-Tampering-app

это выводится при запуске приложения для Android

 Install successfully finished in 6 s 709 ms.
$ adb shell am start -n "com.example.uploadimage/com.example.uploadimage.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Connected to process 32033 on device 'xiaomi-m2010j19si-6686ff050321'.
Capturing and displaying logcat messages from application. This behavior can be disabled in the "Logcat output" section of the "Debugger" settings page.
I/ple.uploadimag: Late-enabling -Xcheck:jni
E/ple.uploadimag: Unknown bits set in runtime_flags: 0x48000
I/Perf: Connecting to perf service.
I/FeatureParser: can't find lime.xml in assets/device_features/,it may be in /vendor/etc/device_features
E/libc: Access denied finding property "ro.vendor.df.effect.conflict"
E/libc: Access denied finding property "ro.vendor.knock.type"
W/ple.uploadimage: type=1400 audit(0.0:18925): avc: denied { read } for name="u:object_r:vendor_default_prop:s0" dev="tmpfs" ino=16328 scontext=u:r:untrusted_app:s0:c35,c257,c512,c768 tcontext=u:object_r:vendor_default_prop:s0 tclass=file permissive=0
    type=1400 audit(0.0:18926): avc: denied { read } for name="u:object_r:vendor_default_prop:s0" dev="tmpfs" ino=16328 scontext=u:r:untrusted_app:s0:c35,c257,c512,c768 tcontext=u:object_r:vendor_default_prop:s0 tclass=file permissive=0
W/Looper: PerfMonitor looperActivity : package=com.example.uploadimage/.MainActivity time=273ms latency=938ms running=224ms  procState=2 ClientTransaction{ callbacks=[android.app.servertransaction.LaunchActivityItem] lifecycleRequest=android.app.servertransaction.ResumeActivityItem } historyMsgCount=1 (msgIndex=1 wall=997ms seq=2 running=873ms runnable=46ms io=17ms late=2ms h=android.app.ActivityThread$H w=110)
W/Looper: PerfMonitor looperActivity : package=com.example.uploadimage/.MainActivity time=0ms latency=1216ms running=0ms  procState=2 ClientTransaction{ callbacks=[android.app.servertransaction.TopResumedActivityChangeItem] } historyMsgCount=2 (msgIndex=1 wall=997ms seq=2 running=873ms runnable=46ms io=17ms late=2ms h=android.app.ActivityThread$H w=110) (msgIndex=2 wall=273ms seq=3 running=224ms runnable=4ms io=20ms late=938ms h=android.app.ActivityThread$H w=159)
I/AdrenoGLES-0: QUALCOMM build                   : 243b6bc, I98aee2b40e
    Build Date                       : 12/08/20
    OpenGL ES Shader Compiler Version: EV031.29.00.16
    Local Branch                     : 
    Remote Branch                    : refs/tags/AU_LINUX_ANDROID_LA.UM.8.15.R1.10.00.00.643.066
    Remote Branch                    : NONE
    Reconstruct Branch               : NOTHING
    Build Config                     : S P 8.0.16 AArch64
    Driver Path                      : /vendor/lib64/egl/libGLESv2_adreno.so
I/AdrenoGLES-0: PFP: 0x016ee188, ME: 0x00000000
I/OpenGLRenderer: Davey! duration=902ms; Flags=1, IntendedVsync=17962622634853, Vsync=17962905968175, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=17962922546739, AnimationStart=17962922639291, PerformTraversalsStart=17962922843354, DrawStart=17963416902364, SyncQueued=17963440580541, SyncStart=17963440964031, IssueDrawCommandsStart=17963441058406, SwapBuffers=17963524637156, FrameCompleted=17963525914447, DequeueBufferDuration=106000, QueueBufferDuration=392000, 
W/Looper: PerfMonitor doFrame : time=605ms vsyncFrame=646397 latency=300ms procState=2 historyMsgCount=4 (msgIndex=1 wall=997ms seq=2 running=873ms runnable=46ms io=17ms late=2ms h=android.app.ActivityThread$H w=110) (msgIndex=2 wall=273ms seq=3 running=224ms runnable=4ms io=20ms late=938ms h=android.app.ActivityThread$H w=159)
I/Choreographer: Skipped 34 frames!  The application may be doing too much work on its main thread.
W/Looper: PerfMonitor doFrame : time=11ms vsyncFrame=646410 latency=576ms procState=2 historyMsgCount=5 (msgIndex=1 wall=605ms seq=6 running=461ms late=300ms h=android.view.Choreographer$FrameHandler c=android.view.Choreographer$FrameDisplayEventReceiver)
I/ple.uploadimag: ProcessProfilingInfo new_methods=5563 is saved saved_to_disk=1 resolve_classes_delay=8000
I/Timeline: Timeline: Activity_launch_request time:17970735
W/ActivityThread: handleWindowVisibility: no activity for token android.os.BinderProxy@8f28626
W/ple.uploadimag: Accessing hidden method Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z (greylist, reflection, allowed)
W/ple.uploadimag: Accessing hidden method Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V (greylist, reflection, allowed)
I/Timeline: Timeline: Activity_launch_request time:17970975
W/Glide: Failed to find GeneratedAppGlideModule. You should include an annotationProcessor compile dependency on com.github.bumptech.glide:compiler in your application and a @GlideModule annotated AppGlideModule implementation or LibraryGlideModules will be silently ignored
I/System.out: 20:44:19.969 [main] INFO io.ktor.client.HttpClient - REQUEST: https://pancard-fraud.herokuapp.com/
    20:44:19.978 [main] INFO io.ktor.client.HttpClient - METHOD: HttpMethod(value=POST)
I/System.out: 20:44:19.978 [main] INFO io.ktor.client.HttpClient - COMMON HEADERS
I/System.out: 20:44:19.981 [main] INFO io.ktor.client.HttpClient - -> Accept: application/json
    20:44:19.982 [main] INFO io.ktor.client.HttpClient - -> Accept-Charset: UTF-8
I/System.out: 20:44:19.982 [main] INFO io.ktor.client.HttpClient - CONTENT HEADERS
    20:44:19.983 [main] INFO io.ktor.client.HttpClient - -> Content-Length: 18
    20:44:19.983 [main] INFO io.ktor.client.HttpClient - -> Content-Type: application/json
I/System.out: 20:44:19.984 [main] INFO io.ktor.client.HttpClient - BODY Content-Type: application/json
I/System.out: 20:44:20.024 [main] INFO io.ktor.client.HttpClient - BODY START
    20:44:20.025 [main] INFO io.ktor.client.HttpClient - {"imageString":""}
    20:44:20.025 [main] INFO io.ktor.client.HttpClient - BODY END
D/NetworkSecurityConfig: No Network Security Config specified, using platform default
I/DpmTcmClient: RegisterTcmMonitor from: $Proxy0
I/System.out: 20:44:41.745 [main] INFO io.ktor.client.HttpClient - RESPONSE: 503 Service Unavailable
    20:44:41.746 [main] INFO io.ktor.client.HttpClient - METHOD: HttpMethod(value=POST)
I/System.out: 20:44:41.747 [main] INFO io.ktor.client.HttpClient - FROM: https://pancard-fraud.herokuapp.com/
I/System.out: 20:44:41.747 [main] INFO io.ktor.client.HttpClient - COMMON HEADERS
I/System.out: 20:44:41.748 [main] INFO io.ktor.client.HttpClient - -> cache-control: no-cache, no-store
I/System.out: 20:44:41.749 [main] INFO io.ktor.client.HttpClient - -> connection: keep-alive
I/System.out: 20:44:41.750 [main] INFO io.ktor.client.HttpClient - -> content-length: 506
I/System.out: 20:44:41.751 [main] INFO io.ktor.client.HttpClient - -> content-type: text/html; charset=utf-8
I/System.out: 20:44:41.752 [main] INFO io.ktor.client.HttpClient - -> date: Wed, 03 Nov 2021 15:14:40 GMT
I/System.out: 20:44:41.753 [main] INFO io.ktor.client.HttpClient - -> server: Cowboy
I/System.out: 20:44:41.754 [main] INFO io.ktor.client.HttpClient - -> x-android-received-millis: 1635952481690
I/System.out: 20:44:41.755 [main] INFO io.ktor.client.HttpClient - -> x-android-response-source: NETWORK 503
I/System.out: 20:44:41.756 [main] INFO io.ktor.client.HttpClient - -> x-android-selected-protocol: http/1.1
I/System.out: 20:44:41.757 [main] INFO io.ktor.client.HttpClient - -> x-android-sent-millis: 1635952461008
I/System.out: 20:44:41.769 [ktor-android-dispatcher-worker-3] INFO io.ktor.client.HttpClient - BODY Content-Type: text/html; charset=utf-8
I/System.out: 20:44:41.770 [ktor-android-dispatcher-worker-3] INFO io.ktor.client.HttpClient - BODY START
I/System.out: 20:44:41.771 [ktor-android-dispatcher-worker-3] INFO io.ktor.client.HttpClient - <!DOCTYPE html>
        <html>
          <head>
            <meta name="viewport" content="width=device-width, initial-scale=1">
            <meta charset="utf-8">
            <title>Application Error</title>
            <style media="screen">
              html,body,iframe {
                margin: 0;
                padding: 0;
              }
              html,body {
                height: 100%;
                overflow: hidden;
              }
              iframe {
                width: 100%;
                height: 100%;
                border: 0;
              }
            </style>
          </head>
          <body>
            <iframe src="//www.herokucdn.com/error-pages/application-error.html"></iframe>
          </body>
        </html>
I/System.out: 20:44:41.772 [ktor-android-dispatcher-worker-3] INFO io.ktor.client.HttpClient - BODY END
I/System.out: Error: Service Unavailable
 

Комментарии:

1. Не могли бы вы поделиться кодом для клиента Ktor, который отправляет запрос, и примером ответа сервера?

2. извините за поздний ответ. Я включил свою ссылку на github в свой вопрос, а также в ответ.

3. Вы проверили, что E/libc: Access denied... означают эти ошибки?

4. Ваш код для получения строки с кодировкой base64 неверен. Вам нужно использовать getContentResolver().openInputStream(imageUri.value!!)!!.readBytes() для чтения байтов из файла изображения. Кроме того, imageStr свойство должно быть обновлено непосредственно перед загрузкой или при обрезке изображения, потому что в onCreate методе imageUri всегда есть null значение.

5. Спасибо за вашу помощь. Теперь это работает. Ты спас меня.