Files
yusheng-android/BaseModule/src/main/java/com/xscm/moduleutil/utils/ImageUtils.java
2025-11-12 16:40:26 +08:00

637 lines
26 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

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

package com.xscm.moduleutil.utils;
import static android.view.View.GONE;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.blankj.utilcode.util.ConvertUtils;
import com.blankj.utilcode.util.Utils;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.load.resource.gif.GifDrawable;
import com.bumptech.glide.request.FutureTarget;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.target.Target;
import com.bumptech.glide.request.transition.Transition;
import com.bumptech.glide.signature.ObjectKey;
import com.opensource.svgaplayer.SVGADrawable;
import com.opensource.svgaplayer.SVGAImageView;
import com.opensource.svgaplayer.SVGAParser;
import com.opensource.svgaplayer.SVGAVideoEntity;
import com.xscm.moduleutil.R;
import com.xscm.moduleutil.utils.logger.Logger;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
/**
* <p> 图片加载工具类</p>
*
* @name ImageUtils
*/
public class ImageUtils {
public static final int ANIM = -1;
/**
* 默认加载
*/
public static void loadImageView(String path, ImageView mImageView) {
Glide.with(mImageView).load(path).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImageView);
}
/**
* 默认加载
*/
public static void loadIcon(String path, ImageView mImageView) {
mImageView.setVisibility(TextUtils.isEmpty(path) ? GONE : View.VISIBLE);
Glide.with(mImageView).load(path).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImageView);
}
/**
* 加载爵位动图
*/
public static void loadVipWebp(String path, ImageView mImageView) {
loadSample(path, mImageView, ConvertUtils.dp2px(200), ConvertUtils.dp2px(200));
}
/**
* 采样
*
* @param path
* @param mImageView
* @param width
* @param height
*/
public static void loadSample(String path, ImageView mImageView, int width, int height) {
RequestOptions options = new RequestOptions().override(width, height).diskCacheStrategy(DiskCacheStrategy.ALL);
Glide.with(mImageView).load(path).apply(options).into(mImageView);
}
/**
* 默认加载
*/
public static void loadDecorationAvatar(String path, SVGAImageView mImageView) {
if (path.endsWith(".svga")) {
try {
SVGAParser.Companion.shareParser().decodeFromURL(new URL(path), new SVGAParser.ParseCompletion() {
@Override
public void onComplete(@NotNull SVGAVideoEntity svgaVideoEntity) {
if (mImageView != null) {
SVGADrawable svgaDrawable = new SVGADrawable(svgaVideoEntity);
mImageView.setImageDrawable(svgaDrawable);
mImageView.startAnimation();
}
}
@Override
public void onError() {
Logger.e("loadDecorationAvatar error");
}
});
} catch (MalformedURLException e) {
e.printStackTrace();
}
} else {
if (mImageView.isAnimating()) {
mImageView.stopAnimation();
}
Glide.with(mImageView).load(path).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImageView);
}
}
private static Map<Integer, SVGAVideoEntity> svgaCache = new HashMap<>();
// TODO: 2025/8/22 播放svga
public static void loadDecorationAvatar2(int resourceId, SVGAImageView mImageView) {
// 从资源文件夹加载SVGA文件
if (resourceId != 0) {
// 检查缓存
SVGAVideoEntity cachedEntity = svgaCache.get(resourceId);
if (cachedEntity != null) {
// 使用缓存的实体
SVGADrawable svgaDrawable = new SVGADrawable(cachedEntity);
mImageView.setImageDrawable(svgaDrawable);
mImageView.startAnimation();
return;
}
try {
// 没有缓存,正常加载
SVGAParser parser = SVGAParser.Companion.shareParser();
InputStream inputStream = mImageView.getContext().getResources().openRawResource(resourceId);
parser.decodeFromAssets("heart_line_31.svga", new SVGAParser.ParseCompletion() {
@Override
public void onComplete(@NotNull SVGAVideoEntity svgaVideoEntity) {
if (mImageView != null) {
// 缓存实体
svgaCache.put(resourceId, svgaVideoEntity);
SVGADrawable svgaDrawable = new SVGADrawable(svgaVideoEntity);
mImageView.setImageDrawable(svgaDrawable);
mImageView.startAnimation();
}
}
@Override
public void onError() {
Logger.e("loadDecorationAvatar2 error, resourceId: " + resourceId);
}
});
} catch (Exception e) {
Logger.e("loadDecorationAvatar2 exception, resourceId: " + resourceId, e);
}
} else {
Logger.e("Resource ID is 0 or invalid");
}
}
public static void loadSetErrorImg(String path, ImageView mImageView,int errorRes) {
if (mImageView == null) {
return;
}
Context context = mImageView.getContext();
if (context instanceof android.app.Activity) {
android.app.Activity activity = (android.app.Activity) context;
if (activity.isFinishing() || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed())) {
return;
}
}
Glide.with(mImageView).load(path).error(errorRes).placeholder(errorRes).centerCrop().diskCacheStrategy(DiskCacheStrategy.ALL).into(mImageView);
}
public static void loadHeadCC(String path, ImageView mImageView) {
if (mImageView == null) {
return;
}
Context context = mImageView.getContext();
if (context instanceof android.app.Activity) {
android.app.Activity activity = (android.app.Activity) context;
if (activity.isFinishing() || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed())) {
return;
}
}
Glide.with(mImageView).load(path).error(R.mipmap.default_avatar).placeholder(R.mipmap.default_avatar).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImageView);
}
public static void loadHeadCC(String path, ImageView mImageView, LinearLayout.LayoutParams params) {
if (mImageView == null) {
return;
}
Context context = mImageView.getContext();
if (context instanceof android.app.Activity) {
android.app.Activity activity = (android.app.Activity) context;
if (activity.isFinishing() || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed())) {
return;
}
}
Glide.with(mImageView).asBitmap().load(path).error(R.mipmap.default_avatar).placeholder(R.mipmap.default_avatar)
.diskCacheStrategy(DiskCacheStrategy.ALL)
// 添加加载监听
.listener(new RequestListener<Bitmap>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Bitmap> target, boolean isFirstResource) {
// 加载失败(显示默认图),可处理异常
Log.e("Glide", "图片加载失败", e);
return false; // 返回 falseGlide 会继续执行默认的错误处理(显示 error 图)
}
@Override
public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
// 加载成功resource 就是最终的 Bitmap 对象
int imageWidth = resource.getWidth(); // 图片原始宽度
int imageHeight = resource.getHeight(); // 图片原始高度
params.width = (int)(imageWidth * 1.3);
// 这里可以使用宽高(如打印、适配布局等)
Log.d("GlideImageSize", "宽度:" + imageWidth + ",高度:" + imageHeight);
return false; // 返回 falseGlide 会继续执行默认的图片设置(显示到 mImageView
}
})
.into(mImageView);
}
public static void loadCompressImg(String path, ImageView mImageView, int width, int height) {
Glide.with(mImageView)
.load(path)
.centerCrop()
.override(width, height).diskCacheStrategy(DiskCacheStrategy.ALL)
.into(mImageView);
}
public static void loadCenterCrop(String path, ImageView mImageView) {
Glide.with(mImageView).load(path).centerCrop().diskCacheStrategy(DiskCacheStrategy.ALL).into(mImageView);
}
public static void loadRes(int path, ImageView mImageView) {
Glide.with(mImageView).load(path).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImageView);
}
/**
* 加载图片(优先使用本地缓存,无缓存则下载)
*
* @param context 上下文
* @param url 图片 URL
* @param imageView 目标 ImageView
*/
public static void loadImageWithCache(Context context, String url, ImageView imageView) {
if (TextUtils.isEmpty(url)) return;
// 去掉动态参数,提取稳定 URL
String stableUrl = url.split("\\?")[0];
String signature = Md5Utils.getMD5String(stableUrl); // 使用 MD5 生成唯一签名
// Glide 加载配置
Glide.with(context)
.load(stableUrl)
.diskCacheStrategy(DiskCacheStrategy.ALL) // 缓存所有版本
.signature(new ObjectKey(signature)) // 使用签名确保缓存一致
.placeholder(R.mipmap.room_bj) // 加载中占位图
.error(R.mipmap.room_bj) // 加载失败占位图
.centerCrop()
.into(imageView);
}
public static boolean isImageCached(Context context, String url) {
FutureTarget<File> future = Glide.with(context)
.downloadOnly()
.load(url)
.submit();
try {
File cacheFile = future.get();
return cacheFile != null && cacheFile.exists();
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public static void loadImageBlurBg(String url, ImageView imageView) {
RequestOptions options = new RequestOptions().centerCrop().placeholder(R.mipmap.room_bg).error(R.mipmap.room_bg).diskCacheStrategy(DiskCacheStrategy.ALL);
Glide.with(imageView).asBitmap().apply(options).load(url).into(new SimpleTarget<Bitmap>(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) {
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override
public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
try {
Drawable foregroundDrawable = FastBlurUtil.getForegroundDrawable(resource);
imageView.setImageDrawable(foregroundDrawable);
} catch (Exception e) {
imageView.setImageResource(R.mipmap.room_bg);
}
}
});
}
public static void loadCoverBlurBg(Context context, String url, LinearLayout linearLayout) {
RequestOptions options = new RequestOptions().centerCrop().placeholder(R.mipmap.default_avatar).error(R.mipmap.default_avatar).diskCacheStrategy(DiskCacheStrategy.ALL);
Glide.with(context).asBitmap().apply(options).load(url).into(new SimpleTarget<Bitmap>(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) {
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override
public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
try {
setUpCoverBg(linearLayout, resource);
} catch (Exception e) {
linearLayout.setBackgroundResource(R.mipmap.index_bg_hot);
}
}
});
}
private static void setUpCoverBg(LinearLayout linearLayout, Bitmap resource) {
// Palette.from(resource).generate(new Palette.PaletteAsyncListener() {
// @Override
// public void onGenerated(Palette palette) {
// //记得判空
// if (palette == null) return;
// //palette取色不一定取得到某些特定的颜色这里通过取多种颜色来避免取不到颜色的情况
// if (palette.getDarkVibrantColor(Color.TRANSPARENT) != Color.TRANSPARENT) {
// createLinearGradientBitmap(linearLayout, resource, palette.getDarkVibrantColor(Color.TRANSPARENT), palette.getVibrantColor(Color.TRANSPARENT));
// } else if (palette.getDarkMutedColor(Color.TRANSPARENT) != Color.TRANSPARENT) {
// createLinearGradientBitmap(linearLayout, resource, palette.getDarkMutedColor(Color.TRANSPARENT), palette.getMutedColor(Color.TRANSPARENT));
// } else {
// createLinearGradientBitmap(linearLayout, resource, palette.getLightMutedColor(Color.TRANSPARENT), palette.getLightVibrantColor(Color.TRANSPARENT));
// }
// }
// });
}
//创建线性渐变背景色
private static void createLinearGradientBitmap(LinearLayout ivBg, Bitmap bgBitmap, int darkColor, int color) {
int bgColors[] = new int[2];
bgColors[0] = darkColor;
bgColors[1] = color;
if (bgBitmap == null) {
bgBitmap = Bitmap.createBitmap(ivBg.getWidth(), ivBg.getHeight(), Bitmap.Config.ARGB_4444);
}
Canvas mCanvas = new Canvas();
Paint mPaint = new Paint();
mCanvas.setBitmap(bgBitmap);
mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
LinearGradient gradient = new LinearGradient(0, 0, 0, bgBitmap.getHeight(), bgColors[0], bgColors[1], Shader.TileMode.CLAMP);
mPaint.setShader(gradient);
RectF rectF = new RectF(0, 0, bgBitmap.getWidth(), bgBitmap.getHeight());
mCanvas.drawRoundRect(rectF, 16, 16, mPaint);
// mCanvas.drawRect(rectF, mPaint);
ivBg.setBackground(new BitmapDrawable(bgBitmap));
}
public static void loadRoomBg(String url, ImageView imageView) {
RequestOptions options = new RequestOptions().centerCrop().placeholder(R.mipmap.room_bg).error(R.mipmap.room_bg).diskCacheStrategy(DiskCacheStrategy.ALL);
Glide.with(imageView).load(url).apply(options).into(imageView);
}
/**
* 设置加载中以及加载失败图片
*/
public static void loadImageWithLoading(String path, ImageView mImageView, int lodingImage, int errorRes) {
Glide.with(mImageView).load(path).placeholder(lodingImage).
error(errorRes).diskCacheStrategy(DiskCacheStrategy.ALL).into(mImageView);
}
/**
* 加载为bitmap
*
* @param path 图片地址
* @param listener 回调
*/
public static void loadBitmap(String path, final onLoadBitmap listener) {
Glide.with(Utils.getApp()).asBitmap().load(path).into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
listener.onReady(resource);
}
});
}
public static void loadGift(ImageView view, int res) {
if (res == ANIM) {
try {
AnimationDrawable background = (AnimationDrawable) view.getBackground();
if (background != null) {
background.start();
}
} catch (Exception e) {
e.printStackTrace();
}
} else {
Glide.with(view.getContext()).asGif().load(res).into(view);
}
}
public static void loadIconByHeight(String path, ImageView mImageView) {
mImageView.setVisibility(TextUtils.isEmpty(path) ? GONE : View.VISIBLE);
Glide.with(mImageView).load(path).diskCacheStrategy(DiskCacheStrategy.ALL).into(new SimpleTarget<Drawable>() {
@Override
public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
mImageView.setImageDrawable(resource);
ViewGroup.LayoutParams layoutParams = mImageView.getLayoutParams();
layoutParams.width = (int) (layoutParams.height * 1f / resource.getIntrinsicHeight() * resource.getIntrinsicWidth());
mImageView.setLayoutParams(layoutParams);
}
});
}
public static void loadIconByHeight1(String path, ImageView mImageView,int height) {
mImageView.setVisibility(TextUtils.isEmpty(path) ? GONE : View.VISIBLE);
Glide.with(mImageView).load(path).diskCacheStrategy(DiskCacheStrategy.ALL).into(new SimpleTarget<Drawable>() {
@Override
public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
mImageView.setImageDrawable(resource);
ViewGroup.LayoutParams layoutParams = mImageView.getLayoutParams();
layoutParams.width = (int) (layoutParams.height * 1f / resource.getIntrinsicHeight() * resource.getIntrinsicWidth());
layoutParams.height = height;
mImageView.setLayoutParams(layoutParams);
}
});
}
/**
* 加载网络图片并高斯模糊,失败时加载默认图片并同样模糊
*/
public static void loadBlurredImageWithDefault(String url, ImageView imageView, int defaultResId, int radius) {
if (imageView == null) return;
Glide.with(imageView.getContext())
.asBitmap()
.load(url)
.error(defaultResId) // 加载失败时显示默认图片
.into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
// 对网络图或默认图都进行模糊处理
Bitmap blurred = com.blankj.utilcode.util.ImageUtils.stackBlur(resource, radius);
imageView.setImageBitmap(blurred);
}
@Override
public void onLoadFailed(@Nullable Drawable errorDrawable) {
// 如果 errorDrawable 不为空,也可以直接用它生成 Bitmap
if (errorDrawable instanceof BitmapDrawable) {
Bitmap bitmap = ((BitmapDrawable) errorDrawable).getBitmap();
Bitmap blurred = com.blankj.utilcode.util.ImageUtils.stackBlur(bitmap, radius);
imageView.setImageBitmap(blurred);
} else {
// 如果不是 BitmapDrawable尝试从资源中加载 Bitmap
Bitmap defaultBitmap = BitmapFactory.decodeResource(imageView.getResources(), defaultResId);
if (defaultBitmap != null) {
Bitmap blurred = com.blankj.utilcode.util.ImageUtils.stackBlur(defaultBitmap, radius);
imageView.setImageBitmap(blurred);
}
}
}
});
}
/**
* 加载bitmap回调
*/
public interface onLoadBitmap {
void onReady(Bitmap resource);
}
public static void loadOneTimeGif(Context context, Object model, final ImageView imageView) {
Glide.with(context).asGif().load(model).listener(new RequestListener<GifDrawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<GifDrawable> target, boolean isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(GifDrawable resource, Object model, Target<GifDrawable> target, DataSource dataSource, boolean isFirstResource) {
try {
Field gifStateField = GifDrawable.class.getDeclaredField("state");
gifStateField.setAccessible(true);
Class gifStateClass = Class.forName("com.bumptech.glide.load.resource.gif.GifDrawable$GifState");
Field gifFrameLoaderField = gifStateClass.getDeclaredField("frameLoader");
gifFrameLoaderField.setAccessible(true);
Class gifFrameLoaderClass = Class.forName("com.bumptech.glide.load.resource.gif.GifFrameLoader");
Field gifDecoderField = gifFrameLoaderClass.getDeclaredField("gifDecoder");
gifDecoderField.setAccessible(true);
Class gifDecoderClass = Class.forName("com.bumptech.glide.gifdecoder.GifDecoder");
Object gifDecoder = gifDecoderField.get(gifFrameLoaderField.get(gifStateField.get(resource)));
Method getDelayMethod = gifDecoderClass.getDeclaredMethod("getDelay", int.class);
getDelayMethod.setAccessible(true);
//设置只播放一次
resource.setLoopCount(1);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return false;
}
}).into(imageView);
}
// public static String getImagePath() {
// String path = Constants.IMAGE_PATH;
// File file = new File(path);
// if (file.mkdirs()) {
// return path;
// } else {
// return path;
// }
// }
public static String getUrl(String url) {
// url = EncodeUtils.htmlDecode(url).toString();
// if (!TextUtils.isEmpty(url) && !url.contains("http"))
// url = BuildConfig.BASE_URL + url;
return url;
}
public static void preload(String url) {
// Glide.with(BaseApplication.getInstance()).download(url).preload();
}
public static void preloadImgConstants() {
// try {
// ImgConstants constants = new ImgConstants();
// Field[] fields = ImgConstants.class.getDeclaredFields();
// for (Field field : fields) {
// preload(field.get(constants).toString());
// }
// } catch (Exception e) {
// e.printStackTrace();
// }
}
/**
* 将 assets 中的文件复制到指定路径
*
* @param assetName assets 中的文件名,例如:"my_file.txt"
* @param savePath 要保存的目录路径,例如:"/data/data/your.package/files/"
* @param saveName 保存后的文件名
*/
public static void copyAssetToFile(String assetName, String savePath, String saveName) {
InputStream myInput = null;
FileOutputStream myOutput = null;
try {
// 打开 assets 中的文件输入流
myInput = Utils.getApp().getAssets().open(assetName);
// 创建目标目录(如果不存在)
File dir = new File(savePath);
if (!dir.exists()) {
dir.mkdirs();
}
// 创建目标文件
File outFile = new File(savePath + saveName);
if (outFile.exists()) {
outFile.delete(); // 如果已存在,先删除
}
// 创建输出流
myOutput = new FileOutputStream(outFile);
// 缓冲区读写
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
// 刷新输出流
myOutput.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭流
try {
if (myInput != null) {
myInput.close();
}
if (myOutput != null) {
myOutput.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void clearDiskCache(Context context){
Glide.get(context).clearDiskCache();
}
}