移植文件上传:七牛云换腾讯云
This commit is contained in:
@@ -251,7 +251,7 @@ class UploadRoomAlbumDialogFragment : BottomSheetDialogFragment() {
|
||||
}
|
||||
if (requestCode == 200) {
|
||||
PhotoProvider.getResultPathListAsync(data) {
|
||||
it?.let { paths ->
|
||||
it?.mapNotNull { it.path }?.let { paths ->
|
||||
compressPhotos(paths.toMutableList())
|
||||
}
|
||||
}
|
||||
|
@@ -207,7 +207,7 @@ class PhotoDialog : BaseDialogFragment<PhotoDialogBinding>(), EasyPermissions.Pe
|
||||
REQUEST_CODE_OPEN_CAMERA_PROVIDER -> {
|
||||
if (mOnResultCallBack == null || data == null) return
|
||||
PhotoProvider.getResultPathListAsync(data) { paths ->
|
||||
val list = paths?.toMutableList() ?: ArrayList()
|
||||
val list = paths?.mapNotNull { it.path }?.toMutableList() ?: ArrayList()
|
||||
val path = list[0]
|
||||
if (!TextUtils.isEmpty(path)) {
|
||||
mJob?.cancel()
|
||||
@@ -233,7 +233,7 @@ class PhotoDialog : BaseDialogFragment<PhotoDialogBinding>(), EasyPermissions.Pe
|
||||
REQUEST_CODE_OPEN_PHOTO_PROVIDER -> {
|
||||
if (mOnResultCallBack == null || data == null) return
|
||||
PhotoProvider.getResultPathListAsync(data) { list ->
|
||||
val paths = list?.toMutableList() ?: ArrayList()
|
||||
val paths = list?.mapNotNull { it.path }?.toMutableList() ?: ArrayList()
|
||||
if (paths.isEmpty()) {
|
||||
mOnResultCallBack?.choicePhotoCallBack(paths)
|
||||
} else {
|
||||
|
@@ -130,7 +130,7 @@ object PhotoProvider {
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getResultPathListAsync(data: Intent?, resultListener: ((List<String>?) -> Unit)) {
|
||||
fun getResultPathListAsync(data: Intent?, resultListener: ((List<Photo>?) -> Unit)) {
|
||||
cancelJop()
|
||||
mPhotoJob = MainScope().launch {
|
||||
val list: List<Photo>? = data?.getParcelableArrayListExtra(EasyPhotos.RESULT_PHOTOS)
|
||||
@@ -150,22 +150,21 @@ object PhotoProvider {
|
||||
* 1. 项目使用到BitmapFactory.decodeFile(imgPath, options)之类的方法,该方法在android Q直接使用外部path测试中发现,获取图片信息失败
|
||||
*
|
||||
*/
|
||||
private fun copyToInternalCache(photos: List<Photo>?): List<String>? {
|
||||
private fun copyToInternalCache(photos: List<Photo>?): List<Photo>? {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
val foldPath = getInternalPath() + File.separator
|
||||
val newPaths = ArrayList<String>()
|
||||
photos?.forEach {
|
||||
if (it.uri != null && !it.name.isNullOrEmpty()) {
|
||||
val path = "$foldPath${it.name}"
|
||||
if (FileHelper.copyFileFromUri(it.uri, path, true)) {
|
||||
newPaths.add(path)
|
||||
it.path = path
|
||||
LibLogger.debug(TAG, "path: ${it.path} , displayName: ${it.name} , newPath: $path ")
|
||||
}
|
||||
}
|
||||
}
|
||||
newPaths
|
||||
photos
|
||||
} else {
|
||||
photos?.takeIf { it.isNotEmpty() }?.map { it.path }
|
||||
photos
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -22,6 +22,22 @@ public class ObjectTypeHelper {
|
||||
return resultList;
|
||||
}
|
||||
|
||||
public static List<DynamicMedia> customToMediaList(List<CustomItem> paramsList) {
|
||||
List<DynamicMedia> resultList = new ArrayList<>();
|
||||
if (paramsList == null) {
|
||||
return resultList;
|
||||
}
|
||||
for (CustomItem item : paramsList) {
|
||||
DynamicMedia media = new DynamicMedia();
|
||||
media.setLocalFilePath(item.getPath());
|
||||
media.setWidth(item.getWidth());
|
||||
media.setHeight(item.getHeight());
|
||||
media.setFormat(item.getFormat());
|
||||
resultList.add(media);
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
|
||||
public static List<CustomItem> stringToCustomList(List<String> paramsList) {
|
||||
List<CustomItem> resultList = new ArrayList<>();
|
||||
if (paramsList == null) {
|
||||
|
@@ -36,6 +36,10 @@ public class CustomItem implements Parcelable, Serializable {
|
||||
|
||||
private String format;
|
||||
|
||||
private int width;
|
||||
|
||||
private int height;
|
||||
|
||||
public String getPath(){
|
||||
return path;
|
||||
}
|
||||
@@ -66,7 +70,7 @@ public class CustomItem implements Parcelable, Serializable {
|
||||
}
|
||||
|
||||
public CustomItem(String path, int fileType) {
|
||||
this(path, fileType, "jpeg");
|
||||
this(path, fileType, "jpeg",0,0);
|
||||
}
|
||||
|
||||
public CustomItem() {
|
||||
@@ -82,12 +86,16 @@ public class CustomItem implements Parcelable, Serializable {
|
||||
dest.writeString(this.path);
|
||||
dest.writeInt(this.fileType);
|
||||
dest.writeString(this.format);
|
||||
dest.writeInt(this.width);
|
||||
dest.writeInt(this.height);
|
||||
}
|
||||
|
||||
protected CustomItem(Parcel in) {
|
||||
this.path = in.readString();
|
||||
this.fileType = in.readInt();
|
||||
this.format = in.readString();
|
||||
this.width = in.readInt();
|
||||
this.height = in.readInt();
|
||||
}
|
||||
|
||||
public static final Creator<CustomItem> CREATOR = new Creator<CustomItem>() {
|
||||
|
@@ -2,24 +2,23 @@ package com.chwl.core.file;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.netease.nim.uikit.common.util.log.LogUtil;
|
||||
import com.qiniu.android.common.FixedZone;
|
||||
import com.qiniu.android.storage.Configuration;
|
||||
import com.qiniu.android.storage.UploadManager;
|
||||
import com.chwk.core.file.cos.CosClient;
|
||||
import com.chwk.core.file.cos.CosToken;
|
||||
import com.chwl.core.utils.net.RxHelper;
|
||||
import com.example.lib_utils.AppUtils;
|
||||
import com.example.lib_utils.PathUtils;
|
||||
import com.chwl.core.R;
|
||||
import com.chwl.core.base.BaseModel;
|
||||
import com.chwl.core.bean.response.ServiceResult;
|
||||
import com.chwl.core.community.bean.DynamicMedia;
|
||||
import com.chwl.core.exception.ErrorThrowable;
|
||||
import com.chwl.core.utils.net.RxHelper;
|
||||
import com.chwl.library.net.rxnet.RxNet;
|
||||
import com.chwl.library.utils.ResUtil;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.UUID;
|
||||
|
||||
import io.reactivex.Single;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import retrofit2.http.GET;
|
||||
|
||||
public class FileModel extends BaseModel implements IFileModel {
|
||||
@@ -29,120 +28,51 @@ public class FileModel extends BaseModel implements IFileModel {
|
||||
}
|
||||
|
||||
private FileModel() {
|
||||
Configuration config = new Configuration.Builder()
|
||||
.zone(FixedZone.zoneAs0) // 设置区域,不指定会自动选择。指定不同区域的上传域名、备用域名、备用IP。
|
||||
.build();
|
||||
uploadManager = new UploadManager(config);
|
||||
}
|
||||
|
||||
public static FileModel get() {
|
||||
return Helper.INSTANCE;
|
||||
}
|
||||
|
||||
private UploadManager uploadManager;
|
||||
private final Api api = RxNet.create(Api.class);
|
||||
private CosToken cosToken;
|
||||
|
||||
private Single<CosToken> getCosToken() {
|
||||
if (cosToken != null && cosToken.isValid()) {
|
||||
return Single.just(cosToken);
|
||||
} else {
|
||||
return api.getCosToken().compose(RxHelper.handleSchedulers())
|
||||
.compose(RxHelper.handleBeanData()).map(cosToken -> {
|
||||
FileModel.get().cosToken = cosToken;
|
||||
return cosToken;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Single<String> uploadFile(String path) {
|
||||
|
||||
File file;
|
||||
if (TextUtils.isEmpty(path) || !((file = new File(path)).exists())) {
|
||||
return Single.error(new ErrorThrowable(path + ResUtil.getString(R.string.xchat_android_core_file_filemodel_01)));
|
||||
}
|
||||
File finalFile = file;
|
||||
return api.getUploadToken()
|
||||
.compose(RxHelper.handleSchedulers())
|
||||
.compose(RxHelper.handleBeanData())
|
||||
.flatMap(uploadToken -> Single.create(singleEmitter ->
|
||||
uploadManager.put(finalFile, uploadToken.getKey(), uploadToken.getToken() ,
|
||||
(key, info, response) -> {
|
||||
if (info.isOK()) {
|
||||
try {
|
||||
String imgUrl = response.getString("path");
|
||||
singleEmitter.onSuccess(imgUrl);
|
||||
} catch (Exception e) {
|
||||
singleEmitter.onError(e);
|
||||
}
|
||||
} else {
|
||||
singleEmitter.onError(new Throwable(info.error));
|
||||
}
|
||||
}, null)
|
||||
));
|
||||
String outName = UUID.randomUUID().toString() + PathUtils.INSTANCE.getSuffixType(finalFile.getName());
|
||||
return getCosToken().flatMap(token -> CosClient.INSTANCE.upload(AppUtils.getApp(), finalFile, outName, token).map(cosXmlResult -> cosXmlResult.accessUrl))
|
||||
.observeOn(AndroidSchedulers.mainThread());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Single<DynamicMedia> uploadFileReturnImageInfo(String path) {
|
||||
return uploadFileReturnImageInfo(path, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Single<DynamicMedia> uploadFileReturnImageInfo(String path, String qiniuName) {
|
||||
File file;
|
||||
if (TextUtils.isEmpty(path) || !((file = new File(path)).exists())) {
|
||||
return Single.error(new ErrorThrowable(path + ResUtil.getString(R.string.xchat_android_core_file_filemodel_02)));
|
||||
}
|
||||
|
||||
File finalFile = file;
|
||||
return api.getUploadToken()
|
||||
.compose(RxHelper.handleSchedulers())
|
||||
.compose(RxHelper.handleBeanData())
|
||||
.flatMap(uploadToken -> Single.create(singleEmitter ->
|
||||
uploadManager.put(finalFile, uploadToken.getKey(), uploadToken.getToken(),
|
||||
(key, info, response) -> {
|
||||
if (info.isOK()) {
|
||||
try {
|
||||
LogUtil.print(ResUtil.getString(R.string.xchat_android_core_file_filemodel_03));
|
||||
LogUtil.print(response);
|
||||
DynamicMedia media = responseToMeia(response);
|
||||
if (media != null) {
|
||||
singleEmitter.onSuccess(media);
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
singleEmitter.onError(new Throwable("qiniu json error"));
|
||||
} else {
|
||||
singleEmitter.onError(new Throwable(info.error));
|
||||
}
|
||||
}, null)));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Single<String> downloadFile(String url) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private DynamicMedia responseToMeia(JSONObject response) {
|
||||
DynamicMedia media = new DynamicMedia();
|
||||
try {
|
||||
String imgNamePath = response.getString("path");
|
||||
media.setResUrl(imgNamePath);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
media.setFormat(response.getString("format"));
|
||||
media.setWidth(response.getInt("w"));
|
||||
media.setHeight(response.getInt("h"));
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
LogUtil.print(ResUtil.getString(R.string.xchat_android_core_file_filemodel_04), media);
|
||||
return media;
|
||||
}
|
||||
|
||||
interface Api {
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@GET("/qiniu/upload/getUploadToken")
|
||||
Single<ServiceResult<UploadToken>> getUploadToken();
|
||||
|
||||
@GET("/tencent/cos/getToken")
|
||||
Single<ServiceResult<CosToken>> getCosToken();
|
||||
}
|
||||
}
|
||||
|
@@ -22,9 +22,4 @@ public interface IFileModel extends IModel {
|
||||
* @return
|
||||
*/
|
||||
Single<String> downloadFile(String url);
|
||||
|
||||
Single<DynamicMedia> uploadFileReturnImageInfo(String path);
|
||||
|
||||
Single<DynamicMedia> uploadFileReturnImageInfo(String path, String qiniuName);
|
||||
|
||||
}
|
||||
|
@@ -1,11 +0,0 @@
|
||||
package com.chwl.core.file;
|
||||
|
||||
import io.realm.internal.Keep;
|
||||
import lombok.Data;
|
||||
|
||||
@Keep
|
||||
@Data
|
||||
public class UploadToken {
|
||||
private String key;
|
||||
private String token;
|
||||
}
|
128
core/src/main/java/com/chwl/core/file/cos/CosClient.kt
Normal file
128
core/src/main/java/com/chwl/core/file/cos/CosClient.kt
Normal file
@@ -0,0 +1,128 @@
|
||||
package com.chwk.core.file.cos
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import com.chwl.library.common.application.Env
|
||||
import com.tencent.cos.xml.CosXmlService
|
||||
import com.tencent.cos.xml.CosXmlServiceConfig
|
||||
import com.tencent.cos.xml.exception.CosXmlClientException
|
||||
import com.tencent.cos.xml.exception.CosXmlServiceException
|
||||
import com.tencent.cos.xml.listener.CosXmlResultListener
|
||||
import com.tencent.cos.xml.model.CosXmlRequest
|
||||
import com.tencent.cos.xml.model.CosXmlResult
|
||||
import com.tencent.cos.xml.transfer.COSXMLUploadTask
|
||||
import com.tencent.cos.xml.transfer.TransferConfig
|
||||
import com.tencent.cos.xml.transfer.TransferManager
|
||||
import io.reactivex.Single
|
||||
import java.io.File
|
||||
|
||||
|
||||
|
||||
object CosClient {
|
||||
private var cosXmlClient: CosXmlService? = null
|
||||
private var credentialProvider: CosCredentialProvider? = null
|
||||
|
||||
private fun getCosXmlClient(context: Context, token: CosToken): CosXmlService {
|
||||
var client = this.cosXmlClient
|
||||
if (client != null && credentialProvider != null) {
|
||||
credentialProvider?.updateCredentials(token.toCredential())
|
||||
return client
|
||||
}
|
||||
// 创建 CosXmlServiceConfig 对象,根据需要修改默认的配置参数
|
||||
val serviceConfig: CosXmlServiceConfig = CosXmlServiceConfig.Builder()
|
||||
.setRegion(token.region)
|
||||
.isHttps(true) // 使用 HTTPS 请求, 默认为 HTTP 请求
|
||||
.builder()
|
||||
|
||||
val credentials = token.toCredential()
|
||||
credentialProvider = CosCredentialProvider(credentials)
|
||||
// 初始化 COS Service,获取实例
|
||||
client = CosXmlService(
|
||||
context,
|
||||
serviceConfig, credentialProvider
|
||||
)
|
||||
cosXmlClient = client
|
||||
return client
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
* @param outName 远端文件名
|
||||
*/
|
||||
fun upload(
|
||||
context: Context,
|
||||
file: File,
|
||||
outName: String,
|
||||
token: CosToken
|
||||
): Single<CosXmlResult> {
|
||||
if (Env.isDebug()) {
|
||||
Log.e("CosClient", "upload file:${file.absolutePath} outName:${outName}")
|
||||
}
|
||||
return Single.create {
|
||||
uploadFile(context, file, outName, token).apply {
|
||||
setCosXmlResultListener(object : CosXmlResultListener {
|
||||
override fun onSuccess(request: CosXmlRequest?, result: CosXmlResult) {
|
||||
transformDomain(result, token)
|
||||
if (Env.isDebug()) {
|
||||
Log.e("CosClient", "upload onSuccess result:${result.accessUrl}")
|
||||
}
|
||||
it.onSuccess(result)
|
||||
}
|
||||
|
||||
override fun onFail(
|
||||
request: CosXmlRequest?,
|
||||
clientException: CosXmlClientException?,
|
||||
serviceException: CosXmlServiceException?
|
||||
) {
|
||||
if (Env.isDebug()) {
|
||||
Log.e("CosClient", "upload onFail clientException:$clientException")
|
||||
Log.e("CosClient", "upload onFail serviceException:$serviceException")
|
||||
}
|
||||
it.onError(CosException(clientException, serviceException))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformDomain(result: CosXmlResult, token: CosToken) {
|
||||
try {
|
||||
if (result.accessUrl.isNullOrEmpty()) {
|
||||
return
|
||||
}
|
||||
if (token.customDomain.isNullOrEmpty()) {
|
||||
return
|
||||
}
|
||||
val newUri = Uri.parse(token.customDomain)
|
||||
result.accessUrl = Uri.parse(result.accessUrl).buildUpon().scheme(newUri.scheme)
|
||||
.authority(newUri.authority).build().toString()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
* @param outName 远端文件名
|
||||
*/
|
||||
private fun uploadFile(
|
||||
context: Context,
|
||||
file: File,
|
||||
outName: String,
|
||||
token: CosToken
|
||||
): COSXMLUploadTask {
|
||||
val cosXmlService = getCosXmlClient(context, token)
|
||||
// 初始化 TransferConfig,这里使用默认配置,如果需要定制,请参考 SDK 接口文档
|
||||
val transferConfig = TransferConfig.Builder().build()
|
||||
// 初始化 TransferManager
|
||||
val transferManager = TransferManager(
|
||||
cosXmlService,
|
||||
transferConfig
|
||||
)
|
||||
return transferManager.upload(
|
||||
token.bucket, outName,
|
||||
file.absolutePath, null
|
||||
)
|
||||
}
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
package com.chwk.core.file.cos
|
||||
|
||||
import com.tencent.qcloud.core.auth.BasicLifecycleCredentialProvider
|
||||
import com.tencent.qcloud.core.auth.QCloudLifecycleCredentials
|
||||
|
||||
class CosCredentialProvider(private var credentials: QCloudLifecycleCredentials) :
|
||||
BasicLifecycleCredentialProvider() {
|
||||
|
||||
fun updateCredentials(credentials: QCloudLifecycleCredentials) {
|
||||
this.credentials = credentials
|
||||
}
|
||||
|
||||
override fun fetchNewCredentials(): QCloudLifecycleCredentials {
|
||||
return credentials
|
||||
}
|
||||
}
|
18
core/src/main/java/com/chwl/core/file/cos/CosException.kt
Normal file
18
core/src/main/java/com/chwl/core/file/cos/CosException.kt
Normal file
@@ -0,0 +1,18 @@
|
||||
package com.chwk.core.file.cos
|
||||
|
||||
import com.tencent.cos.xml.exception.CosXmlClientException
|
||||
import com.tencent.cos.xml.exception.CosXmlServiceException
|
||||
|
||||
|
||||
class CosException : Exception {
|
||||
var clientException: CosXmlClientException? = null
|
||||
var serviceException: CosXmlServiceException? = null
|
||||
|
||||
constructor(
|
||||
clientException: CosXmlClientException?,
|
||||
serviceException: CosXmlServiceException?
|
||||
) : super(clientException ?: serviceException) {
|
||||
this.clientException = clientException
|
||||
this.serviceException = serviceException
|
||||
}
|
||||
}
|
41
core/src/main/java/com/chwl/core/file/cos/CosToken.kt
Normal file
41
core/src/main/java/com/chwl/core/file/cos/CosToken.kt
Normal file
@@ -0,0 +1,41 @@
|
||||
package com.chwk.core.file.cos
|
||||
|
||||
import com.chwl.core.utils.CurrentTimeUtils
|
||||
import com.tencent.qcloud.core.auth.QCloudLifecycleCredentials
|
||||
import com.tencent.qcloud.core.auth.SessionQCloudCredentials
|
||||
|
||||
|
||||
data class CosToken(
|
||||
val secretId: String?,
|
||||
val secretKey: String?,
|
||||
val sessionToken: String?,
|
||||
val bucket: String?,
|
||||
val region: String?,
|
||||
val startTime: Long?,
|
||||
val expireTime: Long?,
|
||||
val customDomain: String?
|
||||
) {
|
||||
|
||||
/**
|
||||
* 是否有效
|
||||
*/
|
||||
fun isValid(): Boolean {
|
||||
if (expireTime == null) {
|
||||
return false
|
||||
}
|
||||
val currentTime = CurrentTimeUtils.getCurrentTime() / 1000
|
||||
// 预留一点安全时长
|
||||
var safeTime = 30
|
||||
if (safeTime >= (expireTime - (startTime ?: 0))) {
|
||||
safeTime = 0
|
||||
}
|
||||
return currentTime <= (expireTime - safeTime)
|
||||
}
|
||||
|
||||
fun toCredential(): QCloudLifecycleCredentials {
|
||||
return SessionQCloudCredentials(
|
||||
secretId ?: "", secretKey ?: "",
|
||||
sessionToken ?: "", startTime ?: 0, expireTime ?: 0
|
||||
)
|
||||
}
|
||||
}
|
@@ -2,6 +2,7 @@ package com.chwl.core.community.bean;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import kotlin.jvm.Transient;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
@@ -26,6 +27,15 @@ public class DynamicMedia {
|
||||
private String format;
|
||||
private int width;
|
||||
private int height;
|
||||
@Transient
|
||||
private String localFilePath;
|
||||
public String getLocalFilePath() {
|
||||
return localFilePath;
|
||||
}
|
||||
|
||||
public void setLocalFilePath(String localFilePath) {
|
||||
this.localFilePath = localFilePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是网络图片
|
||||
|
@@ -57,7 +57,6 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
def qiniu = "8.4.4"
|
||||
def SmartRefreshLayoutVersion = "1.0.3"
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
|
||||
@@ -87,8 +86,6 @@ dependencies {
|
||||
|
||||
api "com.orhanobut:logger:2.2.0"
|
||||
|
||||
api "com.qiniu:qiniu-android-sdk:${qiniu}"
|
||||
|
||||
api "org.greenrobot:eventbus:3.3.1"
|
||||
api "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
|
||||
@@ -120,6 +117,8 @@ dependencies {
|
||||
api project(':libs:lib_utils')
|
||||
api project(':libs:lib_core')
|
||||
api project(':libs:lib_encipher')
|
||||
|
||||
api 'com.qcloud.cos:cos-android:5.9.25'
|
||||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
@@ -33,247 +33,247 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class JXImageUtils {
|
||||
public static final int IMAGE_COMPRESS_RATE = 80;
|
||||
public static final int IMAGE_SCALE_WIDTH = 800;
|
||||
public static final int IMAGE_SCALE_HEIGHT = 800;
|
||||
public static Bitmap decodeFile(String filePath) {
|
||||
return decodeFile(filePath, null);
|
||||
}
|
||||
|
||||
public static Bitmap decodeByWidth(String filePath, int desiredWidth) {
|
||||
try {
|
||||
return decodeFileOrThrow(filePath, desiredWidth, 0);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Bitmap decodeBySize(String filePath, int size) {
|
||||
Rect rect = decodeBmpSize(filePath);
|
||||
if (rect.width() > rect.height()) {
|
||||
return decodeByWidth(filePath, size);
|
||||
}
|
||||
else {
|
||||
return decodeByHeight(filePath, size);
|
||||
}
|
||||
}
|
||||
public static final int IMAGE_COMPRESS_RATE = 80;
|
||||
public static final int IMAGE_SCALE_WIDTH = 800;
|
||||
public static final int IMAGE_SCALE_HEIGHT = 800;
|
||||
public static Bitmap decodeFile(String filePath) {
|
||||
return decodeFile(filePath, null);
|
||||
}
|
||||
|
||||
public static Rect decodeBmpSize(String filePath) {
|
||||
Options opts = new Options();
|
||||
opts.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeFile(filePath, opts);
|
||||
return new Rect(0, 0, opts.outWidth, opts.outHeight);
|
||||
}
|
||||
|
||||
public static Rect decodeBmpSizeBy(String filePath, int desiredWidth, int desiredHeight) {
|
||||
Options opts = getProperOptions(filePath, desiredWidth, desiredHeight, false);
|
||||
if (opts == null) {
|
||||
return null;
|
||||
}
|
||||
return new Rect(0, 0, opts.outWidth, opts.outHeight);
|
||||
}
|
||||
|
||||
public static Bitmap decodeByHeight(String filePath, int desiredHeight) {
|
||||
try {
|
||||
return decodeFileOrThrow(filePath, 0, desiredHeight);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Bitmap decodeByWidthOrThrow(String filePath, int desiredWidth) {
|
||||
return decodeFileOrThrow(filePath, desiredWidth, 0);
|
||||
}
|
||||
|
||||
public static Bitmap decodeByHeightOrThrow(String filePath, int desiredHeight) {
|
||||
return decodeFileOrThrow(filePath, 0, desiredHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode file with given options.
|
||||
* Will prefer use a smaller sample size to save memory,
|
||||
* If this is not up to demand, use the one with more parameter:
|
||||
* {@link #decodeFileOrThrow(String, int, int, boolean)}.
|
||||
* NOTE OutOfMemoryError will be eaten here, and null returned in this case.
|
||||
* @param filePath File path.
|
||||
* @param desiredWidth Desired width, can be 0.
|
||||
* If set to 0, desiredHeight will be honored.
|
||||
* If both desiredWidth and desiredHeight are 0,
|
||||
* the original bitmap will be decoded.
|
||||
* @param desiredHeight Desired height, can be 0.
|
||||
* If set to 0, desiredWidth will be honored.
|
||||
* If both desiredWidth and desiredHeight are 0,
|
||||
* the original bitmap will be decoded.
|
||||
* @return Bitmap decoded, or null if failed.
|
||||
*/
|
||||
public static Bitmap decodeFile(String filePath, int desiredWidth, int desiredHeight) {
|
||||
try {
|
||||
return decodeFileOrThrow(filePath, desiredWidth, desiredHeight);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
MLog.warn("decoeFile", "fail to decode %s, %s", filePath, e.toString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode file with given options.
|
||||
* Will prefer use a smaller sample size to save memory,
|
||||
* If this is not up to demand, use the one with more parameter:
|
||||
* {@link #decodeFileOrThrow(String, int, int, boolean)}.
|
||||
* NOTE OutOfMemoryError will be eaten here, and null returned in this case.
|
||||
* @param resId resId
|
||||
* @param desiredWidth Desired width, can be 0.
|
||||
* If set to 0, desiredHeight will be honored.
|
||||
* If both desiredWidth and desiredHeight are 0,
|
||||
* the original bitmap will be decoded.
|
||||
* @param desiredHeight Desired height, can be 0.
|
||||
* If set to 0, desiredWidth will be honored.
|
||||
* If both desiredWidth and desiredHeight are 0,
|
||||
* the original bitmap will be decoded.
|
||||
* @return Bitmap decoded, or null if failed.
|
||||
*/
|
||||
public static Bitmap decodeResource(Context context, int resId, int desiredWidth, int desiredHeight) {
|
||||
if (desiredWidth <= 0 && desiredHeight <= 0) {
|
||||
return decodeResource(context, resId);
|
||||
}
|
||||
try {
|
||||
return decodeResOrThrow(context, resId, desiredWidth, desiredHeight, true);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
MLog.error("JXImageUtils", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Bitmap decodeResource(Context context, int resId) {
|
||||
try {
|
||||
final Bitmap res = BitmapFactory.decodeResource(context.getResources(), resId);
|
||||
return res;
|
||||
}
|
||||
catch (OutOfMemoryError e) {
|
||||
MLog.error("JXImageUtils", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static Bitmap decodeByWidth(String filePath, int desiredWidth) {
|
||||
try {
|
||||
return decodeFileOrThrow(filePath, desiredWidth, 0);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode file with given options.
|
||||
* Will prefer use a smaller sample size to save memory,
|
||||
* If this is not up to demand, use the one with more parameter:
|
||||
* {@link #decodeFileOrThrow(String, int, int, boolean)}.
|
||||
* NOTE OutOfMemoryError can be throw here.
|
||||
* @param filePath File path.
|
||||
* @param desiredWidth Desired width, can be 0.
|
||||
* If set to 0, desiredHeight will be honored.
|
||||
* If both desiredWidth and desiredHeight are 0,
|
||||
* the original bitmap will be decoded.
|
||||
* @param desiredHeight Desired height, can be 0.
|
||||
* If set to 0, desiredWidth will be honored.
|
||||
* If both desiredWidth and desiredHeight are 0,
|
||||
* the original bitmap will be decoded.
|
||||
* @return Bitmap decoded, or null if failed.
|
||||
*/
|
||||
public static Bitmap decodeFileOrThrow(String filePath, int desiredWidth, int desiredHeight) {
|
||||
return decodeFileOrThrow(filePath, desiredWidth, desiredHeight, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode file with given options.
|
||||
* NOTE OutOfMemoryError can be throw here.
|
||||
* @param filePath File path.
|
||||
* @param desiredWidth Desired width, can be 0.
|
||||
* If set to 0, maximum width will be used,
|
||||
* i.e. : desiredHeight will take effect.
|
||||
* If both desiredWidth and desiredHeight are 0,
|
||||
* the original bitmap will be decoded.
|
||||
* @param desiredHeight Desired height, can be 0.
|
||||
* If set to 0, maximum height will be used.
|
||||
* i.e. : desiredWidth will take effect.
|
||||
* If both desiredWidth and desiredHeight are 0,
|
||||
* the original bitmap will be decoded.
|
||||
* @param isMemoryPrior If true, will prefer to use a bigger sample size
|
||||
* to use less memory, otherwise prefer to use a smaller
|
||||
* sample size, the the returned bitmap can be with bigger size,
|
||||
* and can be probably more vivid.
|
||||
* @return Bitmap decoded, or null if failed.
|
||||
*/
|
||||
public static Bitmap decodeFileOrThrow(String filePath,
|
||||
int desiredWidth, int desiredHeight, boolean isMemoryPrior) {
|
||||
public static Bitmap decodeBySize(String filePath, int size) {
|
||||
Rect rect = decodeBmpSize(filePath);
|
||||
if (rect.width() > rect.height()) {
|
||||
return decodeByWidth(filePath, size);
|
||||
}
|
||||
else {
|
||||
return decodeByHeight(filePath, size);
|
||||
}
|
||||
}
|
||||
|
||||
public static Rect decodeBmpSize(String filePath) {
|
||||
Options opts = new Options();
|
||||
opts.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeFile(filePath, opts);
|
||||
return new Rect(0, 0, opts.outWidth, opts.outHeight);
|
||||
}
|
||||
|
||||
public static Rect decodeBmpSizeBy(String filePath, int desiredWidth, int desiredHeight) {
|
||||
Options opts = getProperOptions(filePath, desiredWidth, desiredHeight, false);
|
||||
if (opts == null) {
|
||||
return null;
|
||||
}
|
||||
return new Rect(0, 0, opts.outWidth, opts.outHeight);
|
||||
}
|
||||
|
||||
public static Bitmap decodeByHeight(String filePath, int desiredHeight) {
|
||||
try {
|
||||
return decodeFileOrThrow(filePath, 0, desiredHeight);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Bitmap decodeByWidthOrThrow(String filePath, int desiredWidth) {
|
||||
return decodeFileOrThrow(filePath, desiredWidth, 0);
|
||||
}
|
||||
|
||||
public static Bitmap decodeByHeightOrThrow(String filePath, int desiredHeight) {
|
||||
return decodeFileOrThrow(filePath, 0, desiredHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode file with given options.
|
||||
* Will prefer use a smaller sample size to save memory,
|
||||
* If this is not up to demand, use the one with more parameter:
|
||||
* {@link #decodeFileOrThrow(String, int, int, boolean)}.
|
||||
* NOTE OutOfMemoryError will be eaten here, and null returned in this case.
|
||||
* @param filePath File path.
|
||||
* @param desiredWidth Desired width, can be 0.
|
||||
* If set to 0, desiredHeight will be honored.
|
||||
* If both desiredWidth and desiredHeight are 0,
|
||||
* the original bitmap will be decoded.
|
||||
* @param desiredHeight Desired height, can be 0.
|
||||
* If set to 0, desiredWidth will be honored.
|
||||
* If both desiredWidth and desiredHeight are 0,
|
||||
* the original bitmap will be decoded.
|
||||
* @return Bitmap decoded, or null if failed.
|
||||
*/
|
||||
public static Bitmap decodeFile(String filePath, int desiredWidth, int desiredHeight) {
|
||||
try {
|
||||
return decodeFileOrThrow(filePath, desiredWidth, desiredHeight);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
MLog.warn("decoeFile", "fail to decode %s, %s", filePath, e.toString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode file with given options.
|
||||
* Will prefer use a smaller sample size to save memory,
|
||||
* If this is not up to demand, use the one with more parameter:
|
||||
* {@link #decodeFileOrThrow(String, int, int, boolean)}.
|
||||
* NOTE OutOfMemoryError will be eaten here, and null returned in this case.
|
||||
* @param resId resId
|
||||
* @param desiredWidth Desired width, can be 0.
|
||||
* If set to 0, desiredHeight will be honored.
|
||||
* If both desiredWidth and desiredHeight are 0,
|
||||
* the original bitmap will be decoded.
|
||||
* @param desiredHeight Desired height, can be 0.
|
||||
* If set to 0, desiredWidth will be honored.
|
||||
* If both desiredWidth and desiredHeight are 0,
|
||||
* the original bitmap will be decoded.
|
||||
* @return Bitmap decoded, or null if failed.
|
||||
*/
|
||||
public static Bitmap decodeResource(Context context, int resId, int desiredWidth, int desiredHeight) {
|
||||
if (desiredWidth <= 0 && desiredHeight <= 0) {
|
||||
return decodeResource(context, resId);
|
||||
}
|
||||
try {
|
||||
return decodeResOrThrow(context, resId, desiredWidth, desiredHeight, true);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
MLog.error("JXImageUtils", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Bitmap decodeResource(Context context, int resId) {
|
||||
try {
|
||||
final Bitmap res = BitmapFactory.decodeResource(context.getResources(), resId);
|
||||
return res;
|
||||
}
|
||||
catch (OutOfMemoryError e) {
|
||||
MLog.error("JXImageUtils", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode file with given options.
|
||||
* Will prefer use a smaller sample size to save memory,
|
||||
* If this is not up to demand, use the one with more parameter:
|
||||
* {@link #decodeFileOrThrow(String, int, int, boolean)}.
|
||||
* NOTE OutOfMemoryError can be throw here.
|
||||
* @param filePath File path.
|
||||
* @param desiredWidth Desired width, can be 0.
|
||||
* If set to 0, desiredHeight will be honored.
|
||||
* If both desiredWidth and desiredHeight are 0,
|
||||
* the original bitmap will be decoded.
|
||||
* @param desiredHeight Desired height, can be 0.
|
||||
* If set to 0, desiredWidth will be honored.
|
||||
* If both desiredWidth and desiredHeight are 0,
|
||||
* the original bitmap will be decoded.
|
||||
* @return Bitmap decoded, or null if failed.
|
||||
*/
|
||||
public static Bitmap decodeFileOrThrow(String filePath, int desiredWidth, int desiredHeight) {
|
||||
return decodeFileOrThrow(filePath, desiredWidth, desiredHeight, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode file with given options.
|
||||
* NOTE OutOfMemoryError can be throw here.
|
||||
* @param filePath File path.
|
||||
* @param desiredWidth Desired width, can be 0.
|
||||
* If set to 0, maximum width will be used,
|
||||
* i.e. : desiredHeight will take effect.
|
||||
* If both desiredWidth and desiredHeight are 0,
|
||||
* the original bitmap will be decoded.
|
||||
* @param desiredHeight Desired height, can be 0.
|
||||
* If set to 0, maximum height will be used.
|
||||
* i.e. : desiredWidth will take effect.
|
||||
* If both desiredWidth and desiredHeight are 0,
|
||||
* the original bitmap will be decoded.
|
||||
* @param isMemoryPrior If true, will prefer to use a bigger sample size
|
||||
* to use less memory, otherwise prefer to use a smaller
|
||||
* sample size, the the returned bitmap can be with bigger size,
|
||||
* and can be probably more vivid.
|
||||
* @return Bitmap decoded, or null if failed.
|
||||
*/
|
||||
public static Bitmap decodeFileOrThrow(String filePath,
|
||||
int desiredWidth, int desiredHeight, boolean isMemoryPrior) {
|
||||
Options opts = getProperOptions(filePath, desiredWidth, desiredHeight, isMemoryPrior);
|
||||
if (opts == null) {
|
||||
return null;
|
||||
return null;
|
||||
}
|
||||
opts.inJustDecodeBounds = false;
|
||||
final Bitmap bmp = BitmapFactory.decodeFile(filePath, opts);
|
||||
return bmp;
|
||||
}
|
||||
|
||||
private static Options getProperOptions(String filePath, int desiredWidth, int desiredHeight,
|
||||
boolean isMemoryPrior) {
|
||||
Options opts = new Options();
|
||||
opts.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeFile(filePath, opts);
|
||||
if (opts.outWidth <= 0 || opts.outHeight <= 0) {
|
||||
return null;
|
||||
}
|
||||
return bmp;
|
||||
}
|
||||
|
||||
int sampleSize = calSampleSize(desiredWidth, desiredHeight, isMemoryPrior, opts);
|
||||
|
||||
if (desiredHeight > 0 || desiredWidth > 0) {
|
||||
do {
|
||||
opts.inSampleSize = sampleSize;
|
||||
BitmapFactory.decodeFile(filePath, opts);
|
||||
sampleSize++;
|
||||
}
|
||||
while ((desiredWidth > 0 && opts.outWidth > desiredWidth)
|
||||
|| (desiredHeight > 0 && opts.outHeight > desiredHeight));
|
||||
}
|
||||
return opts;
|
||||
}
|
||||
private static Options getProperOptions(String filePath, int desiredWidth, int desiredHeight,
|
||||
boolean isMemoryPrior) {
|
||||
Options opts = new Options();
|
||||
opts.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeFile(filePath, opts);
|
||||
if (opts.outWidth <= 0 || opts.outHeight <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode file with given options.
|
||||
* NOTE OutOfMemoryError can be throw here.
|
||||
* @param desiredWidth Desired width, can be 0.
|
||||
* If set to 0, maximum width will be used,
|
||||
* i.e. : desiredHeight will take effect.
|
||||
* If both desiredWidth and desiredHeight are 0,
|
||||
* the original bitmap will be decoded.
|
||||
* @param desiredHeight Desired height, can be 0.
|
||||
* If set to 0, maximum height will be used.
|
||||
* i.e. : desiredWidth will take effect.
|
||||
* If both desiredWidth and desiredHeight are 0,
|
||||
* the original bitmap will be decoded.
|
||||
* @param isMemoryPrior If true, will prefer to use a bigger sample size
|
||||
* to use less memory, otherwise prefer to use a smaller
|
||||
* sample size, the the returned bitmap can be with bigger size,
|
||||
* and can be probably more vivid.
|
||||
* @return Bitmap decoded, or null if failed.
|
||||
*/
|
||||
public static Bitmap decodeResOrThrow(Context context, int drawableId,
|
||||
int desiredWidth, int desiredHeight, boolean isMemoryPrior) {
|
||||
Options opts = new Options();
|
||||
opts.inJustDecodeBounds = true;
|
||||
|
||||
final Resources res = context.getResources();
|
||||
BitmapFactory.decodeResource(res, drawableId, opts);
|
||||
if (opts.outWidth <= 0 || opts.outHeight <= 0) {
|
||||
return null;
|
||||
}
|
||||
int sampleSize = calSampleSize(desiredWidth, desiredHeight, isMemoryPrior, opts);
|
||||
|
||||
int sampleSize = calSampleSize(desiredWidth, desiredHeight, isMemoryPrior, opts);
|
||||
if (desiredHeight > 0 || desiredWidth > 0) {
|
||||
do {
|
||||
opts.inSampleSize = sampleSize;
|
||||
BitmapFactory.decodeFile(filePath, opts);
|
||||
sampleSize++;
|
||||
}
|
||||
while ((desiredWidth > 0 && opts.outWidth > desiredWidth)
|
||||
|| (desiredHeight > 0 && opts.outHeight > desiredHeight));
|
||||
}
|
||||
return opts;
|
||||
}
|
||||
|
||||
opts.inJustDecodeBounds = false;
|
||||
opts.inSampleSize = sampleSize;
|
||||
final Bitmap ret = BitmapFactory.decodeResource(res, drawableId, opts);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static int calSampleSize(int desiredWidth, int desiredHeight, boolean isMemoryPrior, Options opts) {
|
||||
int sampleSize = 1;
|
||||
/**
|
||||
* Decode file with given options.
|
||||
* NOTE OutOfMemoryError can be throw here.
|
||||
* @param desiredWidth Desired width, can be 0.
|
||||
* If set to 0, maximum width will be used,
|
||||
* i.e. : desiredHeight will take effect.
|
||||
* If both desiredWidth and desiredHeight are 0,
|
||||
* the original bitmap will be decoded.
|
||||
* @param desiredHeight Desired height, can be 0.
|
||||
* If set to 0, maximum height will be used.
|
||||
* i.e. : desiredWidth will take effect.
|
||||
* If both desiredWidth and desiredHeight are 0,
|
||||
* the original bitmap will be decoded.
|
||||
* @param isMemoryPrior If true, will prefer to use a bigger sample size
|
||||
* to use less memory, otherwise prefer to use a smaller
|
||||
* sample size, the the returned bitmap can be with bigger size,
|
||||
* and can be probably more vivid.
|
||||
* @return Bitmap decoded, or null if failed.
|
||||
*/
|
||||
public static Bitmap decodeResOrThrow(Context context, int drawableId,
|
||||
int desiredWidth, int desiredHeight, boolean isMemoryPrior) {
|
||||
Options opts = new Options();
|
||||
opts.inJustDecodeBounds = true;
|
||||
|
||||
final Resources res = context.getResources();
|
||||
BitmapFactory.decodeResource(res, drawableId, opts);
|
||||
if (opts.outWidth <= 0 || opts.outHeight <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int sampleSize = calSampleSize(desiredWidth, desiredHeight, isMemoryPrior, opts);
|
||||
|
||||
opts.inJustDecodeBounds = false;
|
||||
opts.inSampleSize = sampleSize;
|
||||
final Bitmap ret = BitmapFactory.decodeResource(res, drawableId, opts);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static int calSampleSize(int desiredWidth, int desiredHeight, boolean isMemoryPrior, Options opts) {
|
||||
int sampleSize = 1;
|
||||
if (desiredWidth == 0 && desiredHeight == 0) {
|
||||
sampleSize = 1;
|
||||
}
|
||||
@@ -288,28 +288,28 @@ public class JXImageUtils {
|
||||
final int verRatio = (opts.outHeight + desiredHeight - 1) / desiredHeight;
|
||||
sampleSize = isMemoryPrior ? Math.max(horRatio, verRatio) : Math.min(horRatio, verRatio);
|
||||
}
|
||||
return sampleSize;
|
||||
}
|
||||
|
||||
public static Bitmap decodeFile(String filePath, Options opt) {
|
||||
if (StringUtils.isEmpty(filePath)) {
|
||||
return null;
|
||||
}
|
||||
Bitmap bmp = null;
|
||||
try {
|
||||
File file = new File(filePath);
|
||||
if (file.isFile()) {
|
||||
bmp = BitmapFactory.decodeFile(filePath, opt);
|
||||
}
|
||||
else {
|
||||
MLog.error(JXImageUtils.class, filePath + " is not a file");
|
||||
}
|
||||
} catch (OutOfMemoryError err) {
|
||||
MLog.error(JXImageUtils.class, "oom: " + filePath);
|
||||
bmp = null;
|
||||
}
|
||||
return bmp;
|
||||
}
|
||||
return sampleSize;
|
||||
}
|
||||
|
||||
public static Bitmap decodeFile(String filePath, Options opt) {
|
||||
if (StringUtils.isEmpty(filePath)) {
|
||||
return null;
|
||||
}
|
||||
Bitmap bmp = null;
|
||||
try {
|
||||
File file = new File(filePath);
|
||||
if (file.isFile()) {
|
||||
bmp = BitmapFactory.decodeFile(filePath, opt);
|
||||
}
|
||||
else {
|
||||
MLog.error(JXImageUtils.class, filePath + " is not a file");
|
||||
}
|
||||
} catch (OutOfMemoryError err) {
|
||||
MLog.error(JXImageUtils.class, "oom: " + filePath);
|
||||
bmp = null;
|
||||
}
|
||||
return bmp;
|
||||
}
|
||||
|
||||
public static Bitmap resizeBitmap(Bitmap bitmap, int maxBorderLength, boolean recycle) {
|
||||
if (bitmap == null) {
|
||||
@@ -346,7 +346,7 @@ public class JXImageUtils {
|
||||
return resizedBitmap;
|
||||
}
|
||||
catch (OutOfMemoryError e) {
|
||||
MLog.error(JXImageUtils.class, "lcy resizeBitmap OOM %s", e);
|
||||
MLog.error(JXImageUtils.class, "lcy resizeBitmap OOM %s", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -389,7 +389,7 @@ public class JXImageUtils {
|
||||
Bitmap bitmap = null;
|
||||
try {
|
||||
bitmap = BitmapFactory.decodeFile(imageFile, options);
|
||||
|
||||
|
||||
|
||||
if( matrix != null ) {
|
||||
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
|
||||
@@ -415,7 +415,7 @@ public class JXImageUtils {
|
||||
try {
|
||||
ExifInterface exif = new ExifInterface(filepath);
|
||||
return exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
|
||||
ExifInterface.ORIENTATION_NORMAL);
|
||||
ExifInterface.ORIENTATION_NORMAL);
|
||||
}
|
||||
catch (Exception e) {
|
||||
return 0;
|
||||
@@ -424,20 +424,20 @@ public class JXImageUtils {
|
||||
|
||||
public static int getAngleFromRotateEnum(int rotate) {
|
||||
switch (rotate) {
|
||||
case ExifInterface.ORIENTATION_ROTATE_180:
|
||||
return 180;
|
||||
case ExifInterface.ORIENTATION_ROTATE_90:
|
||||
return 90;
|
||||
case ExifInterface.ORIENTATION_ROTATE_270:
|
||||
return 270;
|
||||
default:
|
||||
return 0;
|
||||
case ExifInterface.ORIENTATION_ROTATE_180:
|
||||
return 180;
|
||||
case ExifInterface.ORIENTATION_ROTATE_90:
|
||||
return 90;
|
||||
case ExifInterface.ORIENTATION_ROTATE_270:
|
||||
return 270;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// resize bitmap if it's size exceeded maxWidth or maxHeight. and return the passed in bitmap if
|
||||
// no need to change size
|
||||
// no need to change size
|
||||
public static Bitmap rotateAndResizeImage(Bitmap inBitmap, int maxWidth, int maxHeight, int rotate) {
|
||||
int imgWidth = inBitmap.getWidth();
|
||||
int imgHeight = inBitmap.getHeight();
|
||||
@@ -453,8 +453,8 @@ public class JXImageUtils {
|
||||
matrix.postRotate(getAngleFromRotateEnum(rotate));
|
||||
}
|
||||
try {
|
||||
Bitmap resultBitmap = Bitmap.createBitmap(inBitmap, 0, 0, imgWidth, imgHeight, matrix, true);
|
||||
return resultBitmap;
|
||||
Bitmap resultBitmap = Bitmap.createBitmap(inBitmap, 0, 0, imgWidth, imgHeight, matrix, true);
|
||||
return resultBitmap;
|
||||
}
|
||||
catch (OutOfMemoryError e) {
|
||||
}
|
||||
@@ -480,15 +480,15 @@ public class JXImageUtils {
|
||||
options.inScaled = false;
|
||||
|
||||
try {
|
||||
final Bitmap ret = BitmapFactory.decodeStream(decodeStream, null, options);
|
||||
return ret;
|
||||
final Bitmap ret = BitmapFactory.decodeStream(decodeStream, null, options);
|
||||
return ret;
|
||||
}
|
||||
catch (OutOfMemoryError e) {
|
||||
MLog.error("JXImageUtils", "decodeImageFromStream error, OOM");
|
||||
MLog.error("JXImageUtils", "decodeImageFromStream error, OOM");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static void saveBitmapToFile(Bitmap bitmap, String filename) throws Exception {
|
||||
if (bitmap != null && filename != null) {
|
||||
JXFileUtils out = JXFileUtils.openFile(filename);
|
||||
@@ -502,36 +502,36 @@ public class JXImageUtils {
|
||||
options.outHeight = 0;
|
||||
options.inJustDecodeBounds = true;
|
||||
try {
|
||||
BitmapFactory.decodeStream(queryStream, null, options);
|
||||
return (options.outWidth > 0 && options.outHeight > 0);
|
||||
BitmapFactory.decodeStream(queryStream, null, options);
|
||||
return (options.outWidth > 0 && options.outHeight > 0);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static boolean isImage(File file) {
|
||||
if (file == null) {
|
||||
return false;
|
||||
}
|
||||
return isImage(file.getPath());
|
||||
if (file == null) {
|
||||
return false;
|
||||
}
|
||||
return isImage(file.getPath());
|
||||
}
|
||||
|
||||
public static boolean isImage(String imageFile) {
|
||||
|
||||
if (StringUtils.isEmpty(imageFile)) {
|
||||
return false;
|
||||
}
|
||||
if (StringUtils.isEmpty(imageFile)) {
|
||||
return false;
|
||||
}
|
||||
Options options = new Options();
|
||||
options.outHeight = 0;
|
||||
options.inJustDecodeBounds = true;
|
||||
try {
|
||||
BitmapFactory.decodeFile(imageFile, options);
|
||||
return (options.outWidth > 0 && options.outHeight > 0);
|
||||
BitmapFactory.decodeFile(imageFile, options);
|
||||
return (options.outWidth > 0 && options.outHeight > 0);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
MLog.verbose("JXImageUtils", "%d isn't image file", imageFile);
|
||||
return false;
|
||||
MLog.verbose("JXImageUtils", "%d isn't image file", imageFile);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -550,136 +550,136 @@ public class JXImageUtils {
|
||||
canvas.drawBitmap(bitmap, rect, rect, paint);
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
private static Bitmap sDefaultMalePhoto = null;
|
||||
private static Bitmap sDefaultMalePhotoOffline = null;
|
||||
private static Bitmap sDefaultFemalePhotoOffline = null;
|
||||
private static Bitmap sDefaultMalePhotoBitmap = null;
|
||||
private static Bitmap sDefaultFemalePhotoBitmap = null;
|
||||
|
||||
|
||||
public static boolean isNotDefaultPortrait(Bitmap image) {
|
||||
return (image != sDefaultFemalePhotoBitmap && image != sDefaultMalePhotoBitmap
|
||||
&& image != sDefaultMalePhotoOffline && image != sDefaultFemalePhotoOffline
|
||||
&& image != sDefaultMalePhoto && image != sDefaultMalePhotoOffline);
|
||||
}
|
||||
|
||||
public static Bitmap getGrayBmp(final Bitmap image) {
|
||||
if (image != null) {
|
||||
try {
|
||||
Bitmap grayscalBitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(),
|
||||
Config.RGB_565);
|
||||
Canvas canvas = new Canvas(grayscalBitmap);
|
||||
Paint paint = new Paint();
|
||||
ColorMatrix matrix = new ColorMatrix();
|
||||
matrix.setSaturation(0);
|
||||
ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrix);
|
||||
paint.setColorFilter(filter);
|
||||
canvas.drawBitmap(image, 0, 0, paint);
|
||||
|
||||
return grayscalBitmap;
|
||||
}
|
||||
catch (Exception e) {
|
||||
MLog.error("Utils.getGrayBmp", e);
|
||||
} catch (OutOfMemoryError e) {
|
||||
MLog.error("Utils.getGrayBmp", e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Bitmap createClipBitmap(Bitmap bmp, Rect photoRect) {
|
||||
// the right and bottom must be checked for their values are converted
|
||||
// from float math to integer value and might be bigger than actual
|
||||
// bitmap because of round error
|
||||
Bitmap portrait = null;
|
||||
try {
|
||||
if (bmp != null) {
|
||||
int bmpWidth = bmp.getWidth();
|
||||
int bmpHeight = bmp.getHeight();
|
||||
if (bmpWidth > 0 && bmpHeight > 0) {
|
||||
photoRect.right = photoRect.right > bmpWidth ? bmpWidth
|
||||
: photoRect.right;
|
||||
photoRect.bottom = photoRect.bottom > bmpHeight ? bmpHeight
|
||||
: photoRect.bottom;
|
||||
portrait = Bitmap.createBitmap(bmp, photoRect.left,
|
||||
photoRect.top, photoRect.width(), photoRect.height());
|
||||
|
||||
if (bmp != portrait && !bmp.isRecycled()) // old bitmap is useless, free memory
|
||||
bmp.recycle();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable e) {
|
||||
MLog.debug("hjinw", "e = " + e);
|
||||
}
|
||||
return portrait;
|
||||
}
|
||||
return (image != sDefaultFemalePhotoBitmap && image != sDefaultMalePhotoBitmap
|
||||
&& image != sDefaultMalePhotoOffline && image != sDefaultFemalePhotoOffline
|
||||
&& image != sDefaultMalePhoto && image != sDefaultMalePhotoOffline);
|
||||
}
|
||||
|
||||
public static boolean renameFile(String oriPath, String newPath) {
|
||||
File file = new File(oriPath);
|
||||
File newFile = new File(newPath);
|
||||
return file.renameTo(newFile);
|
||||
}
|
||||
public static Bitmap getGrayBmp(final Bitmap image) {
|
||||
if (image != null) {
|
||||
try {
|
||||
Bitmap grayscalBitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(),
|
||||
Config.RGB_565);
|
||||
Canvas canvas = new Canvas(grayscalBitmap);
|
||||
Paint paint = new Paint();
|
||||
ColorMatrix matrix = new ColorMatrix();
|
||||
matrix.setSaturation(0);
|
||||
ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrix);
|
||||
paint.setColorFilter(filter);
|
||||
canvas.drawBitmap(image, 0, 0, paint);
|
||||
|
||||
public static Bitmap decodeResource(Context context, int resId, Options opt) {
|
||||
try {
|
||||
final Bitmap res = BitmapFactory.decodeResource(context.getResources(),
|
||||
resId, opt);
|
||||
return res;
|
||||
}
|
||||
catch (OutOfMemoryError e) {
|
||||
MLog.error("lcy", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static interface PORTRAIT_OPS {
|
||||
public static final int SMALL = 0;
|
||||
public static final int BIG = 1;
|
||||
public static final int ORIGINAL = 2;
|
||||
}
|
||||
return grayscalBitmap;
|
||||
}
|
||||
catch (Exception e) {
|
||||
MLog.error("Utils.getGrayBmp", e);
|
||||
} catch (OutOfMemoryError e) {
|
||||
MLog.error("Utils.getGrayBmp", e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Created blended bitmap for given bitmap.
|
||||
* This aims to be used for the pressed state of an image icon.
|
||||
* This can cost much time for a big sized given bitmap.
|
||||
*
|
||||
* @param src Cannot be null.
|
||||
* @return Blended bitmap.
|
||||
*
|
||||
*/
|
||||
public static Bitmap createBlended(Bitmap src) {
|
||||
if (src == null) {
|
||||
throw new IllegalArgumentException("Given src is null.");
|
||||
}
|
||||
final Bitmap target = Bitmap.createBitmap(src.getWidth(), src.getHeight(), Config.ARGB_8888);
|
||||
Canvas c = new Canvas(target);
|
||||
c.drawBitmap(src, 0, 0, null);
|
||||
c.drawColor(0x8F000000 | (Color.GRAY & 0x00111111));
|
||||
|
||||
return target;
|
||||
}
|
||||
public static Bitmap createClipBitmap(Bitmap bmp, Rect photoRect) {
|
||||
// the right and bottom must be checked for their values are converted
|
||||
// from float math to integer value and might be bigger than actual
|
||||
// bitmap because of round error
|
||||
Bitmap portrait = null;
|
||||
try {
|
||||
if (bmp != null) {
|
||||
int bmpWidth = bmp.getWidth();
|
||||
int bmpHeight = bmp.getHeight();
|
||||
if (bmpWidth > 0 && bmpHeight > 0) {
|
||||
photoRect.right = photoRect.right > bmpWidth ? bmpWidth
|
||||
: photoRect.right;
|
||||
photoRect.bottom = photoRect.bottom > bmpHeight ? bmpHeight
|
||||
: photoRect.bottom;
|
||||
portrait = Bitmap.createBitmap(bmp, photoRect.left,
|
||||
photoRect.top, photoRect.width(), photoRect.height());
|
||||
|
||||
public static Bitmap resize(Bitmap oriBitmap, int targetWidth, int targetHeight) {
|
||||
if (oriBitmap == null) {
|
||||
return null;
|
||||
}
|
||||
int width = oriBitmap.getWidth();
|
||||
int height = oriBitmap.getHeight();
|
||||
float scaleWidth = ((float) targetWidth) / width;
|
||||
float scaleHeight = ((float) targetHeight) / height;
|
||||
float scale = scaleWidth > scaleHeight ? scaleHeight : scaleWidth;
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.postScale(scale, scale);
|
||||
try {
|
||||
Bitmap resizedBitmap = Bitmap.createBitmap(oriBitmap, 0, 0, width, height, matrix, true);
|
||||
return resizedBitmap;
|
||||
}
|
||||
catch (OutOfMemoryError e) {
|
||||
MLog.error(JXImageUtils.class, "resizeBitmap OOM %s", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (bmp != portrait && !bmp.isRecycled()) // old bitmap is useless, free memory
|
||||
bmp.recycle();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable e) {
|
||||
MLog.debug("hjinw", "e = " + e);
|
||||
}
|
||||
return portrait;
|
||||
}
|
||||
|
||||
public static boolean renameFile(String oriPath, String newPath) {
|
||||
File file = new File(oriPath);
|
||||
File newFile = new File(newPath);
|
||||
return file.renameTo(newFile);
|
||||
}
|
||||
|
||||
public static Bitmap decodeResource(Context context, int resId, Options opt) {
|
||||
try {
|
||||
final Bitmap res = BitmapFactory.decodeResource(context.getResources(),
|
||||
resId, opt);
|
||||
return res;
|
||||
}
|
||||
catch (OutOfMemoryError e) {
|
||||
MLog.error("lcy", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static interface PORTRAIT_OPS {
|
||||
public static final int SMALL = 0;
|
||||
public static final int BIG = 1;
|
||||
public static final int ORIGINAL = 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Created blended bitmap for given bitmap.
|
||||
* This aims to be used for the pressed state of an image icon.
|
||||
* This can cost much time for a big sized given bitmap.
|
||||
*
|
||||
* @param src Cannot be null.
|
||||
* @return Blended bitmap.
|
||||
*
|
||||
*/
|
||||
public static Bitmap createBlended(Bitmap src) {
|
||||
if (src == null) {
|
||||
throw new IllegalArgumentException("Given src is null.");
|
||||
}
|
||||
final Bitmap target = Bitmap.createBitmap(src.getWidth(), src.getHeight(), Config.ARGB_8888);
|
||||
Canvas c = new Canvas(target);
|
||||
c.drawBitmap(src, 0, 0, null);
|
||||
c.drawColor(0x8F000000 | (Color.GRAY & 0x00111111));
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
public static Bitmap resize(Bitmap oriBitmap, int targetWidth, int targetHeight) {
|
||||
if (oriBitmap == null) {
|
||||
return null;
|
||||
}
|
||||
int width = oriBitmap.getWidth();
|
||||
int height = oriBitmap.getHeight();
|
||||
float scaleWidth = ((float) targetWidth) / width;
|
||||
float scaleHeight = ((float) targetHeight) / height;
|
||||
float scale = scaleWidth > scaleHeight ? scaleHeight : scaleWidth;
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.postScale(scale, scale);
|
||||
try {
|
||||
Bitmap resizedBitmap = Bitmap.createBitmap(oriBitmap, 0, 0, width, height, matrix, true);
|
||||
return resizedBitmap;
|
||||
}
|
||||
catch (OutOfMemoryError e) {
|
||||
MLog.error(JXImageUtils.class, "resizeBitmap OOM %s", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final int DEFAULT_JPEG_QUALITY = 90;
|
||||
public static byte[] compressToBytes(Bitmap bitmap) {
|
||||
@@ -693,7 +693,7 @@ public class JXImageUtils {
|
||||
}
|
||||
|
||||
|
||||
public static String compressImagePxAndQuality(String inPath, File outDir, String outFileName, int expectWidth, long expectSize) {
|
||||
public static CompressResult compressImagePxAndQuality(String inPath, File outDir, String outFileName, int expectWidth, long expectSize) {
|
||||
try {
|
||||
if (outDir == null) {
|
||||
return null;
|
||||
@@ -748,13 +748,15 @@ public class JXImageUtils {
|
||||
fos.close();
|
||||
if (thumbnailFile.exists()) {
|
||||
String compressPath = thumbnailFile.getPath();
|
||||
exif = new ExifInterface(compressPath);
|
||||
if (orientation != null) {
|
||||
exif = new ExifInterface(compressPath);
|
||||
exif.setAttribute(ExifInterface.TAG_ORIENTATION, orientation);
|
||||
exif.saveAttributes();
|
||||
}
|
||||
LogUtil.print(ResUtil.getString(R.string.utils_image_jximageutils_06) + getPicRotate(compressPath));
|
||||
return compressPath;
|
||||
int width = exif.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, 0);
|
||||
int height = exif.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, 0);
|
||||
return new CompressResult(compressPath, width, height, "image/jpeg");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Log.e("mouse_debug", ResUtil.getString(R.string.utils_image_jximageutils_07));
|
||||
@@ -816,5 +818,33 @@ public class JXImageUtils {
|
||||
return degree;
|
||||
}
|
||||
|
||||
public static class CompressResult {
|
||||
private String path;
|
||||
private int width;
|
||||
private int height;
|
||||
private String format;
|
||||
|
||||
public CompressResult(String path, int width, int height, String format) {
|
||||
this.path = path;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public String getFormat() {
|
||||
return format;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -5,7 +5,6 @@ import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.qiniu.android.utils.StringUtils;
|
||||
import com.chwl.library.common.application.BaseApp;
|
||||
import com.chwl.library.common.util.LibLogger;
|
||||
import com.chwl.library.utils.FP;
|
||||
@@ -877,41 +876,4 @@ public class FileHelper {
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件转换成字符串
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @return 字符串内容
|
||||
*/
|
||||
public static String getTxtFileContent(String filePath) {
|
||||
String content = "";
|
||||
if (!StringUtils.isNullOrEmpty(filePath)) {
|
||||
File file = new File(filePath);
|
||||
if (file.isFile()) {
|
||||
FileInputStream inputStream = null;
|
||||
try {
|
||||
inputStream = new FileInputStream(file);
|
||||
String line;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
BufferedReader buffReader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
while ((line = buffReader.readLine()) != null) {
|
||||
sb.append(line).append("\n");
|
||||
}
|
||||
content = sb.toString();
|
||||
} catch (Exception e) {
|
||||
LibLogger.error(TAG, "getTxtFileContent read fail, e = " + e);
|
||||
} finally {
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,33 @@
|
||||
package com.example.lib_utils
|
||||
|
||||
object PathUtils {
|
||||
|
||||
/**
|
||||
* 获取后缀名称
|
||||
* @param path 路径
|
||||
* @return 后缀格式 .mp4 .gif 等
|
||||
*/
|
||||
fun getSuffixType(path: String): String? {
|
||||
if (path.isEmpty()) {
|
||||
return null
|
||||
}
|
||||
val dotIndex = path.indexOfLast {
|
||||
'.' == it
|
||||
}
|
||||
val separatorIndex = path.indexOfLast {
|
||||
'/' == it
|
||||
}
|
||||
if (dotIndex >= 0 && dotIndex > separatorIndex) {
|
||||
val suffix = path.substring(dotIndex)
|
||||
val askIndex = suffix.indexOfLast {
|
||||
'?' == it
|
||||
}
|
||||
return if (askIndex >= 0) {
|
||||
suffix.substring(0, askIndex)
|
||||
} else {
|
||||
suffix
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user