添加菜品采集
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
package com.sw.dualscreen.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.provider.OpenableColumns
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.ActivityResultCaller
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.core.content.FileProvider
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
|
||||
/**
|
||||
* 简洁相机工具类
|
||||
* 调用系统相机拍照并返回照片路径
|
||||
*/
|
||||
class CameraHelper(
|
||||
private val context: Context,
|
||||
caller: ActivityResultCaller,
|
||||
private val authority: String,
|
||||
private val onResult: (uri: Uri, filePath: String?) -> Unit
|
||||
) {
|
||||
|
||||
private lateinit var imageUri: Uri
|
||||
private val takePictureLauncher: ActivityResultLauncher<Uri>
|
||||
|
||||
init {
|
||||
takePictureLauncher =
|
||||
caller.registerForActivityResult(ActivityResultContracts.TakePicture()) { success ->
|
||||
if (success) {
|
||||
val path = getRealPathFromUri(context, imageUri)
|
||||
onResult(imageUri, path)
|
||||
} else {
|
||||
Toast.makeText(context, "拍照取消", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 打开系统相机 */
|
||||
fun openCamera() {
|
||||
// 1. 创建存储图片的文件
|
||||
val photoFile = File(context.externalCacheDir, "IMG_${System.currentTimeMillis()}.jpg")
|
||||
photoFile.parentFile?.mkdirs() // 确保目录存在
|
||||
|
||||
// 2. 生成 content:// Uri
|
||||
imageUri = FileProvider.getUriForFile(context, authority, photoFile)
|
||||
|
||||
// 3. 启动相机
|
||||
takePictureLauncher.launch(imageUri)
|
||||
}
|
||||
|
||||
/** 可选:将 content:// 转为实际路径 */
|
||||
private fun getRealPathFromUri(context: Context, uri: Uri): String? {
|
||||
var filePath: String? = null
|
||||
context.contentResolver.query(uri, null, null, null, null)?.use { cursor ->
|
||||
val nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
|
||||
cursor.moveToFirst()
|
||||
val fileName = cursor.getString(nameIndex)
|
||||
val file = File(context.cacheDir, fileName)
|
||||
context.contentResolver.openInputStream(uri)?.use { input ->
|
||||
FileOutputStream(file).use { output -> input.copyTo(output) }
|
||||
}
|
||||
filePath = file.absolutePath
|
||||
}
|
||||
return filePath
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.example.utils
|
||||
|
||||
import android.util.Base64
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.ByteOrder
|
||||
|
||||
/**
|
||||
* 工具类:float[] 与 Base64 字符串互转
|
||||
* 无需外部依赖,适用于 Android 原生项目。
|
||||
*/
|
||||
object FloatBase64Utils {
|
||||
|
||||
/**
|
||||
* float数组 → Base64字符串
|
||||
* @param values FloatArray
|
||||
* @return Base64字符串(无换行)
|
||||
*/
|
||||
fun floatArrayToBase64(values: FloatArray): String {
|
||||
if (values.isEmpty()) return ""
|
||||
|
||||
val buffer = ByteBuffer.allocate(values.size * 4)
|
||||
buffer.order(ByteOrder.BIG_ENDIAN) // 默认大端序,可改 LITTLE_ENDIAN
|
||||
values.forEach { buffer.putFloat(it) }
|
||||
|
||||
val bytes = buffer.array()
|
||||
return Base64.encodeToString(bytes, Base64.NO_WRAP)
|
||||
}
|
||||
|
||||
/**
|
||||
* Base64字符串 → float数组
|
||||
* @param base64 Base64字符串
|
||||
* @return FloatArray
|
||||
*/
|
||||
fun base64ToFloatArray(base64: String?): FloatArray {
|
||||
if (base64.isNullOrEmpty()) return FloatArray(0)
|
||||
|
||||
val bytes = Base64.decode(base64, Base64.NO_WRAP)
|
||||
val buffer = ByteBuffer.wrap(bytes)
|
||||
buffer.order(ByteOrder.BIG_ENDIAN)
|
||||
|
||||
val result = FloatArray(bytes.size / 4)
|
||||
for (i in result.indices) {
|
||||
result[i] = buffer.getFloat()
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,12 @@ import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.net.Uri
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.MultipartBody
|
||||
import okhttp3.RequestBody
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.InputStream
|
||||
|
||||
object ImageUtil {
|
||||
|
||||
@@ -18,4 +24,24 @@ object ImageUtil {
|
||||
}
|
||||
}
|
||||
|
||||
fun uriToMultipart(context: Context, uri: Uri, partName: String): MultipartBody.Part? {
|
||||
try {
|
||||
val contentResolver = context.contentResolver
|
||||
val inputStream: InputStream = contentResolver.openInputStream(uri) ?: return null
|
||||
|
||||
// 临时文件(避免直接访问SAF文件)
|
||||
val tempFile = File.createTempFile("upload_", ".jpg", context.cacheDir)
|
||||
|
||||
val outputStream = FileOutputStream(tempFile)
|
||||
inputStream.copyTo(outputStream)
|
||||
inputStream.close()
|
||||
outputStream.close()
|
||||
|
||||
val requestFile = RequestBody.create("image/*".toMediaTypeOrNull(), tempFile)
|
||||
return MultipartBody.Part.createFormData(partName, tempFile.name, requestFile)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user