136 lines
5.5 KiB
Kotlin
136 lines
5.5 KiB
Kotlin
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)
|
||
}
|
||
}
|
||
} |