pref: 优化图片保存
This commit is contained in:
parent
254c844ed2
commit
90cebdb90d
|
|
@ -30,6 +30,7 @@ import com.huanchengfly.tieba.post.models.PhotoViewBean
|
|||
import com.huanchengfly.tieba.post.ui.common.theme.utils.ThemeUtils
|
||||
import com.huanchengfly.tieba.post.utils.AnimUtil
|
||||
import com.huanchengfly.tieba.post.utils.ImageUtil
|
||||
import com.huanchengfly.tieba.post.utils.download
|
||||
import retrofit2.Call
|
||||
import retrofit2.Callback
|
||||
import retrofit2.Response
|
||||
|
|
@ -95,7 +96,7 @@ class PhotoViewActivity : BaseActivity(), OnChangeBottomBarVisibilityListener,
|
|||
}
|
||||
picBeans.addAll(data.picList)
|
||||
picBeans.forEach {
|
||||
it.img.original?.let { it1 -> imgInfoBeans.add(it1) }
|
||||
it.img.original.let { it1 -> imgInfoBeans.add(it1) }
|
||||
}
|
||||
lastIndex = picBeans.first().overAllIndex.toInt()
|
||||
for (photoViewBean in photoViewBeans) {
|
||||
|
|
@ -277,7 +278,7 @@ class PhotoViewActivity : BaseActivity(), OnChangeBottomBarVisibilityListener,
|
|||
this,
|
||||
mAdapter.getBean(mViewPager.currentItem).originUrl,
|
||||
true
|
||||
) { uri: Uri? ->
|
||||
) { uri: Uri ->
|
||||
val intent = Intent(Intent.ACTION_SEND)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
intent.putExtra(Intent.EXTRA_STREAM, uri)
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ import com.huanchengfly.tieba.post.toastShort
|
|||
import com.huanchengfly.tieba.post.ui.common.theme.compose.ExtendedTheme
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.LazyLoad
|
||||
import com.huanchengfly.tieba.post.utils.ImageUtil
|
||||
import com.huanchengfly.tieba.post.utils.download
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.roundToInt
|
||||
|
|
|
|||
|
|
@ -1,677 +0,0 @@
|
|||
package com.huanchengfly.tieba.post.utils;
|
||||
|
||||
import static com.huanchengfly.tieba.post.utils.FileUtil.FILE_FOLDER;
|
||||
import static com.huanchengfly.tieba.post.utils.FileUtil.changeFileExtension;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorMatrix;
|
||||
import android.graphics.ColorMatrixColorFilter;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.provider.MediaStore;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
import android.webkit.URLUtil;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.PopupMenu;
|
||||
import androidx.core.content.FileProvider;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.RequestBuilder;
|
||||
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
|
||||
import com.bumptech.glide.request.FutureTarget;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.bumptech.glide.request.target.Target;
|
||||
import com.huanchengfly.tieba.post.App;
|
||||
import com.huanchengfly.tieba.post.ExtensionsKt;
|
||||
import com.huanchengfly.tieba.post.R;
|
||||
import com.huanchengfly.tieba.post.activities.PhotoViewActivity;
|
||||
import com.huanchengfly.tieba.post.components.transformations.RadiusTransformation;
|
||||
import com.huanchengfly.tieba.post.models.PhotoViewBean;
|
||||
import com.zhihu.matisse.MimeType;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class ImageUtil {
|
||||
/**
|
||||
* 智能省流
|
||||
*/
|
||||
public static final int SETTINGS_SMART_ORIGIN = 0;
|
||||
/**
|
||||
* 智能无图
|
||||
*/
|
||||
public static final int SETTINGS_SMART_LOAD = 1;
|
||||
/**
|
||||
* 始终高质量
|
||||
*/
|
||||
public static final int SETTINGS_ALL_ORIGIN = 2;
|
||||
/**
|
||||
* 始终无图
|
||||
*/
|
||||
public static final int SETTINGS_ALL_NO = 3;
|
||||
|
||||
public static final int LOAD_TYPE_SMALL_PIC = 0;
|
||||
public static final int LOAD_TYPE_AVATAR = 1;
|
||||
public static final int LOAD_TYPE_NO_RADIUS = 2;
|
||||
public static final int LOAD_TYPE_ALWAYS_ROUND = 3;
|
||||
public static final String TAG = "ImageUtil";
|
||||
|
||||
private static boolean isGifFile(File file) {
|
||||
if (file == null) return false;
|
||||
try {
|
||||
return isGifFile(new FileInputStream(file));
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//判断是否为GIF文件
|
||||
private static boolean isGifFile(InputStream inputStream) {
|
||||
if (inputStream == null) return false;
|
||||
byte[] bytes = new byte[4];
|
||||
try {
|
||||
inputStream.read(bytes);
|
||||
inputStream.close();
|
||||
String str = new String(bytes);
|
||||
return str.equalsIgnoreCase("GIF8");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static File compressImage(Bitmap bitmap, File output, int maxSize) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
int quality = 100;
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
|
||||
while (baos.toByteArray().length / 1024 > maxSize && quality > 0) { //循环判断如果压缩后图片是否大于20kb,大于继续压缩 友盟缩略图要求不大于18kb
|
||||
baos.reset();//重置baos即清空baos
|
||||
quality -= 5;//每次都减少5
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);//这里压缩options%,把压缩后的数据存放到baos中
|
||||
}
|
||||
try {
|
||||
FileOutputStream fos = new FileOutputStream(output);
|
||||
try {
|
||||
fos.write(baos.toByteArray());
|
||||
fos.flush();
|
||||
fos.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
public static File bitmapToFile(Bitmap bitmap, File output) {
|
||||
return bitmapToFile(bitmap, output, Bitmap.CompressFormat.JPEG);
|
||||
}
|
||||
|
||||
public static File bitmapToFile(Bitmap bitmap, File output, Bitmap.CompressFormat format) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
bitmap.compress(format, 100, baos);
|
||||
try {
|
||||
FileOutputStream fos = new FileOutputStream(output);
|
||||
try {
|
||||
fos.write(baos.toByteArray());
|
||||
fos.flush();
|
||||
fos.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
public static File compressImage(Bitmap bitmap, File output) {
|
||||
return compressImage(bitmap, output, 100);
|
||||
}
|
||||
|
||||
public static Bitmap drawableToBitmap(Drawable drawable) {
|
||||
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(),
|
||||
drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
|
||||
drawable.draw(canvas);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
public static boolean copyFile(FileInputStream src, FileOutputStream dest) {
|
||||
boolean result = false;
|
||||
if ((src == null) || (dest == null)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
FileChannel srcChannel = null;
|
||||
FileChannel dstChannel = null;
|
||||
|
||||
try {
|
||||
srcChannel = src.getChannel();
|
||||
dstChannel = dest.getChannel();
|
||||
srcChannel.transferTo(0, srcChannel.size(), dstChannel);
|
||||
result = true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return result;
|
||||
}
|
||||
try {
|
||||
srcChannel.close();
|
||||
dstChannel.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static boolean copyFile(File src, File dest) {
|
||||
boolean result = false;
|
||||
if ((src == null) || (dest == null)) {
|
||||
return result;
|
||||
}
|
||||
if (dest.exists()) {
|
||||
dest.delete();
|
||||
}
|
||||
try {
|
||||
dest.createNewFile();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
FileChannel srcChannel = null;
|
||||
FileChannel dstChannel = null;
|
||||
|
||||
try {
|
||||
srcChannel = new FileInputStream(src).getChannel();
|
||||
dstChannel = new FileOutputStream(dest).getChannel();
|
||||
srcChannel.transferTo(0, srcChannel.size(), dstChannel);
|
||||
result = true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return result;
|
||||
}
|
||||
try {
|
||||
srcChannel.close();
|
||||
dstChannel.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void changeBrightness(ImageView imageView, int brightness) {
|
||||
ColorMatrix cMatrix = new ColorMatrix();
|
||||
cMatrix.set(new float[]{1, 0, 0, 0, brightness, 0, 1, 0, 0, brightness, // 改变亮度
|
||||
0, 0, 1, 0, brightness, 0, 0, 0, 1, 0});
|
||||
imageView.setColorFilter(new ColorMatrixColorFilter(cMatrix));
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
public static void download(Context context, String url) {
|
||||
download(context, url, false, null);
|
||||
}
|
||||
|
||||
private static void downloadForShare(Context context, String url, @NonNull ShareTaskCallback taskCallback) {
|
||||
new DownloadAsyncTask(context, url, file -> {
|
||||
File pictureFolder = new File(context.getCacheDir(), ".shareTemp");
|
||||
if (pictureFolder.exists() || pictureFolder.mkdirs()) {
|
||||
String fileName = "share_" + System.currentTimeMillis();
|
||||
File destFile = new File(pictureFolder, fileName);
|
||||
if (!destFile.exists()) {
|
||||
copyFile(file, destFile);
|
||||
}
|
||||
Uri shareUri;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
shareUri = FileProvider.getUriForFile(
|
||||
context,
|
||||
context.getPackageName() + ".share.FileProvider",
|
||||
destFile
|
||||
);
|
||||
} else {
|
||||
shareUri = Uri.fromFile(destFile);
|
||||
}
|
||||
taskCallback.onGetUri(shareUri);
|
||||
}
|
||||
}).execute();
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
public static void download(Context context, String url, boolean forShare, @Nullable ShareTaskCallback taskCallback) {
|
||||
if (forShare) {
|
||||
if (taskCallback != null) downloadForShare(context, url, taskCallback);
|
||||
return;
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
downloadAboveQ(context, url);
|
||||
return;
|
||||
}
|
||||
PermissionUtils.INSTANCE.askPermission(
|
||||
context,
|
||||
new PermissionUtils.PermissionData(
|
||||
Arrays.asList(PermissionUtils.READ_EXTERNAL_STORAGE, PermissionUtils.WRITE_EXTERNAL_STORAGE),
|
||||
context.getString(R.string.tip_permission_storage)
|
||||
),
|
||||
R.string.toast_no_permission_save_photo,
|
||||
() -> {
|
||||
downloadBelowQ(context, url);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private static void downloadAboveQ(Context context, String url) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||
return;
|
||||
}
|
||||
new DownloadAsyncTask(context, url, file -> {
|
||||
String mimeType = MimeType.JPEG.toString();
|
||||
String fileName = URLUtil.guessFileName(url, null, MimeType.JPEG.toString());
|
||||
if (isGifFile(file)) {
|
||||
fileName = changeFileExtension(fileName, ".gif");
|
||||
mimeType = MimeType.GIF.toString();
|
||||
}
|
||||
Log.i(TAG, "download: fileName = " + fileName);
|
||||
String relativePath = Environment.DIRECTORY_PICTURES + File.separator + FILE_FOLDER;
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(MediaStore.Images.Media.RELATIVE_PATH, relativePath);
|
||||
values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
|
||||
values.put(MediaStore.Images.Media.MIME_TYPE, mimeType);
|
||||
values.put(MediaStore.Images.Media.DESCRIPTION, fileName);
|
||||
Uri uri = null;
|
||||
ContentResolver cr = context.getContentResolver();
|
||||
try {
|
||||
uri = cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
|
||||
if (uri == null) {
|
||||
return;
|
||||
}
|
||||
ParcelFileDescriptor descriptor = cr.openFileDescriptor(uri, "w");
|
||||
FileOutputStream outputStream = new FileOutputStream(descriptor.getFileDescriptor());
|
||||
FileInputStream inputStream = new FileInputStream(file);
|
||||
copyFile(inputStream, outputStream);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
if (uri != null) {
|
||||
cr.delete(uri, null, null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
Toast.makeText(context, context.getString(R.string.toast_photo_saved, relativePath), Toast.LENGTH_SHORT).show();
|
||||
}).execute();
|
||||
}
|
||||
|
||||
private static void downloadBelowQ(Context context, String url) {
|
||||
new DownloadAsyncTask(context, url, file -> {
|
||||
File pictureFolder = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsoluteFile();
|
||||
File appDir;
|
||||
appDir = new File(pictureFolder, FILE_FOLDER);
|
||||
if (appDir.exists() || appDir.mkdirs()) {
|
||||
String fileName = URLUtil.guessFileName(url, null, MimeType.JPEG.toString());
|
||||
if (isGifFile(file)) {
|
||||
fileName = changeFileExtension(fileName, ".gif");
|
||||
}
|
||||
File destFile = new File(appDir, fileName);
|
||||
if (destFile.exists()) {
|
||||
return;
|
||||
}
|
||||
copyFile(file, destFile);
|
||||
checkGifFile(destFile);
|
||||
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(new File(destFile.getPath()))));
|
||||
Toast.makeText(context, context.getString(R.string.toast_photo_saved, destFile.getPath()), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}).execute();
|
||||
}
|
||||
|
||||
private static void checkGifFile(File file) {
|
||||
if (isGifFile(file)) {
|
||||
File gifFile = new File(file.getParentFile(), FileUtil.changeFileExtension(file.getName(), ".gif"));
|
||||
if (gifFile.exists()) {
|
||||
file.delete();
|
||||
} else {
|
||||
file.renameTo(gifFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static String getPicId(String picUrl) {
|
||||
String fileName = URLUtil.guessFileName(picUrl, null, MimeType.JPEG.toString());
|
||||
return fileName.replace(".jpg", "");
|
||||
}
|
||||
|
||||
public static void initImageView(@NonNull ImageView view, List<PhotoViewBean> photoViewBeans, int position, String forumName, String forumId, String threadId, boolean seeLz, String objType) {
|
||||
view.setOnClickListener(v -> {
|
||||
Object tag = view.getTag(R.id.image_load_tag);
|
||||
if (tag != null) {
|
||||
boolean loaded = (boolean) tag;
|
||||
if (loaded) {
|
||||
PhotoViewActivity.launch(v.getContext(), photoViewBeans.toArray(new PhotoViewBean[0]), position, forumName, forumId, threadId, seeLz, objType);
|
||||
} else {
|
||||
load(view, LOAD_TYPE_SMALL_PIC, photoViewBeans.get(position).getUrl(), true);
|
||||
}
|
||||
}
|
||||
});
|
||||
view.setOnLongClickListener(v -> {
|
||||
PopupMenu popupMenu = PopupUtil.create(view);
|
||||
popupMenu.getMenuInflater().inflate(R.menu.menu_image_long_click, popupMenu.getMenu());
|
||||
popupMenu.setOnMenuItemClickListener(item -> {
|
||||
if (item.getItemId() == R.id.menu_save_image) {
|
||||
download(view.getContext(), photoViewBeans.get(position).getOriginUrl());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
popupMenu.show();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public static void initImageView(ImageView view, List<PhotoViewBean> photoViewBeans, int position) {
|
||||
view.setOnClickListener(v -> {
|
||||
Object tag = view.getTag(R.id.image_load_tag);
|
||||
if (tag != null) {
|
||||
boolean loaded = (boolean) tag;
|
||||
if (loaded) {
|
||||
PhotoViewActivity.launch(v.getContext(), photoViewBeans, position);
|
||||
} else {
|
||||
load(view, LOAD_TYPE_SMALL_PIC, photoViewBeans.get(position).getUrl(), true);
|
||||
}
|
||||
}
|
||||
});
|
||||
view.setOnLongClickListener(v -> {
|
||||
PopupMenu popupMenu = PopupUtil.create(view);
|
||||
popupMenu.getMenuInflater().inflate(R.menu.menu_image_long_click, popupMenu.getMenu());
|
||||
popupMenu.setOnMenuItemClickListener(item -> {
|
||||
if (item.getItemId() == R.id.menu_save_image) {
|
||||
download(view.getContext(), photoViewBeans.get(position).getOriginUrl());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
popupMenu.show();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public static void initImageView(ImageView view, PhotoViewBean photoViewBean) {
|
||||
List<PhotoViewBean> photoViewBeans = new ArrayList<>();
|
||||
photoViewBeans.add(photoViewBean);
|
||||
initImageView(view, photoViewBeans, 0);
|
||||
}
|
||||
|
||||
public static String getNonNullString(String... strings) {
|
||||
for (String url : strings) {
|
||||
if (!TextUtils.isEmpty(url)) {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int getRadiusPx(Context context) {
|
||||
return DisplayUtil.dp2px(context, getRadiusDp(context));
|
||||
}
|
||||
|
||||
public static int getRadiusDp(Context context) {
|
||||
return AppPreferencesUtilsKt.getAppPreferences(context).getRadius();
|
||||
}
|
||||
|
||||
public static void load(ImageView imageView, @LoadType int type, String url) {
|
||||
load(imageView, type, url, false);
|
||||
}
|
||||
|
||||
public static void clear(ImageView imageView) {
|
||||
Glide.with(imageView).clear(imageView);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Drawable getPlaceHolder(Context context, int radius) {
|
||||
GradientDrawable drawable = new GradientDrawable();
|
||||
int color = ThemeUtil.isNightMode() ?
|
||||
context.getResources().getColor(R.color.color_place_holder_night) :
|
||||
context.getResources().getColor(R.color.color_place_holder);
|
||||
drawable.setColor(color);
|
||||
drawable.setCornerRadius(DisplayUtil.dp2px(context, radius));
|
||||
return drawable;
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
public static void load(
|
||||
ImageView imageView,
|
||||
@LoadType int type,
|
||||
String url,
|
||||
boolean skipNetworkCheck,
|
||||
boolean noTransition
|
||||
) {
|
||||
if (!Util.canLoadGlide(imageView.getContext())) {
|
||||
return;
|
||||
}
|
||||
int radius = getRadiusDp(imageView.getContext());
|
||||
RequestBuilder<Drawable> requestBuilder;
|
||||
if (skipNetworkCheck ||
|
||||
type == LOAD_TYPE_AVATAR ||
|
||||
getImageLoadSettings() == SETTINGS_ALL_ORIGIN ||
|
||||
getImageLoadSettings() == SETTINGS_SMART_ORIGIN ||
|
||||
(getImageLoadSettings() == SETTINGS_SMART_LOAD && NetworkUtil.isWifiConnected(imageView.getContext()))) {
|
||||
imageView.setTag(R.id.image_load_tag, true);
|
||||
requestBuilder = Glide.with(imageView).load(url);
|
||||
} else {
|
||||
imageView.setTag(R.id.image_load_tag, false);
|
||||
requestBuilder = Glide.with(imageView).load(getPlaceHolder(imageView.getContext(), type == LOAD_TYPE_SMALL_PIC ? radius : 0));
|
||||
}
|
||||
if (ThemeUtil.isNightMode()) {
|
||||
changeBrightness(imageView, -35);
|
||||
} else {
|
||||
imageView.clearColorFilter();
|
||||
}
|
||||
switch (type) {
|
||||
case LOAD_TYPE_SMALL_PIC:
|
||||
requestBuilder.apply(RequestOptions.bitmapTransform(new RadiusTransformation(radius))
|
||||
.placeholder(getPlaceHolder(imageView.getContext(), radius))
|
||||
.skipMemoryCache(true));
|
||||
break;
|
||||
case LOAD_TYPE_AVATAR:
|
||||
requestBuilder.apply(RequestOptions.bitmapTransform(new RadiusTransformation(6))
|
||||
.placeholder(getPlaceHolder(imageView.getContext(), 6))
|
||||
.skipMemoryCache(true));
|
||||
break;
|
||||
case LOAD_TYPE_NO_RADIUS:
|
||||
requestBuilder.apply(new RequestOptions()
|
||||
.placeholder(getPlaceHolder(imageView.getContext(), 0))
|
||||
.skipMemoryCache(true));
|
||||
break;
|
||||
case LOAD_TYPE_ALWAYS_ROUND:
|
||||
requestBuilder.apply(new RequestOptions()
|
||||
.circleCrop()
|
||||
.placeholder(getPlaceHolder(imageView.getContext(), ExtensionsKt.dpToPx(100)))
|
||||
.skipMemoryCache(true));
|
||||
break;
|
||||
}
|
||||
if (!noTransition) {
|
||||
requestBuilder.transition(DrawableTransitionOptions.withCrossFade());
|
||||
}
|
||||
requestBuilder.into(imageView);
|
||||
}
|
||||
|
||||
public static void load(
|
||||
ImageView imageView,
|
||||
@LoadType int type,
|
||||
String url,
|
||||
boolean skipNetworkCheck
|
||||
) {
|
||||
load(imageView, type, url, skipNetworkCheck, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取要加载的图片 Url
|
||||
*
|
||||
* @param isSmallPic 加载的是否为缩略图
|
||||
* @param originUrl 原图 Url
|
||||
* @param smallPicUrls 缩略图 Url,按照画质从好到差排序
|
||||
* @return 要加载的图片 Url
|
||||
*/
|
||||
public static String getUrl(Context context, boolean isSmallPic, @NonNull String originUrl, @NonNull String... smallPicUrls) {
|
||||
List<String> urls = Arrays.asList(smallPicUrls);
|
||||
if (isSmallPic) {
|
||||
if (needReverse(context)) {
|
||||
Collections.reverse(urls);
|
||||
}
|
||||
for (String url : urls) {
|
||||
if (!TextUtils.isEmpty(url)) {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
}
|
||||
return originUrl;
|
||||
}
|
||||
|
||||
private static boolean needReverse(Context context) {
|
||||
if (getImageLoadSettings() == SETTINGS_SMART_ORIGIN && NetworkUtil.isWifiConnected(context)) {
|
||||
return false;
|
||||
}
|
||||
return getImageLoadSettings() != SETTINGS_ALL_ORIGIN;
|
||||
}
|
||||
|
||||
@ImageLoadSettings
|
||||
private static int getImageLoadSettings() {
|
||||
return Integer.parseInt(AppPreferencesUtilsKt.getAppPreferences(App.getINSTANCE()).getImageLoadType());
|
||||
}
|
||||
|
||||
public static String imageToBase64(InputStream is) {
|
||||
if (is == null) {
|
||||
return null;
|
||||
}
|
||||
byte[] data = null;
|
||||
String result = null;
|
||||
try {
|
||||
//创建一个字符流大小的数组。
|
||||
data = new byte[is.available()];
|
||||
//写入数组
|
||||
is.read(data);
|
||||
//用默认的编码格式进行编码
|
||||
result = Base64.encodeToString(data, Base64.DEFAULT);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (null != is) {
|
||||
try {
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String imageToBase64(File file) {
|
||||
if (file == null) {
|
||||
return null;
|
||||
}
|
||||
String result = null;
|
||||
try {
|
||||
InputStream is = new FileInputStream(file);
|
||||
result = imageToBase64(is);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public interface ShareTaskCallback {
|
||||
void onGetUri(Uri uri);
|
||||
}
|
||||
|
||||
@IntDef({LOAD_TYPE_SMALL_PIC, LOAD_TYPE_AVATAR, LOAD_TYPE_NO_RADIUS, LOAD_TYPE_ALWAYS_ROUND})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface LoadType {
|
||||
}
|
||||
|
||||
@IntDef({SETTINGS_SMART_ORIGIN, SETTINGS_SMART_LOAD, SETTINGS_ALL_ORIGIN, SETTINGS_ALL_NO})
|
||||
public @interface ImageLoadSettings {
|
||||
}
|
||||
|
||||
public static class DownloadAsyncTask extends AsyncTask<Void, Integer, File> {
|
||||
private final WeakReference<Context> contextWeakReference;
|
||||
private final TaskCallback callback;
|
||||
private final String url;
|
||||
|
||||
public DownloadAsyncTask(Context context, String url, TaskCallback callback) {
|
||||
this.contextWeakReference = new WeakReference<>(context);
|
||||
this.url = url;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public TaskCallback getCallback() {
|
||||
return callback;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
private Context getContext() {
|
||||
return contextWeakReference.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected File doInBackground(Void... voids) {
|
||||
File file = null;
|
||||
try {
|
||||
FutureTarget<File> future = Glide.with(getContext())
|
||||
.asFile()
|
||||
.load(getUrl())
|
||||
.submit(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);
|
||||
file = future.get();
|
||||
return file;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(File file) {
|
||||
super.onPostExecute(file);
|
||||
getCallback().onPostExecute(file);
|
||||
}
|
||||
|
||||
public interface TaskCallback {
|
||||
void onPostExecute(File file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,701 @@
|
|||
package com.huanchengfly.tieba.post.utils
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Bitmap.CompressFormat
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.ColorMatrix
|
||||
import android.graphics.ColorMatrixColorFilter
|
||||
import android.graphics.PixelFormat
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import android.provider.MediaStore
|
||||
import android.text.TextUtils
|
||||
import android.util.Base64
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.webkit.URLUtil
|
||||
import android.widget.ImageView
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.IntDef
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.FileProvider
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.github.panpf.sketch.request.DownloadRequest
|
||||
import com.github.panpf.sketch.request.DownloadResult
|
||||
import com.huanchengfly.tieba.post.App.Companion.INSTANCE
|
||||
import com.huanchengfly.tieba.post.R
|
||||
import com.huanchengfly.tieba.post.activities.PhotoViewActivity.Companion.launch
|
||||
import com.huanchengfly.tieba.post.components.transformations.RadiusTransformation
|
||||
import com.huanchengfly.tieba.post.dpToPx
|
||||
import com.huanchengfly.tieba.post.models.PhotoViewBean
|
||||
import com.huanchengfly.tieba.post.utils.PermissionUtils.PermissionData
|
||||
import com.huanchengfly.tieba.post.utils.PermissionUtils.askPermission
|
||||
import com.huanchengfly.tieba.post.utils.ThemeUtil.isNightMode
|
||||
import com.zhihu.matisse.MimeType
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.nio.channels.FileChannel
|
||||
|
||||
object ImageUtil {
|
||||
/**
|
||||
* 智能省流
|
||||
*/
|
||||
const val SETTINGS_SMART_ORIGIN = 0
|
||||
|
||||
/**
|
||||
* 智能无图
|
||||
*/
|
||||
const val SETTINGS_SMART_LOAD = 1
|
||||
|
||||
/**
|
||||
* 始终高质量
|
||||
*/
|
||||
const val SETTINGS_ALL_ORIGIN = 2
|
||||
|
||||
/**
|
||||
* 始终无图
|
||||
*/
|
||||
const val SETTINGS_ALL_NO = 3
|
||||
const val LOAD_TYPE_SMALL_PIC = 0
|
||||
const val LOAD_TYPE_AVATAR = 1
|
||||
const val LOAD_TYPE_NO_RADIUS = 2
|
||||
const val LOAD_TYPE_ALWAYS_ROUND = 3
|
||||
const val TAG = "ImageUtil"
|
||||
private fun isGifFile(file: File?): Boolean {
|
||||
if (file == null) return false
|
||||
try {
|
||||
return FileInputStream(file).use { isGifFile(it) }
|
||||
} catch (e: FileNotFoundException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
//判断是否为GIF文件
|
||||
private fun isGifFile(inputStream: InputStream?): Boolean {
|
||||
if (inputStream == null) return false
|
||||
val bytes = ByteArray(4)
|
||||
try {
|
||||
inputStream.mark(0)
|
||||
inputStream.read(bytes)
|
||||
inputStream.reset()
|
||||
val str = String(bytes)
|
||||
return str.equals("GIF8", ignoreCase = true)
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun compressImage(bitmap: Bitmap, output: File, maxSize: Int = 100): File {
|
||||
val baos = ByteArrayOutputStream()
|
||||
var quality = 100
|
||||
bitmap.compress(CompressFormat.JPEG, quality, baos) //质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
|
||||
while (baos.toByteArray().size / 1024 > maxSize && quality > 0) { //循环判断如果压缩后图片是否大于20kb,大于继续压缩 友盟缩略图要求不大于18kb
|
||||
baos.reset() //重置baos即清空baos
|
||||
quality -= 5 //每次都减少5
|
||||
bitmap.compress(CompressFormat.JPEG, quality, baos) //这里压缩options%,把压缩后的数据存放到baos中
|
||||
}
|
||||
try {
|
||||
val fos = FileOutputStream(output)
|
||||
try {
|
||||
fos.write(baos.toByteArray())
|
||||
fos.flush()
|
||||
fos.close()
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
} catch (e: FileNotFoundException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun bitmapToFile(
|
||||
bitmap: Bitmap,
|
||||
output: File,
|
||||
format: CompressFormat? = CompressFormat.JPEG
|
||||
): File {
|
||||
val baos = ByteArrayOutputStream()
|
||||
bitmap.compress(format, 100, baos)
|
||||
try {
|
||||
val fos = FileOutputStream(output)
|
||||
try {
|
||||
fos.write(baos.toByteArray())
|
||||
fos.flush()
|
||||
fos.close()
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
} catch (e: FileNotFoundException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
fun drawableToBitmap(drawable: Drawable): Bitmap {
|
||||
val bitmap = Bitmap.createBitmap(
|
||||
drawable.intrinsicWidth, drawable.intrinsicHeight,
|
||||
if (drawable.opacity != PixelFormat.OPAQUE) Bitmap.Config.ARGB_8888 else Bitmap.Config.RGB_565
|
||||
)
|
||||
val canvas = Canvas(bitmap)
|
||||
drawable.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight)
|
||||
drawable.draw(canvas)
|
||||
return bitmap
|
||||
}
|
||||
|
||||
fun copyFile(src: FileInputStream?, dest: FileOutputStream?): Boolean {
|
||||
if (src == null || dest == null) {
|
||||
return false
|
||||
}
|
||||
val srcChannel: FileChannel?
|
||||
val dstChannel: FileChannel?
|
||||
try {
|
||||
srcChannel = src.channel
|
||||
dstChannel = dest.channel
|
||||
srcChannel.transferTo(0, srcChannel.size(), dstChannel)
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
return false
|
||||
}
|
||||
try {
|
||||
srcChannel.close()
|
||||
dstChannel.close()
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun copyFile(src: File?, dest: File?): Boolean {
|
||||
if (src == null || dest == null) {
|
||||
return false
|
||||
}
|
||||
if (dest.exists()) {
|
||||
dest.delete()
|
||||
}
|
||||
try {
|
||||
dest.createNewFile()
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
val srcChannel: FileChannel?
|
||||
val dstChannel: FileChannel?
|
||||
try {
|
||||
srcChannel = FileInputStream(src).channel
|
||||
dstChannel = FileOutputStream(dest).channel
|
||||
srcChannel.transferTo(0, srcChannel.size(), dstChannel)
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
return false
|
||||
}
|
||||
try {
|
||||
srcChannel.close()
|
||||
dstChannel.close()
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun changeBrightness(imageView: ImageView, brightness: Int) {
|
||||
val cMatrix = ColorMatrix()
|
||||
cMatrix.set(
|
||||
floatArrayOf(
|
||||
1f, 0f, 0f, 0f, brightness.toFloat(), 0f, 1f, 0f, 0f, brightness.toFloat(), // 改变亮度
|
||||
0f, 0f, 1f, 0f, brightness.toFloat(), 0f, 0f, 0f, 1f, 0f
|
||||
)
|
||||
)
|
||||
imageView.colorFilter = ColorMatrixColorFilter(cMatrix)
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
fun download(context: Context, url: String?) {
|
||||
download(context, url, false, null)
|
||||
}
|
||||
|
||||
private fun downloadForShare(context: Context, url: String?, taskCallback: ShareTaskCallback) {
|
||||
if (url == null) return
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val downloadResult = DownloadRequest(context, url).execute()
|
||||
if (downloadResult is DownloadResult.Success) {
|
||||
val inputStream = downloadResult.data.data.newInputStream()
|
||||
val pictureFolder = File(context.cacheDir, ".shareTemp")
|
||||
if (pictureFolder.exists() || pictureFolder.mkdirs()) {
|
||||
val fileName = "share_" + System.currentTimeMillis()
|
||||
val destFile = File(pictureFolder, fileName)
|
||||
if (!destFile.exists()) {
|
||||
withContext(Dispatchers.IO) {
|
||||
destFile.createNewFile()
|
||||
}
|
||||
}
|
||||
inputStream.use { input ->
|
||||
if (destFile.canWrite()) {
|
||||
destFile.outputStream().use { output ->
|
||||
input.copyTo(output)
|
||||
}
|
||||
}
|
||||
}
|
||||
val shareUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
FileProvider.getUriForFile(
|
||||
context,
|
||||
context.packageName + ".share.FileProvider",
|
||||
destFile
|
||||
)
|
||||
} else {
|
||||
Uri.fromFile(destFile)
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
taskCallback.onGetUri(shareUri)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
fun download(
|
||||
context: Context,
|
||||
url: String?,
|
||||
forShare: Boolean,
|
||||
taskCallback: ShareTaskCallback?
|
||||
) {
|
||||
if (forShare) {
|
||||
if (taskCallback != null) downloadForShare(context, url, taskCallback)
|
||||
return
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
downloadAboveQ(context, url)
|
||||
return
|
||||
}
|
||||
askPermission(
|
||||
context,
|
||||
PermissionData(
|
||||
listOf(
|
||||
PermissionUtils.READ_EXTERNAL_STORAGE,
|
||||
PermissionUtils.WRITE_EXTERNAL_STORAGE
|
||||
),
|
||||
context.getString(R.string.tip_permission_storage)
|
||||
),
|
||||
R.string.toast_no_permission_save_photo
|
||||
) {
|
||||
downloadBelowQ(context, url)
|
||||
}
|
||||
}
|
||||
|
||||
private fun downloadAboveQ(context: Context, url: String?) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||
return
|
||||
}
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val downloadResult = DownloadRequest(context, url).execute()
|
||||
if (downloadResult is DownloadResult.Success) {
|
||||
var mimeType = MimeType.JPEG.toString()
|
||||
var fileName = URLUtil.guessFileName(url, null, mimeType)
|
||||
downloadResult.data.data.newInputStream().use { inputStream ->
|
||||
if (isGifFile(inputStream)) {
|
||||
mimeType = MimeType.GIF.toString()
|
||||
fileName = FileUtil.changeFileExtension(fileName, ".gif")
|
||||
}
|
||||
}
|
||||
downloadResult.data.data.newInputStream().use { inputStream ->
|
||||
val relativePath =
|
||||
Environment.DIRECTORY_PICTURES + File.separator + FileUtil.FILE_FOLDER
|
||||
val values = ContentValues().apply {
|
||||
put(MediaStore.Images.Media.RELATIVE_PATH, relativePath)
|
||||
put(MediaStore.Images.Media.DISPLAY_NAME, fileName)
|
||||
put(MediaStore.Images.Media.MIME_TYPE, mimeType)
|
||||
put(MediaStore.Images.Media.DESCRIPTION, fileName)
|
||||
}
|
||||
val cr = context.contentResolver
|
||||
val uri: Uri = runCatching {
|
||||
cr.insert(
|
||||
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
||||
values
|
||||
)
|
||||
}.getOrNull() ?: return@launch
|
||||
try {
|
||||
cr.openFileDescriptor(uri, "w")?.use {
|
||||
FileOutputStream(it.fileDescriptor).use { outputStream ->
|
||||
inputStream.copyTo(outputStream)
|
||||
}
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
Toast.makeText(
|
||||
context,
|
||||
context.getString(R.string.toast_photo_saved, relativePath),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
cr.delete(uri, null, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun downloadBelowQ(context: Context, url: String?) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val downloadResult = DownloadRequest(context, url).execute()
|
||||
if (downloadResult is DownloadResult.Success) {
|
||||
var fileName = URLUtil.guessFileName(url, null, MimeType.JPEG.toString())
|
||||
downloadResult.data.data.newInputStream().use { inputStream ->
|
||||
if (isGifFile(inputStream)) {
|
||||
fileName = FileUtil.changeFileExtension(fileName, ".gif")
|
||||
}
|
||||
}
|
||||
downloadResult.data.data.newInputStream().use { inputStream ->
|
||||
val pictureFolder =
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
|
||||
val appDir = File(pictureFolder, FileUtil.FILE_FOLDER)
|
||||
val dirExists =
|
||||
withContext(Dispatchers.IO) { appDir.exists() || appDir.mkdirs() }
|
||||
if (dirExists) {
|
||||
val destFile = File(appDir, fileName)
|
||||
if (!destFile.exists()) {
|
||||
withContext(Dispatchers.IO) {
|
||||
destFile.createNewFile()
|
||||
}
|
||||
}
|
||||
destFile.outputStream().use { outputStream ->
|
||||
inputStream.copyTo(outputStream)
|
||||
}
|
||||
context.sendBroadcast(
|
||||
Intent(
|
||||
Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
|
||||
Uri.fromFile(File(destFile.path))
|
||||
)
|
||||
)
|
||||
withContext(Dispatchers.Main) {
|
||||
Toast.makeText(
|
||||
context,
|
||||
context.getString(R.string.toast_photo_saved, destFile.path),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkGifFile(file: File) {
|
||||
if (isGifFile(file)) {
|
||||
val gifFile = File(file.parentFile, FileUtil.changeFileExtension(file.name, ".gif"))
|
||||
if (gifFile.exists()) {
|
||||
file.delete()
|
||||
} else {
|
||||
file.renameTo(gifFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getPicId(picUrl: String?): String {
|
||||
val fileName = URLUtil.guessFileName(picUrl, null, MimeType.JPEG.toString())
|
||||
return fileName.replace(".jpg", "")
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun initImageView(
|
||||
view: ImageView,
|
||||
photoViewBeans: List<PhotoViewBean?>,
|
||||
position: Int,
|
||||
forumName: String?,
|
||||
forumId: String?,
|
||||
threadId: String?,
|
||||
seeLz: Boolean,
|
||||
objType: String?
|
||||
) {
|
||||
view.setOnClickListener { v: View ->
|
||||
val tag = view.getTag(R.id.image_load_tag)
|
||||
if (tag != null) {
|
||||
val loaded = tag as Boolean
|
||||
if (loaded) {
|
||||
launch(
|
||||
v.context,
|
||||
photoViewBeans.toTypedArray(),
|
||||
position,
|
||||
forumName,
|
||||
forumId,
|
||||
threadId,
|
||||
seeLz,
|
||||
objType
|
||||
)
|
||||
} else {
|
||||
load(view, LOAD_TYPE_SMALL_PIC, photoViewBeans[position]!!.url, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
view.setOnLongClickListener {
|
||||
val popupMenu = PopupUtil.create(view)
|
||||
popupMenu.menuInflater.inflate(R.menu.menu_image_long_click, popupMenu.menu)
|
||||
popupMenu.setOnMenuItemClickListener { item: MenuItem ->
|
||||
if (item.itemId == R.id.menu_save_image) {
|
||||
download(view.context, photoViewBeans[position]!!.originUrl)
|
||||
return@setOnMenuItemClickListener true
|
||||
}
|
||||
false
|
||||
}
|
||||
popupMenu.show()
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun initImageView(view: ImageView, photoViewBeans: List<PhotoViewBean>, position: Int) {
|
||||
view.setOnClickListener { v: View ->
|
||||
val tag = view.getTag(R.id.image_load_tag)
|
||||
if (tag != null) {
|
||||
val loaded = tag as Boolean
|
||||
if (loaded) {
|
||||
launch(v.context, photoViewBeans, position)
|
||||
} else {
|
||||
load(view, LOAD_TYPE_SMALL_PIC, photoViewBeans[position].url, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
view.setOnLongClickListener {
|
||||
val popupMenu = PopupUtil.create(view)
|
||||
popupMenu.menuInflater.inflate(R.menu.menu_image_long_click, popupMenu.menu)
|
||||
popupMenu.setOnMenuItemClickListener { item: MenuItem ->
|
||||
if (item.itemId == R.id.menu_save_image) {
|
||||
download(view.context, photoViewBeans[position].originUrl)
|
||||
return@setOnMenuItemClickListener true
|
||||
}
|
||||
false
|
||||
}
|
||||
popupMenu.show()
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fun initImageView(view: ImageView, photoViewBean: PhotoViewBean) {
|
||||
val photoViewBeans: MutableList<PhotoViewBean> = ArrayList()
|
||||
photoViewBeans.add(photoViewBean)
|
||||
initImageView(view, photoViewBeans, 0)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getNonNullString(vararg strings: String?): String? {
|
||||
for (url in strings) {
|
||||
if (!TextUtils.isEmpty(url)) {
|
||||
return url
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getRadiusPx(context: Context): Int {
|
||||
return DisplayUtil.dp2px(context, getRadiusDp(context).toFloat())
|
||||
}
|
||||
|
||||
private fun getRadiusDp(context: Context): Int {
|
||||
return context.appPreferences.radius
|
||||
}
|
||||
|
||||
fun clear(imageView: ImageView?) {
|
||||
Glide.with(imageView!!).clear(imageView)
|
||||
}
|
||||
|
||||
fun getPlaceHolder(context: Context, radius: Int): Drawable {
|
||||
val drawable = GradientDrawable()
|
||||
val colorResId =
|
||||
if (isNightMode()) R.color.color_place_holder_night else R.color.color_place_holder
|
||||
val color = ContextCompat.getColor(context, colorResId)
|
||||
drawable.setColor(color)
|
||||
drawable.cornerRadius =
|
||||
DisplayUtil.dp2px(context, radius.toFloat()).toFloat()
|
||||
return drawable
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
fun load(
|
||||
imageView: ImageView,
|
||||
@LoadType type: Int,
|
||||
url: String?,
|
||||
skipNetworkCheck: Boolean,
|
||||
noTransition: Boolean
|
||||
) {
|
||||
if (!Util.canLoadGlide(imageView.context)) {
|
||||
return
|
||||
}
|
||||
val radius = getRadiusDp(imageView.context)
|
||||
val requestBuilder =
|
||||
if (skipNetworkCheck ||
|
||||
type == LOAD_TYPE_AVATAR ||
|
||||
imageLoadSettings == SETTINGS_ALL_ORIGIN ||
|
||||
imageLoadSettings == SETTINGS_SMART_ORIGIN ||
|
||||
(imageLoadSettings == SETTINGS_SMART_LOAD && NetworkUtil.isWifiConnected(imageView.context))
|
||||
) {
|
||||
imageView.setTag(R.id.image_load_tag, true)
|
||||
Glide.with(imageView).load(url)
|
||||
} else {
|
||||
imageView.setTag(R.id.image_load_tag, false)
|
||||
Glide.with(imageView).load(
|
||||
getPlaceHolder(
|
||||
imageView.context,
|
||||
if (type == LOAD_TYPE_SMALL_PIC) radius else 0
|
||||
)
|
||||
)
|
||||
}
|
||||
if (isNightMode()) {
|
||||
changeBrightness(imageView, -35)
|
||||
} else {
|
||||
imageView.clearColorFilter()
|
||||
}
|
||||
when (type) {
|
||||
LOAD_TYPE_SMALL_PIC -> requestBuilder.apply(
|
||||
RequestOptions.bitmapTransform(RadiusTransformation(radius))
|
||||
.placeholder(getPlaceHolder(imageView.context, radius))
|
||||
.skipMemoryCache(true)
|
||||
)
|
||||
|
||||
LOAD_TYPE_AVATAR -> requestBuilder.apply(
|
||||
RequestOptions.bitmapTransform(RadiusTransformation(6))
|
||||
.placeholder(getPlaceHolder(imageView.context, 6))
|
||||
.skipMemoryCache(true)
|
||||
)
|
||||
|
||||
LOAD_TYPE_NO_RADIUS -> requestBuilder.apply(
|
||||
RequestOptions()
|
||||
.placeholder(getPlaceHolder(imageView.context, 0))
|
||||
.skipMemoryCache(true)
|
||||
)
|
||||
|
||||
LOAD_TYPE_ALWAYS_ROUND -> requestBuilder.apply(
|
||||
RequestOptions()
|
||||
.circleCrop()
|
||||
.placeholder(getPlaceHolder(imageView.context, 100.dpToPx()))
|
||||
.skipMemoryCache(true)
|
||||
)
|
||||
}
|
||||
if (!noTransition) {
|
||||
requestBuilder.transition(DrawableTransitionOptions.withCrossFade())
|
||||
}
|
||||
requestBuilder.into(imageView)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun load(
|
||||
imageView: ImageView,
|
||||
@LoadType type: Int,
|
||||
url: String?,
|
||||
skipNetworkCheck: Boolean = false
|
||||
) {
|
||||
load(imageView, type, url, skipNetworkCheck, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取要加载的图片 Url
|
||||
*
|
||||
* @param isSmallPic 加载的是否为缩略图
|
||||
* @param originUrl 原图 Url
|
||||
* @param smallPicUrls 缩略图 Url,按照画质从好到差排序
|
||||
* @return 要加载的图片 Url
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getUrl(
|
||||
context: Context,
|
||||
isSmallPic: Boolean,
|
||||
originUrl: String,
|
||||
vararg smallPicUrls: String?
|
||||
): String {
|
||||
val urls = mutableListOf(*smallPicUrls)
|
||||
if (isSmallPic) {
|
||||
if (needReverse(context)) {
|
||||
urls.reverse()
|
||||
}
|
||||
for (url in urls) {
|
||||
if (!url.isNullOrEmpty()) {
|
||||
return url
|
||||
}
|
||||
}
|
||||
}
|
||||
return originUrl
|
||||
}
|
||||
|
||||
private fun needReverse(context: Context): Boolean {
|
||||
return if (imageLoadSettings == SETTINGS_SMART_ORIGIN &&
|
||||
NetworkUtil.isWifiConnected(context)
|
||||
) false
|
||||
else imageLoadSettings != SETTINGS_ALL_ORIGIN
|
||||
}
|
||||
|
||||
@get:ImageLoadSettings
|
||||
private val imageLoadSettings: Int
|
||||
get() = INSTANCE.appPreferences.imageLoadType!!.toInt()
|
||||
|
||||
fun imageToBase64(inputStream: InputStream?): String? {
|
||||
if (inputStream == null) {
|
||||
return null
|
||||
}
|
||||
return runCatching {
|
||||
inputStream.use {
|
||||
Base64.encodeToString(inputStream.readBytes(), Base64.DEFAULT)
|
||||
}
|
||||
}.getOrNull()
|
||||
}
|
||||
|
||||
fun imageToBase64(file: File?): String? {
|
||||
if (file == null) {
|
||||
return null
|
||||
}
|
||||
var result: String? = null
|
||||
try {
|
||||
val `is`: InputStream = FileInputStream(file)
|
||||
result = imageToBase64(`is`)
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
interface ShareTaskCallback {
|
||||
fun onGetUri(uri: Uri)
|
||||
}
|
||||
|
||||
@IntDef(LOAD_TYPE_SMALL_PIC, LOAD_TYPE_AVATAR, LOAD_TYPE_NO_RADIUS, LOAD_TYPE_ALWAYS_ROUND)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
annotation class LoadType
|
||||
|
||||
@IntDef(SETTINGS_SMART_ORIGIN, SETTINGS_SMART_LOAD, SETTINGS_ALL_ORIGIN, SETTINGS_ALL_NO)
|
||||
annotation class ImageLoadSettings
|
||||
|
||||
}
|
||||
|
||||
fun ImageUtil.download(
|
||||
context: Context,
|
||||
url: String?,
|
||||
forShare: Boolean,
|
||||
taskCallback: (Uri) -> Unit
|
||||
) {
|
||||
download(context, url, forShare, object : ImageUtil.ShareTaskCallback {
|
||||
override fun onGetUri(uri: Uri) {
|
||||
taskCallback(uri)
|
||||
}
|
||||
})
|
||||
}
|
||||
Loading…
Reference in New Issue