From fdd6f1836f6d5c2b1358f478c84b9c23d3abb5d2 Mon Sep 17 00:00:00 2001 From: max Date: Fri, 12 Apr 2024 16:16:37 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A7=BB=E6=A4=8D=E6=96=87=E4=BB=B6=E4=B8=8A?= =?UTF-8?q?=E4=BC=A0=EF=BC=9A=E4=B8=83=E7=89=9B=E4=BA=91=E6=8D=A2=E8=85=BE?= =?UTF-8?q?=E8=AE=AF=E4=BA=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UploadRoomAlbumDialogFragment.kt | 2 +- .../com/chwl/app/common/dialog/PhotoDialog.kt | 4 +- .../chwl/app/common/photo/PhotoProvider.kt | 11 +- .../com/chwl/app/utils/ObjectTypeHelper.java | 16 + .../matisse/internal/entity/CustomItem.java | 10 +- .../java/com/chwl/core/file/FileModel.java | 122 +-- .../java/com/chwl/core/file/IFileModel.java | 5 - .../java/com/chwl/core/file/UploadToken.java | 11 - .../java/com/chwl/core/file/cos/CosClient.kt | 128 +++ .../core/file/cos/CosCredentialProvider.kt | 16 + .../com/chwl/core/file/cos/CosException.kt | 18 + .../java/com/chwl/core/file/cos/CosToken.kt | 41 + .../core/community/bean/DynamicMedia.java | 10 + library/build.gradle | 5 +- .../library/utils/image/JXImageUtils.java | 850 +++++++++--------- .../chwl/library/common/file/FileHelper.java | 38 - .../java/com/example/lib_utils/PathUtils.kt | 33 + 17 files changed, 747 insertions(+), 573 deletions(-) delete mode 100644 core/src/main/java/com/chwl/core/file/UploadToken.java create mode 100644 core/src/main/java/com/chwl/core/file/cos/CosClient.kt create mode 100644 core/src/main/java/com/chwl/core/file/cos/CosCredentialProvider.kt create mode 100644 core/src/main/java/com/chwl/core/file/cos/CosException.kt create mode 100644 core/src/main/java/com/chwl/core/file/cos/CosToken.kt create mode 100644 libs/lib_utils/src/main/java/com/example/lib_utils/PathUtils.kt diff --git a/app/src/main/java/com/chwl/app/avroom/room_album/UploadRoomAlbumDialogFragment.kt b/app/src/main/java/com/chwl/app/avroom/room_album/UploadRoomAlbumDialogFragment.kt index ac134ea28..c5f6748cb 100644 --- a/app/src/main/java/com/chwl/app/avroom/room_album/UploadRoomAlbumDialogFragment.kt +++ b/app/src/main/java/com/chwl/app/avroom/room_album/UploadRoomAlbumDialogFragment.kt @@ -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()) } } diff --git a/app/src/main/java/com/chwl/app/common/dialog/PhotoDialog.kt b/app/src/main/java/com/chwl/app/common/dialog/PhotoDialog.kt index f651f69ea..6b60b0455 100644 --- a/app/src/main/java/com/chwl/app/common/dialog/PhotoDialog.kt +++ b/app/src/main/java/com/chwl/app/common/dialog/PhotoDialog.kt @@ -207,7 +207,7 @@ class PhotoDialog : BaseDialogFragment(), 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(), 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 { diff --git a/app/src/main/java/com/chwl/app/common/photo/PhotoProvider.kt b/app/src/main/java/com/chwl/app/common/photo/PhotoProvider.kt index 94c1d6d04..ce52cea6d 100644 --- a/app/src/main/java/com/chwl/app/common/photo/PhotoProvider.kt +++ b/app/src/main/java/com/chwl/app/common/photo/PhotoProvider.kt @@ -130,7 +130,7 @@ object PhotoProvider { } @JvmStatic - fun getResultPathListAsync(data: Intent?, resultListener: ((List?) -> Unit)) { + fun getResultPathListAsync(data: Intent?, resultListener: ((List?) -> Unit)) { cancelJop() mPhotoJob = MainScope().launch { val list: List? = data?.getParcelableArrayListExtra(EasyPhotos.RESULT_PHOTOS) @@ -150,22 +150,21 @@ object PhotoProvider { * 1. 项目使用到BitmapFactory.decodeFile(imgPath, options)之类的方法,该方法在android Q直接使用外部path测试中发现,获取图片信息失败 * */ - private fun copyToInternalCache(photos: List?): List? { + private fun copyToInternalCache(photos: List?): List? { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { val foldPath = getInternalPath() + File.separator - val newPaths = ArrayList() 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 } } diff --git a/app/src/main/java/com/chwl/app/utils/ObjectTypeHelper.java b/app/src/main/java/com/chwl/app/utils/ObjectTypeHelper.java index 3db3f78c2..7c1532583 100644 --- a/app/src/main/java/com/chwl/app/utils/ObjectTypeHelper.java +++ b/app/src/main/java/com/chwl/app/utils/ObjectTypeHelper.java @@ -22,6 +22,22 @@ public class ObjectTypeHelper { return resultList; } + public static List customToMediaList(List paramsList) { + List 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 stringToCustomList(List paramsList) { List resultList = new ArrayList<>(); if (paramsList == null) { diff --git a/app/src/module_album/java/com/example/matisse/internal/entity/CustomItem.java b/app/src/module_album/java/com/example/matisse/internal/entity/CustomItem.java index 8ea485642..182512dd0 100644 --- a/app/src/module_album/java/com/example/matisse/internal/entity/CustomItem.java +++ b/app/src/module_album/java/com/example/matisse/internal/entity/CustomItem.java @@ -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 CREATOR = new Creator() { diff --git a/core/src/main/java/com/chwl/core/file/FileModel.java b/core/src/main/java/com/chwl/core/file/FileModel.java index d0e32c412..9c47779eb 100644 --- a/core/src/main/java/com/chwl/core/file/FileModel.java +++ b/core/src/main/java/com/chwl/core/file/FileModel.java @@ -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 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 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 uploadFileReturnImageInfo(String path) { - return uploadFileReturnImageInfo(path, null); - } - - @Override - public Single 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 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> getUploadToken(); - + @GET("/tencent/cos/getToken") + Single> getCosToken(); } } diff --git a/core/src/main/java/com/chwl/core/file/IFileModel.java b/core/src/main/java/com/chwl/core/file/IFileModel.java index f10619c9a..b66343119 100644 --- a/core/src/main/java/com/chwl/core/file/IFileModel.java +++ b/core/src/main/java/com/chwl/core/file/IFileModel.java @@ -22,9 +22,4 @@ public interface IFileModel extends IModel { * @return */ Single downloadFile(String url); - - Single uploadFileReturnImageInfo(String path); - - Single uploadFileReturnImageInfo(String path, String qiniuName); - } diff --git a/core/src/main/java/com/chwl/core/file/UploadToken.java b/core/src/main/java/com/chwl/core/file/UploadToken.java deleted file mode 100644 index 8cbc0fd1c..000000000 --- a/core/src/main/java/com/chwl/core/file/UploadToken.java +++ /dev/null @@ -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; -} diff --git a/core/src/main/java/com/chwl/core/file/cos/CosClient.kt b/core/src/main/java/com/chwl/core/file/cos/CosClient.kt new file mode 100644 index 000000000..17976421a --- /dev/null +++ b/core/src/main/java/com/chwl/core/file/cos/CosClient.kt @@ -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 { + 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 + ) + } +} \ No newline at end of file diff --git a/core/src/main/java/com/chwl/core/file/cos/CosCredentialProvider.kt b/core/src/main/java/com/chwl/core/file/cos/CosCredentialProvider.kt new file mode 100644 index 000000000..f11a4af74 --- /dev/null +++ b/core/src/main/java/com/chwl/core/file/cos/CosCredentialProvider.kt @@ -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 + } +} \ No newline at end of file diff --git a/core/src/main/java/com/chwl/core/file/cos/CosException.kt b/core/src/main/java/com/chwl/core/file/cos/CosException.kt new file mode 100644 index 000000000..19a8e1d15 --- /dev/null +++ b/core/src/main/java/com/chwl/core/file/cos/CosException.kt @@ -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 + } +} \ No newline at end of file diff --git a/core/src/main/java/com/chwl/core/file/cos/CosToken.kt b/core/src/main/java/com/chwl/core/file/cos/CosToken.kt new file mode 100644 index 000000000..8d7dc1bb6 --- /dev/null +++ b/core/src/main/java/com/chwl/core/file/cos/CosToken.kt @@ -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 + ) + } +} \ No newline at end of file diff --git a/core/src/model_community/java/com/chwl/core/community/bean/DynamicMedia.java b/core/src/model_community/java/com/chwl/core/community/bean/DynamicMedia.java index 4e99a3f21..cdf9cd709 100644 --- a/core/src/model_community/java/com/chwl/core/community/bean/DynamicMedia.java +++ b/core/src/model_community/java/com/chwl/core/community/bean/DynamicMedia.java @@ -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; + } /** * 是否是网络图片 diff --git a/library/build.gradle b/library/build.gradle index ae56b4e0c..cd59bfc23 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -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() diff --git a/library/src/main/java/com/chwl/library/utils/image/JXImageUtils.java b/library/src/main/java/com/chwl/library/utils/image/JXImageUtils.java index d6b38c889..3c3f7702b 100644 --- a/library/src/main/java/com/chwl/library/utils/image/JXImageUtils.java +++ b/library/src/main/java/com/chwl/library/utils/image/JXImageUtils.java @@ -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; + } + } } diff --git a/library/src/module_common/java/com/chwl/library/common/file/FileHelper.java b/library/src/module_common/java/com/chwl/library/common/file/FileHelper.java index ca7be4bb0..6a2156c4f 100644 --- a/library/src/module_common/java/com/chwl/library/common/file/FileHelper.java +++ b/library/src/module_common/java/com/chwl/library/common/file/FileHelper.java @@ -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; - } - } diff --git a/libs/lib_utils/src/main/java/com/example/lib_utils/PathUtils.kt b/libs/lib_utils/src/main/java/com/example/lib_utils/PathUtils.kt new file mode 100644 index 000000000..614768198 --- /dev/null +++ b/libs/lib_utils/src/main/java/com/example/lib_utils/PathUtils.kt @@ -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 + } +} \ No newline at end of file