package dev.utils.app.image; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.NinePatchDrawable; import android.view.View; import androidx.annotation.ColorInt; import androidx.annotation.DrawableRes; import androidx.annotation.IntRange; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import dev.utils.LogPrintUtils; import dev.utils.app.ResourceUtils; import dev.utils.common.CloseUtils; import dev.utils.common.FileUtils; /** * detail: Image ( Bitmap、Drawable 等 ) 工具类 * @author Ttt * <pre> * 图片文件头标识信息 * @see <a href="https://mp.weixin.qq.com/s?__biz=MzA3NTYzODYzMg==&mid=2653578220&idx=1&sn=bdc57c640427984e240b19d8b9e10a15&chksm=84b3b1ebb3c438fdcbd446e9f28abd2713e685246efedfc133eb453ca41d08730dbf297ba1a4&scene=4#wechat_redirect"/> * @see <a href="https://developers.google.com/speed/webp/docs/riff_container"/> * 各类文件的文件头标志 * @see <a href="https://www.garykessler.net/library/file_sigs.html"/> * @see <a href="https://blog.csdn.net/feixi7358/article/details/87712812"/> * @see <a href="http://www.manongjc.com/article/56456.html"/> * </pre> */ public final class ImageUtils { private ImageUtils() { } // 日志 TAG private static final String TAG = ImageUtils.class.getSimpleName(); /** * 判断 Bitmap 对象是否为 null * @param bitmap {@link Bitmap} * @return {@code true} yes, {@code false} no */ public static boolean isEmpty(final Bitmap bitmap) { return bitmap == null || bitmap.getWidth() == 0 || bitmap.getHeight() == 0; } /** * 判断 Bitmap 对象是否不为 null * @param bitmap {@link Bitmap} * @return {@code true} yes, {@code false} no */ public static boolean isNotEmpty(final Bitmap bitmap) { return bitmap != null && bitmap.getWidth() != 0 && bitmap.getHeight() != 0; } // = /** * 判断 Drawable 对象是否为 null * @param drawable {@link Drawable} * @return {@code true} yes, {@code false} no */ public static boolean isEmpty(final Drawable drawable) { return drawable == null; } /** * 判断 Drawable 对象是否不为 null * @param drawable {@link Drawable} * @return {@code true} yes, {@code false} no */ public static boolean isNotEmpty(final Drawable drawable) { return drawable != null; } // ================ // = 图片类型判断 = // ================ /** * 根据文件名判断文件是否为图片 * @param file 文件 * @return {@code true} yes, {@code false} no */ public static boolean isImageFormats(final File file) { return FileUtils.isImageFormats(file); } /** * 根据文件名判断文件是否为图片 * @param filePath 文件路径 * @return {@code true} yes, {@code false} no */ public static boolean isImageFormats(final String filePath) { return FileUtils.isImageFormats(filePath); } /** * 根据文件名判断文件是否为图片 * @param filePath 文件路径 * @param imageFormats 图片格式 * @return {@code true} yes, {@code false} no */ public static boolean isImageFormats(final String filePath, final String[] imageFormats) { return FileUtils.isImageFormats(filePath, imageFormats); } // = /** * detail: 图片类型 * @author Ttt */ public enum ImageType { TYPE_PNG("png"), TYPE_JPG("jpg"), TYPE_BMP("bmp"), TYPE_GIF("gif"), TYPE_WEBP("webp"), TYPE_ICO("ico"), TYPE_TIFF("tiff"), TYPE_UNKNOWN("unknown"); private String value; ImageType(String value) { this.value = value; } /** * 获取图片类型字符串 * @return 图片类型字符串 */ public String getValue() { return value; } } /** * 获取图片类型 * @param filePath 文件路径 * @return {@link ImageType} 图片类型 */ public static ImageType getImageType(final String filePath) { return getImageType(FileUtils.getFileByPath(filePath)); } /** * 获取图片类型 * @param file 文件 * @return {@link ImageType} 图片类型 */ public static ImageType getImageType(final File file) { if (file == null) return ImageType.TYPE_UNKNOWN; InputStream is = null; try { is = new FileInputStream(file); return getImageType(is); } catch (Exception e) { LogPrintUtils.eTag(TAG, e, "getImageType"); return ImageType.TYPE_UNKNOWN; } finally { CloseUtils.closeIOQuietly(is); } } /** * 获取图片类型 * @param inputStream 输入流 * @return {@link ImageType} 图片类型 */ public static ImageType getImageType(final InputStream inputStream) { if (inputStream == null) return ImageType.TYPE_UNKNOWN; try { byte[] bytes = new byte[12]; return inputStream.read(bytes, 0, 12) != -1 ? getImageType(bytes) : null; } catch (Exception e) { LogPrintUtils.eTag(TAG, e, "getImageType"); return ImageType.TYPE_UNKNOWN; } } /** * 获取图片类型 * @param data 图片 byte[] * @return {@link ImageType} 图片类型 */ public static ImageType getImageType(final byte[] data) { if (isPNG(data)) return ImageType.TYPE_PNG; if (isJPEG(data)) return ImageType.TYPE_JPG; if (isBMP(data)) return ImageType.TYPE_BMP; if (isGif(data)) return ImageType.TYPE_GIF; if (isWEBP(data)) return ImageType.TYPE_WEBP; if (isICO(data)) return ImageType.TYPE_ICO; if (isTIFF(data)) return ImageType.TYPE_TIFF; return ImageType.TYPE_UNKNOWN; } // = /** * 判断是否 PNG 图片 * @param data 图片 byte[] * @return {@code true} yes, {@code false} no */ public static boolean isPNG(final byte[] data) { return data != null && data.length >= 8 && (data[0] == (byte) 137 && data[1] == (byte) 80 && data[2] == (byte) 78 && data[3] == (byte) 71 && data[4] == (byte) 13 && data[5] == (byte) 10 && data[6] == (byte) 26 && data[7] == (byte) 10); } /** * 判断是否 JPG 图片 * @param data 图片 byte[] * @return {@code true} yes, {@code false} no */ public static boolean isJPEG(final byte[] data) { return data != null && data.length >= 2 && (data[0] == (byte) 0xFF) && (data[1] == (byte) 0xD8); } /** * 判断是否 BMP 图片 * @param data 图片 byte[] * @return {@code true} yes, {@code false} no */ public static boolean isBMP(final byte[] data) { return data != null && data.length >= 2 && (data[0] == (byte) 0x42) && (data[1] == (byte) 0x4d); } /** * 判断是否 GIF 图片 * @param data 图片 byte[] * @return {@code true} yes, {@code false} no */ public static boolean isGif(final byte[] data) { return data != null && data.length >= 6 && data[0] == 'G' && data[1] == 'I' && data[2] == 'F' && data[3] == '8' && (data[4] == '7' || data[4] == '9') && data[5] == 'a'; } /** * 判断是否 WEBP 图片 * @param data 图片 byte[] * @return {@code true} yes, {@code false} no */ public static boolean isWEBP(final byte[] data) { return data != null && data.length >= 12 && data[0] == 'R' && data[1] == 'I' && data[2] == 'F' && data[3] == 'F' && data[8] == 'W' && (data[9] == 'E' || data[10] == 'B') && data[11] == 'P'; } /** * 判断是否 ICO 图片 * @param data 图片 byte[] * @return {@code true} yes, {@code false} no */ public static boolean isICO(final byte[] data) { return data != null && data.length >= 4 && data[0] == 0 && data[1] == 0 && data[2] == 1 && data[3] == 0; } /** * 判断是否 TIFF 图片 * @param data 图片 byte[] * @return {@code true} yes, {@code false} no */ public static boolean isTIFF(final byte[] data) { if (data != null && data.length >= 4) { if (data[0] == (byte) 73 && data[1] == (byte) 73 && data[2] == (byte) 0x2a && data[3] == 0) { return true; // 49 49 2a 00 } else if (data[0] == (byte) 0x4d && data[1] == (byte) 0x4d && data[2] == 0 && data[3] == (byte) 0x2a) { return true; // 4d 4d 00 2a } else if (data[0] == (byte) 0x4d && data[1] == (byte) 0x4d && data[2] == 0 && data[3] == (byte) 0x2b) { return true; // 4d 4d 00 2b } else if (data[0] == (byte) 73 && data[1] == (byte) 32 && data[2] == (byte) 73) { return true; // 49 20 49 } } return false; } // ============ // = 本地获取 = // ============ /** * 获取 Bitmap * @param file 文件 * @return {@link Bitmap} */ public static Bitmap decodeFile(final File file) { return decodeFile(FileUtils.getAbsolutePath(file), null); } /** * 获取 Bitmap * @param file 文件 * @param options {@link BitmapFactory.Options} * @return {@link Bitmap} */ public static Bitmap decodeFile(final File file, final BitmapFactory.Options options) { return decodeFile(FileUtils.getAbsolutePath(file), options); } /** * 获取 Bitmap * @param filePath 文件路径 * @return {@link Bitmap} */ public static Bitmap decodeFile(final String filePath) { return decodeFile(filePath, null); } /** * 获取 Bitmap * @param filePath 文件路径 * @param options {@link BitmapFactory.Options} * @return {@link Bitmap} */ public static Bitmap decodeFile(final String filePath, final BitmapFactory.Options options) { if (filePath == null) return null; try { return BitmapFactory.decodeFile(filePath, options); } catch (Exception e) { LogPrintUtils.eTag(TAG, e, "decodeFile"); return null; } } // = /** * 获取 Bitmap * @param resId resource identifier * @return {@link Bitmap} */ public static Bitmap decodeResource(@DrawableRes final int resId) { return decodeResource(resId, null); } /** * 获取 Bitmap * @param resId resource identifier * @param options {@link BitmapFactory.Options} * @return {@link Bitmap} */ public static Bitmap decodeResource(@DrawableRes final int resId, final BitmapFactory.Options options) { try { return BitmapFactory.decodeResource(ResourceUtils.getResources(), resId, options); } catch (Exception e) { LogPrintUtils.eTag(TAG, e, "decodeResource"); return null; } } // = /** * 获取 Bitmap * @param inputStream {@link InputStream} * @return {@link Bitmap} */ public static Bitmap decodeStream(final InputStream inputStream) { return decodeStream(inputStream, null); } /** * 获取 Bitmap * @param inputStream {@link InputStream} * @param options {@link BitmapFactory.Options} * @return {@link Bitmap} */ public static Bitmap decodeStream(final InputStream inputStream, final BitmapFactory.Options options) { if (inputStream == null) return null; try { return BitmapFactory.decodeStream(inputStream, null, options); } catch (Exception e) { LogPrintUtils.eTag(TAG, e, "decodeStream"); return null; } } // = /** * 获取 Bitmap * @param fd 文件描述 * @return {@link Bitmap} */ public static Bitmap decodeFileDescriptor(final FileDescriptor fd) { return decodeFileDescriptor(fd, null); } /** * 获取 Bitmap * @param fd 文件描述 * @param options {@link BitmapFactory.Options} * @return {@link Bitmap} */ public static Bitmap decodeFileDescriptor(final FileDescriptor fd, final BitmapFactory.Options options) { if (fd == null) return null; try { return BitmapFactory.decodeFileDescriptor(fd, null, options); } catch (Exception e) { LogPrintUtils.eTag(TAG, e, "decodeFileDescriptor"); return null; } } // = /** * 获取 Bitmap * @param data byte[] * @return {@link Bitmap} */ public static Bitmap decodeByteArray(final byte[] data) { return decodeByteArray(data, 0, (data == null) ? 0 : data.length, null); } /** * 获取 Bitmap * @param data byte[] * @param options {@link BitmapFactory.Options} * @return {@link Bitmap} */ public static Bitmap decodeByteArray(final byte[] data, final BitmapFactory.Options options) { return decodeByteArray(data, 0, (data == null) ? 0 : data.length, options); } /** * 获取 Bitmap * @param data byte[] * @param offset 偏移量 * @param length 所需长度 * @return {@link Bitmap} */ public static Bitmap decodeByteArray(final byte[] data, final int offset, final int length) { return decodeByteArray(data, offset, length, null); } /** * 获取 Bitmap * @param data byte[] * @param offset 偏移量 * @param length 所需长度 * @param options {@link BitmapFactory.Options} * @return {@link Bitmap} */ public static Bitmap decodeByteArray(final byte[] data, final int offset, final int length, final BitmapFactory.Options options) { if (data == null) return null; if ((offset | length) < 0 || data.length < offset + length) return null; try { return BitmapFactory.decodeByteArray(data, offset, length, options); } catch (Exception e) { LogPrintUtils.eTag(TAG, e, "decodeByteArray"); return null; } } // ============ // = 本地保存 = // ============ /** * 保存图片到 SDCard - JPEG * @param bitmap 待保存图片 * @param filePath 保存路径 * @return {@code true} success, {@code false} fail */ public static boolean saveBitmapToSDCardJPEG(final Bitmap bitmap, final String filePath) { return saveBitmapToSDCard(bitmap, filePath, Bitmap.CompressFormat.JPEG, 100); } /** * 保存图片到 SDCard - JPEG * @param bitmap 待保存图片 * @param file 保存路径 * @return {@code true} success, {@code false} fail */ public static boolean saveBitmapToSDCardJPEG(final Bitmap bitmap, final File file) { return saveBitmapToSDCard(bitmap, file, Bitmap.CompressFormat.JPEG, 100); } // = /** * 保存图片到 SDCard - JPEG * @param bitmap 待保存图片 * @param filePath 保存路径 * @param quality 质量 * @return {@code true} success, {@code false} fail */ public static boolean saveBitmapToSDCardJPEG(final Bitmap bitmap, final String filePath, @IntRange(from = 0, to = 100) final int quality) { return saveBitmapToSDCard(bitmap, filePath, Bitmap.CompressFormat.JPEG, quality); } /** * 保存图片到 SDCard - JPEG * @param bitmap 待保存图片 * @param file 保存路径 * @param quality 质量 * @return {@code true} success, {@code false} fail */ public static boolean saveBitmapToSDCardJPEG(final Bitmap bitmap, final File file, @IntRange(from = 0, to = 100) final int quality) { return saveBitmapToSDCard(bitmap, file, Bitmap.CompressFormat.JPEG, quality); } // = /** * 保存图片到 SDCard - PNG * @param bitmap 待保存图片 * @param filePath 保存路径 * @return {@code true} success, {@code false} fail */ public static boolean saveBitmapToSDCardPNG(final Bitmap bitmap, final String filePath) { return saveBitmapToSDCard(bitmap, filePath, Bitmap.CompressFormat.PNG, 100); } /** * 保存图片到 SDCard - PNG * @param bitmap 待保存图片 * @param file 保存路径 * @return {@code true} success, {@code false} fail */ public static boolean saveBitmapToSDCardPNG(final Bitmap bitmap, final File file) { return saveBitmapToSDCard(bitmap, file, Bitmap.CompressFormat.PNG, 100); } // = /** * 保存图片到 SDCard - PNG * @param bitmap 待保存图片 * @param filePath 保存路径 * @param quality 质量 * @return {@code true} success, {@code false} fail */ public static boolean saveBitmapToSDCardPNG(final Bitmap bitmap, final String filePath, @IntRange(from = 0, to = 100) final int quality) { return saveBitmapToSDCard(bitmap, filePath, Bitmap.CompressFormat.PNG, quality); } /** * 保存图片到 SDCard - PNG * @param bitmap 待保存图片 * @param file 保存路径 * @param quality 质量 * @return {@code true} success, {@code false} fail */ public static boolean saveBitmapToSDCardPNG(final Bitmap bitmap, final File file, @IntRange(from = 0, to = 100) final int quality) { return saveBitmapToSDCard(bitmap, file, Bitmap.CompressFormat.PNG, quality); } // = /** * 保存图片到 SDCard - WEBP * @param bitmap 待保存图片 * @param filePath 保存路径 * @return {@code true} success, {@code false} fail */ public static boolean saveBitmapToSDCardWEBP(final Bitmap bitmap, final String filePath) { return saveBitmapToSDCard(bitmap, filePath, Bitmap.CompressFormat.WEBP, 100); } /** * 保存图片到 SDCard - WEBP * @param bitmap 待保存图片 * @param file 保存路径 * @return {@code true} success, {@code false} fail */ public static boolean saveBitmapToSDCardWEBP(final Bitmap bitmap, final File file) { return saveBitmapToSDCard(bitmap, file, Bitmap.CompressFormat.WEBP, 100); } // = /** * 保存图片到 SDCard - WEBP * @param bitmap 待保存图片 * @param filePath 保存路径 * @param quality 质量 * @return {@code true} success, {@code false} fail */ public static boolean saveBitmapToSDCardWEBP(final Bitmap bitmap, final String filePath, @IntRange(from = 0, to = 100) final int quality) { return saveBitmapToSDCard(bitmap, filePath, Bitmap.CompressFormat.WEBP, quality); } /** * 保存图片到 SDCard - WEBP * @param bitmap 待保存图片 * @param file 保存路径 * @param quality 质量 * @return {@code true} success, {@code false} fail */ public static boolean saveBitmapToSDCardWEBP(final Bitmap bitmap, final File file, @IntRange(from = 0, to = 100) final int quality) { return saveBitmapToSDCard(bitmap, file, Bitmap.CompressFormat.WEBP, quality); } // = /** * 保存图片到 SDCard * @param bitmap 待保存图片 * @param filePath 保存路径 * @param format 如 Bitmap.CompressFormat.PNG * @param quality 质量 * @return {@code true} success, {@code false} fail */ public static boolean saveBitmapToSDCard(final Bitmap bitmap, final String filePath, final Bitmap.CompressFormat format, @IntRange(from = 0, to = 100) final int quality) { return saveBitmapToSDCard(bitmap, FileUtils.getFileByPath(filePath), format, quality); } /** * 保存图片到 SDCard * @param bitmap 待保存图片 * @param file 保存路径 * @param format 如 Bitmap.CompressFormat.PNG * @param quality 质量 * @return {@code true} success, {@code false} fail */ public static boolean saveBitmapToSDCard(final Bitmap bitmap, final File file, final Bitmap.CompressFormat format, @IntRange(from = 0, to = 100) final int quality) { if (bitmap == null || file == null || format == null) return false; // 防止 Bitmap 为 null, 或者创建文件夹失败 ( 文件存在则删除 ) if (isEmpty(bitmap) || !FileUtils.createFileByDeleteOldFile(file)) return false; OutputStream os = null; try { os = new BufferedOutputStream(new FileOutputStream(file)); if (os != null) { bitmap.compress(format, quality, os); } } catch (Exception e) { LogPrintUtils.eTag(TAG, e, "saveBitmapToSDCard"); return false; } finally { CloseUtils.closeIOQuietly(os); } return true; } // ================ // = OutputStream = // ================ /** * 保存 JPEG 图片 * @param bitmap 待保存图片 * @param stream {@link OutputStream} * @return {@code true} success, {@code false} fail */ public static boolean saveBitmapToStreamJPEG(final Bitmap bitmap, final OutputStream stream) { return saveBitmapToStream(bitmap, stream, Bitmap.CompressFormat.JPEG, 100); } /** * 保存 JPEG 图片 * @param bitmap 待保存图片 * @param stream {@link OutputStream} * @param quality 质量 * @return {@code true} success, {@code false} fail */ public static boolean saveBitmapToStreamJPEG(final Bitmap bitmap, final OutputStream stream, @IntRange(from = 0, to = 100) final int quality) { return saveBitmapToStream(bitmap, stream, Bitmap.CompressFormat.JPEG, quality); } /** * 保存 PNG 图片 * @param bitmap 待保存图片 * @param stream {@link OutputStream} * @return {@code true} success, {@code false} fail */ public static boolean saveBitmapToStreamPNG(final Bitmap bitmap, final OutputStream stream) { return saveBitmapToStream(bitmap, stream, Bitmap.CompressFormat.PNG, 100); } /** * 保存 PNG 图片 * @param bitmap 待保存图片 * @param stream {@link OutputStream} * @param quality 质量 * @return {@code true} success, {@code false} fail */ public static boolean saveBitmapToStreamPNG(final Bitmap bitmap, final OutputStream stream, @IntRange(from = 0, to = 100) final int quality) { return saveBitmapToStream(bitmap, stream, Bitmap.CompressFormat.PNG, quality); } /** * 保存 WEBP 图片 * @param bitmap 待保存图片 * @param stream {@link OutputStream} * @return {@code true} success, {@code false} fail */ public static boolean saveBitmapToStreamWEBP(final Bitmap bitmap, final OutputStream stream) { return saveBitmapToStream(bitmap, stream, Bitmap.CompressFormat.WEBP, 100); } /** * 保存 WEBP 图片 * @param bitmap 待保存图片 * @param stream {@link OutputStream} * @param quality 质量 * @return {@code true} success, {@code false} fail */ public static boolean saveBitmapToStreamWEBP(final Bitmap bitmap, final OutputStream stream, @IntRange(from = 0, to = 100) final int quality) { return saveBitmapToStream(bitmap, stream, Bitmap.CompressFormat.WEBP, quality); } /** * 保存图片 * @param bitmap 待保存图片 * @param stream {@link OutputStream} * @param format 如 Bitmap.CompressFormat.PNG * @param quality 质量 * @return {@code true} success, {@code false} fail */ public static boolean saveBitmapToStream(final Bitmap bitmap, final OutputStream stream, final Bitmap.CompressFormat format, @IntRange(from = 0, to = 100) final int quality) { if (bitmap == null || stream == null || format == null) return false; try { bitmap.compress(format, quality, stream); } catch (Exception e) { LogPrintUtils.eTag(TAG, e, "saveBitmapToStream"); return false; } finally { CloseUtils.closeIOQuietly(stream); } return true; } // ============ // = Drawable = // ============ /** * 获取 .9 Drawable * <pre> * .9 图片如果需要着色, 需要传入 NinePatchDrawable * setColorFilter(get9PatchDrawable(drawable), color); * </pre> * @param drawable {@link Drawable} * @return .9 {@link NinePatchDrawable} */ public static NinePatchDrawable get9PatchDrawable(final Drawable drawable) { try { return (NinePatchDrawable) drawable; } catch (Exception e) { LogPrintUtils.eTag(TAG, e, "get9PatchDrawable"); } return null; } /** * 图片着色 - tint * @param drawable {@link Drawable} * @param color 颜色值 * @return 着色后的 {@link Drawable} */ public static Drawable setColorFilter(final Drawable drawable, @ColorInt final int color) { return setColorFilter(drawable, color, PorterDuff.Mode.SRC_IN); } /** * 图片着色 - tint * @param drawable {@link Drawable} * @param color 颜色值 * @param mode 着色模式 {@link PorterDuff.Mode} * @return 着色后的 {@link Drawable} */ public static Drawable setColorFilter(final Drawable drawable, @ColorInt final int color, final PorterDuff.Mode mode) { if (drawable != null && mode != null) { try { drawable.setColorFilter(color, mode); } catch (Exception e) { LogPrintUtils.eTag(TAG, e, "setColorFilter"); } } return drawable; } // = /** * 图片着色 - tint * @param drawable {@link Drawable} * @param colorFilter 颜色过滤 ( 效果 ) * @return 着色后的 {@link Drawable} */ public static Drawable setColorFilter(final Drawable drawable, final ColorFilter colorFilter) { if (drawable != null && colorFilter != null) { try { drawable.setColorFilter(colorFilter); } catch (Exception e) { LogPrintUtils.eTag(TAG, e, "setColorFilter"); } } return drawable; } // ========== // = Bitmap = // ========== /** * 获取 Bitmap * @param file 文件 * @param maxWidth 最大宽度 * @param maxHeight 最大高度 * @return {@link Bitmap} */ public static Bitmap getBitmap(final File file, final int maxWidth, final int maxHeight) { return getBitmap(FileUtils.getAbsolutePath(file), maxWidth, maxHeight); } /** * 获取 Bitmap * @param filePath 文件路径 * @param maxWidth 最大宽度 * @param maxHeight 最大高度 * @return {@link Bitmap} */ public static Bitmap getBitmap(final String filePath, final int maxWidth, final int maxHeight) { if (filePath == null) return null; try { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(filePath, options); options.inSampleSize = BitmapUtils.calculateInSampleSize(options, maxWidth, maxHeight); options.inJustDecodeBounds = false; return BitmapFactory.decodeFile(filePath, options); } catch (Exception e) { LogPrintUtils.eTag(TAG, e, "getBitmap"); return null; } } /** * 获取 Bitmap * @param resId resource identifier * @param maxWidth 最大宽度 * @param maxHeight 最大高度 * @return {@link Bitmap} */ public static Bitmap getBitmap(@DrawableRes final int resId, final int maxWidth, final int maxHeight) { try { Resources resources = ResourceUtils.getResources(); BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(resources, resId, options); options.inSampleSize = BitmapUtils.calculateInSampleSize(options, maxWidth, maxHeight); options.inJustDecodeBounds = false; return BitmapFactory.decodeResource(resources, resId, options); } catch (Exception e) { LogPrintUtils.eTag(TAG, e, "getBitmap"); return null; } } /** * 获取 Bitmap * @param inputStream {@link InputStream} * @param maxWidth 最大宽度 * @param maxHeight 最大高度 * @return {@link Bitmap} */ public static Bitmap getBitmap(final InputStream inputStream, final int maxWidth, final int maxHeight) { if (inputStream == null) return null; try { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeStream(inputStream, null, options); options.inSampleSize = BitmapUtils.calculateInSampleSize(options, maxWidth, maxHeight); options.inJustDecodeBounds = false; return BitmapFactory.decodeStream(inputStream, null, options); } catch (Exception e) { LogPrintUtils.eTag(TAG, e, "getBitmap"); return null; } } /** * 获取 Bitmap * @param fd 文件描述 * @param maxWidth 最大宽度 * @param maxHeight 最大高度 * @return {@link Bitmap} */ public static Bitmap getBitmap(final FileDescriptor fd, final int maxWidth, final int maxHeight) { if (fd == null) return null; try { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFileDescriptor(fd, null, options); options.inSampleSize = BitmapUtils.calculateInSampleSize(options, maxWidth, maxHeight); options.inJustDecodeBounds = false; return BitmapFactory.decodeFileDescriptor(fd, null, options); } catch (Exception e) { LogPrintUtils.eTag(TAG, e, "getBitmap"); return null; } } /** * 获取 Bitmap * @param data byte[] * @param maxWidth 最大宽度 * @param maxHeight 最大高度 * @return {@link Bitmap} */ public static Bitmap getBitmap(final byte[] data, final int maxWidth, final int maxHeight) { if (data == null) return null; try { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeByteArray(data, 0, data.length, options); options.inSampleSize = BitmapUtils.calculateInSampleSize(options, maxWidth, maxHeight); options.inJustDecodeBounds = false; return BitmapFactory.decodeByteArray(data, 0, data.length, options); } catch (Exception e) { LogPrintUtils.eTag(TAG, e, "getBitmap"); return null; } } // = /** * 通过 View 绘制为 Bitmap * @param view {@link View} * @return {@link Bitmap} */ public static Bitmap getBitmapFromView(final View view) { if (view == null) return null; try { Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); view.layout(view.getLeft(), view.getTop(), view.getRight(), view.getBottom()); view.draw(canvas); return bitmap; } catch (Exception e) { LogPrintUtils.eTag(TAG, e, "getBitmapFromView"); } return null; } /** * 通过 View Cache 绘制为 Bitmap * @param view {@link View} * @return {@link Bitmap} */ public static Bitmap getBitmapFromViewCache(final View view) { if (view == null) return null; try { // 清除视图焦点 view.clearFocus(); // 将视图设为不可点击 view.setPressed(false); // 获取视图是否可以保存画图缓存 boolean willNotCache = view.willNotCacheDrawing(); view.setWillNotCacheDrawing(false); // 获取绘制缓存位图的背景颜色 int color = view.getDrawingCacheBackgroundColor(); // 设置绘图背景颜色 view.setDrawingCacheBackgroundColor(0); if (color != 0) { // 获取的背景不是黑色的则释放以前的绘图缓存 view.destroyDrawingCache(); // 释放绘图资源所使用的缓存 } // 重新创建绘图缓存, 此时的背景色是黑色 view.buildDrawingCache(); // 获取绘图缓存, 注意这里得到的只是一个图像的引用 Bitmap cacheBitmap = view.getDrawingCache(); if (cacheBitmap == null) return null; Bitmap bitmap = Bitmap.createBitmap(cacheBitmap); // 释放位图内存 view.destroyDrawingCache(); // 回滚以前的缓存设置、缓存颜色设置 view.setWillNotCacheDrawing(willNotCache); view.setDrawingCacheBackgroundColor(color); return bitmap; } catch (Exception e) { LogPrintUtils.eTag(TAG, e, "getBitmapFromViewCache"); } return null; } // ========================= // = Bitmap、Drawable 转换 = // ========================= // =============== // = 转为 byte[] = // =============== /** * Bitmap 转换成 byte[] * @param bitmap 待转换图片 * @return byte[] */ public static byte[] bitmapToByte(final Bitmap bitmap) { return bitmapToByte(bitmap, 100, Bitmap.CompressFormat.PNG); } /** * Bitmap 转换成 byte[] * @param bitmap 待转换图片 * @param format 如 Bitmap.CompressFormat.PNG * @return byte[] */ public static byte[] bitmapToByte(final Bitmap bitmap, final Bitmap.CompressFormat format) { return bitmapToByte(bitmap, 100, format); } /** * Bitmap 转换成 byte[] * @param bitmap 待转换图片 * @param quality 质量 * @param format 如 Bitmap.CompressFormat.PNG * @return byte[] */ public static byte[] bitmapToByte(final Bitmap bitmap, @IntRange(from = 0, to = 100) final int quality, final Bitmap.CompressFormat format) { if (bitmap == null || format == null) return null; try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); bitmap.compress(format, quality, baos); return baos.toByteArray(); } catch (Exception e) { LogPrintUtils.eTag(TAG, e, "bitmapToByte"); } return null; } // = /** * Drawable 转换成 byte[] * @param drawable 待转换图片 * @return byte[] */ public static byte[] drawableToByte(final Drawable drawable) { return drawableToByte(drawable, 100, Bitmap.CompressFormat.PNG); } /** * Drawable 转换成 byte[] * @param drawable 待转换图片 * @param format 如 Bitmap.CompressFormat.PNG * @return byte[] */ public static byte[] drawableToByte(final Drawable drawable, final Bitmap.CompressFormat format) { return drawableToByte(drawable, 100, format); } /** * Drawable 转换成 byte[] * @param drawable 待转换图片 * @param quality 质量 * @param format 如 Bitmap.CompressFormat.PNG * @return byte[] */ public static byte[] drawableToByte(final Drawable drawable, @IntRange(from = 0, to = 100) final int quality, final Bitmap.CompressFormat format) { if (drawable == null || format == null) return null; return bitmapToByte(drawableToBitmap(drawable), quality, format); } // ========== // = Bitmap = // ========== /** * byte[] 转 Bitmap * @param data byte[] * @return {@link Bitmap} */ public static Bitmap byteToBitmap(final byte[] data) { return decodeByteArray(data); } /** * Bitmap 转 Drawable * @param bitmap 待转换图片 * @return {@link Drawable} */ public static Drawable bitmapToDrawable(final Bitmap bitmap) { if (bitmap == null) return null; try { return new BitmapDrawable(ResourceUtils.getResources(), bitmap); } catch (Exception e) { LogPrintUtils.eTag(TAG, e, "bitmapToDrawable"); } return null; } // ============ // = Drawable = // ============ /** * byte[] 转 Drawable * @param data byte[] * @return {@link Drawable} */ public static Drawable byteToDrawable(final byte[] data) { return bitmapToDrawable(decodeByteArray(data)); } /** * Drawable 转 Bitmap * @param drawable 待转换图片 * @return {@link Bitmap} */ public static Bitmap drawableToBitmap(final Drawable drawable) { if (drawable == null) return null; // 属于 BitmapDrawable 直接转换 if (drawable instanceof BitmapDrawable) { try { BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; if (bitmapDrawable.getBitmap() != null) { return bitmapDrawable.getBitmap(); } } catch (Exception e) { LogPrintUtils.eTag(TAG, e, "drawableToBitmap - BitmapDrawable"); } } try { // 获取 drawable 的宽高 int width = drawable.getIntrinsicWidth(); int height = drawable.getIntrinsicHeight(); // 获取 drawable 的颜色格式 Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; // 创建 bitmap Bitmap bitmap = Bitmap.createBitmap(width, height, config); // 创建 bitmap 画布 Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, width, height); // 把 drawable 内容画到画布中 drawable.draw(canvas); return bitmap; } catch (Exception e) { LogPrintUtils.eTag(TAG, e, "drawableToBitmap"); } return null; } // = /** * 设置 Drawable 绘制区域 * @param drawable {@link Drawable} * @return {@link Drawable} */ public static Drawable setBounds(final Drawable drawable) { try { drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); } catch (Exception e) { LogPrintUtils.eTag(TAG, e, "setBounds"); } return drawable; } /** * 设置 Drawable 绘制区域 * @param drawable {@link Drawable} * @param right right 坐标 * @param bottom bottom 坐标 * @return {@link Drawable} */ public static Drawable setBounds(final Drawable drawable, final int right, final int bottom) { return setBounds(drawable, 0, 0, right, bottom); } /** * 设置 Drawable 绘制区域 * @param drawable {@link Drawable} * @param left left 坐标 * @param top top 坐标 * @param right right 坐标 * @param bottom bottom 坐标 * @return {@link Drawable} */ public static Drawable setBounds(final Drawable drawable, final int left, final int top, final int right, final int bottom) { try { drawable.setBounds(left, top, right, bottom); } catch (Exception e) { LogPrintUtils.eTag(TAG, e, "setBounds"); } return drawable; } }