rabbit-android/app/src/main/java/com/img/rabbit/viewmodel/CutoutViewModel.kt

136 lines
5.5 KiB
Kotlin
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.img.rabbit.viewmodel
import android.content.Context
import android.graphics.Bitmap
import android.net.Uri
import android.os.Build
import android.util.Log
import androidx.compose.runtime.mutableStateOf
import com.img.rabbit.bean.local.ErrorBean
import com.img.rabbit.provider.api.ApiManager
import com.img.rabbit.utils.DownLoadUtils
import com.img.rabbit.utils.FileUtils
import com.img.rabbit.utils.ImageUtils
import com.img.rabbit.utils.PhotoCutter
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody
import java.io.File
import java.io.IOException
import kotlin.text.ifEmpty
class CutoutViewModel : BaseViewModel() {
private val targetPath = FileUtils.instance?.cacheImageDir?.absolutePath?:""
private val targetFileName = "cutoutCache.png"
// 错误状态
val errorState = mutableStateOf<ErrorBean?>(null)
// 本地抠图
fun cutoutImageFromLocal(context: Context, uri: Uri, onResult: (isSuccess: Boolean, croppedBitmap: Bitmap?) -> Unit) {
// 执行抠图操作
Thread {
try {
val originalBitmap = ImageUtils.getBitmapFromUri(context, uri)
originalBitmap?.let { bitmap ->
PhotoCutter.cutPureHead(bitmap) { croppedBitmap ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
context.mainExecutor.execute {
onResult(true, croppedBitmap)
}
}
}
}
} catch (e: Exception) {
Log.e("CutoutScreen", "抠图失败: ${e.message}")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
context.mainExecutor.execute {
onResult(false, null)
}
}
}
}.start()
}
//服务器抠图
fun cutoutImageFromService(context: Context, uri: Uri, onResult: (isSuccess: Boolean, croppedBitmap: Bitmap?) -> Unit) {
mLaunch {
try {
// 1. 获取并压缩图片为 PNG (后端示例中使用了 .png可能只支持 PNG)
val bitmap = ImageUtils.getBitmapFromUri(context, uri) ?: throw IOException("无法获取图片")
val outputStream = java.io.ByteArrayOutputStream()
// PNG 是无损的,质量参数 100 即可
bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
val compressedBytes = outputStream.toByteArray()
bitmap.recycle()
// 2. MediaType 修改为 image/png
val requestFile = RequestBody.create("image/png".toMediaTypeOrNull(), compressedBytes)
// 3. 构造 MultipartBody.Part关键强制给文件名加上 .png 后缀
// 不要直接用 uri.lastPathSegment除非你能确定它带后缀
val fileName = "cutout_${System.currentTimeMillis()}.png"
val filePart = MultipartBody.Part.createFormData("file", fileName, requestFile)
// 4. 发起请求
val response = ApiManager.serviceVo.cutoutImage(filePart)
if (response.status) {
Log.i("CutoutViewModel", "抠图成功: ${response.data}")
val resultUrl = response.data.toString()
// 将 http 替换为 https
//val resultUrl = response.data.toString().replace("http://", "https://")
saveUrlToCache(resultUrl, onResult)
} else {
errorState.value = ErrorBean(response.code.toString(), response.message.ifEmpty { "抠图失败" })
onResult(false, null)
}
} catch (e: Exception) { // 捕获更广泛的异常
e.printStackTrace()
Log.e("CutoutViewModel", "服务请求异常: ${e.message}")
onResult(false, null)
}
}
}
private fun saveUrlToCache(url: String, onResult: (isSuccess: Boolean, croppedBitmap: Bitmap?) -> Unit) {
try {
val targetFile = File(targetPath,targetFileName)
if(targetFile.exists()){
targetFile.delete()
}
DownLoadUtils.getInstance()
.initUrl(url, null)
.setFilePath(targetPath)
.setFileName(targetFileName)
.setDownCallBack(object : DownLoadUtils.DownCallBack {
override fun success(file: File) {
// 3. 下载成功后,将文件解析为 Bitmap 并回调给 UI
val bitmap = android.graphics.BitmapFactory.decodeFile(file.absolutePath)
onResult(true, bitmap)
}
override fun fail(str: String) {
onResult(false, null)
}
override fun progress(position: Long) {
// 如果需要进度可以在这里处理
}
override fun total(total: Long) {
// 获取总大小
}
override fun cancel() {
onResult(false, null)
}
})
.down()
}catch (e: Exception){
e.printStackTrace()
onResult(false, null)
}
}
}