import android.annotation.TargetApi; | |
import android.content.Context; | |
import android.content.res.Resources; | |
import android.graphics.Bitmap; | |
import android.graphics.Bitmap.CompressFormat; | |
import android.graphics.BitmapFactory; | |
import android.graphics.Canvas; | |
import android.graphics.Color; | |
import android.graphics.ColorMatrix; | |
import android.graphics.ColorMatrixColorFilter; | |
import android.graphics.LinearGradient; | |
import android.graphics.Matrix; | |
import android.graphics.Paint; | |
import android.graphics.PixelFormat; | |
import android.graphics.PorterDuff; | |
import android.graphics.PorterDuffColorFilter; | |
import android.graphics.PorterDuffXfermode; | |
import android.graphics.Rect; | |
import android.graphics.RectF; | |
import android.graphics.Shader; | |
import android.graphics.drawable.BitmapDrawable; | |
import android.graphics.drawable.Drawable; | |
import android.graphics.drawable.NinePatchDrawable; | |
import android.media.ExifInterface; | |
import android.os.Build; | |
import android.renderscript.Allocation; | |
import android.renderscript.Element; | |
import android.renderscript.RenderScript; | |
import android.renderscript.ScriptIntrinsicBlur; | |
import android.support.annotation.FloatRange; | |
import android.support.annotation.IntRange; | |
import android.view.View; | |
import java.io.BufferedInputStream; | |
import java.io.BufferedOutputStream; | |
import java.io.ByteArrayOutputStream; | |
import java.io.File; | |
import java.io.FileDescriptor; | |
import java.io.FileInputStream; | |
import java.io.FileNotFoundException; | |
import java.io.FileOutputStream; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.io.OutputStream; | |
/** | |
* <pre> | |
* author: Blankj | |
* blog : http://blankj.com | |
* time : 2016/8/12 | |
* desc : 图片相关工具类 | |
* </pre> | |
*/ | |
public final class ImageUtils { | |
private ImageUtils() { | |
throw new UnsupportedOperationException("u can't instantiate me..."); | |
} | |
/** | |
* bitmap转byteArr | |
* | |
* @param bitmap bitmap对象 | |
* @param format 格式 | |
* @return 字节数组 | |
*/ | |
public static byte[] bitmap2Bytes(Bitmap bitmap, CompressFormat format) { | |
if (bitmap == null) return null; | |
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |
bitmap.compress(format, 100, baos); | |
return baos.toByteArray(); | |
} | |
/** | |
* byteArr转bitmap | |
* | |
* @param bytes 字节数组 | |
* @return bitmap | |
*/ | |
public static Bitmap bytes2Bitmap(byte[] bytes) { | |
return (bytes == null || bytes.length == 0) ? null : BitmapFactory.decodeByteArray(bytes, 0, bytes.length); | |
} | |
/** | |
* drawable转bitmap | |
* | |
* @param drawable drawable对象 | |
* @return bitmap | |
*/ | |
public static Bitmap drawable2Bitmap(Drawable drawable) { | |
if (drawable instanceof BitmapDrawable) { | |
return ((BitmapDrawable) drawable).getBitmap(); | |
} else if (drawable instanceof NinePatchDrawable) { | |
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; | |
} else { | |
return null; | |
} | |
} | |
/** | |
* bitmap转drawable | |
* | |
* @param res resources对象 | |
* @param bitmap bitmap对象 | |
* @return drawable | |
*/ | |
public static Drawable bitmap2Drawable(Resources res, Bitmap bitmap) { | |
return bitmap == null ? null : new BitmapDrawable(res, bitmap); | |
} | |
/** | |
* drawable转byteArr | |
* | |
* @param drawable drawable对象 | |
* @param format 格式 | |
* @return 字节数组 | |
*/ | |
public static byte[] drawable2Bytes(Drawable drawable, CompressFormat format) { | |
return drawable == null ? null : bitmap2Bytes(drawable2Bitmap(drawable), format); | |
} | |
/** | |
* byteArr转drawable | |
* | |
* @param res resources对象 | |
* @param bytes 字节数组 | |
* @return drawable | |
*/ | |
public static Drawable bytes2Drawable(Resources res, byte[] bytes) { | |
return res == null ? null : bitmap2Drawable(res, bytes2Bitmap(bytes)); | |
} | |
/** | |
* view转Bitmap | |
* | |
* @param view 视图 | |
* @return bitmap | |
*/ | |
public static Bitmap view2Bitmap(View view) { | |
if (view == null) return null; | |
Bitmap ret = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888); | |
Canvas canvas = new Canvas(ret); | |
Drawable bgDrawable = view.getBackground(); | |
if (bgDrawable != null) { | |
bgDrawable.draw(canvas); | |
} else { | |
canvas.drawColor(Color.WHITE); | |
} | |
view.draw(canvas); | |
return ret; | |
} | |
/** | |
* 计算采样大小 | |
* | |
* @param options 选项 | |
* @param maxWidth 最大宽度 | |
* @param maxHeight 最大高度 | |
* @return 采样大小 | |
*/ | |
private static int calculateInSampleSize(BitmapFactory.Options options, int maxWidth, int maxHeight) { | |
if (maxWidth == 0 || maxHeight == 0) return 1; | |
int height = options.outHeight; | |
int width = options.outWidth; | |
int inSampleSize = 1; | |
while ((height >>= 1) >= maxHeight && (width >>= 1) >= maxWidth) { | |
inSampleSize <<= 1; | |
} | |
return inSampleSize; | |
} | |
/** | |
* 获取bitmap | |
* | |
* @param file 文件 | |
* @return bitmap | |
*/ | |
public static Bitmap getBitmap(File file) { | |
if (file == null) return null; | |
InputStream is = null; | |
try { | |
is = new BufferedInputStream(new FileInputStream(file)); | |
return BitmapFactory.decodeStream(is); | |
} catch (FileNotFoundException e) { | |
e.printStackTrace(); | |
return null; | |
} finally { | |
CloseUtils.closeIO(is); | |
} | |
} | |
/** | |
* 获取bitmap | |
* | |
* @param file 文件 | |
* @param maxWidth 最大宽度 | |
* @param maxHeight 最大高度 | |
* @return bitmap | |
*/ | |
public static Bitmap getBitmap(File file, int maxWidth, int maxHeight) { | |
if (file == null) return null; | |
InputStream is = null; | |
try { | |
BitmapFactory.Options options = new BitmapFactory.Options(); | |
options.inJustDecodeBounds = true; | |
is = new BufferedInputStream(new FileInputStream(file)); | |
BitmapFactory.decodeStream(is, null, options); | |
options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight); | |
options.inJustDecodeBounds = false; | |
return BitmapFactory.decodeStream(is, null, options); | |
} catch (FileNotFoundException e) { | |
e.printStackTrace(); | |
return null; | |
} finally { | |
CloseUtils.closeIO(is); | |
} | |
} | |
/** | |
* 获取bitmap | |
* | |
* @param filePath 文件路径 | |
* @return bitmap | |
*/ | |
public static Bitmap getBitmap(String filePath) { | |
if (isSpace(filePath)) return null; | |
return BitmapFactory.decodeFile(filePath); | |
} | |
/** | |
* 获取bitmap | |
* | |
* @param filePath 文件路径 | |
* @param maxWidth 最大宽度 | |
* @param maxHeight 最大高度 | |
* @return bitmap | |
*/ | |
public static Bitmap getBitmap(String filePath, int maxWidth, int maxHeight) { | |
if (isSpace(filePath)) return null; | |
BitmapFactory.Options options = new BitmapFactory.Options(); | |
options.inJustDecodeBounds = true; | |
BitmapFactory.decodeFile(filePath, options); | |
options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight); | |
options.inJustDecodeBounds = false; | |
return BitmapFactory.decodeFile(filePath, options); | |
} | |
/** | |
* 获取bitmap | |
* | |
* @param is 输入流 | |
* @return bitmap | |
*/ | |
public static Bitmap getBitmap(InputStream is) { | |
if (is == null) return null; | |
return BitmapFactory.decodeStream(is); | |
} | |
/** | |
* 获取bitmap | |
* | |
* @param is 输入流 | |
* @param maxWidth 最大宽度 | |
* @param maxHeight 最大高度 | |
* @return bitmap | |
*/ | |
public static Bitmap getBitmap(InputStream is, int maxWidth, int maxHeight) { | |
if (is == null) return null; | |
BitmapFactory.Options options = new BitmapFactory.Options(); | |
options.inJustDecodeBounds = true; | |
BitmapFactory.decodeStream(is, null, options); | |
options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight); | |
options.inJustDecodeBounds = false; | |
return BitmapFactory.decodeStream(is, null, options); | |
} | |
/** | |
* 获取bitmap | |
* | |
* @param data 数据 | |
* @param offset 偏移量 | |
* @return bitmap | |
*/ | |
public static Bitmap getBitmap(byte[] data, int offset) { | |
if (data.length == 0) return null; | |
return BitmapFactory.decodeByteArray(data, offset, data.length); | |
} | |
/** | |
* 获取bitmap | |
* | |
* @param data 数据 | |
* @param offset 偏移量 | |
* @param maxWidth 最大宽度 | |
* @param maxHeight 最大高度 | |
* @return bitmap | |
*/ | |
public static Bitmap getBitmap(byte[] data, int offset, int maxWidth, int maxHeight) { | |
if (data.length == 0) return null; | |
BitmapFactory.Options options = new BitmapFactory.Options(); | |
options.inJustDecodeBounds = true; | |
BitmapFactory.decodeByteArray(data, offset, data.length, options); | |
options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight); | |
options.inJustDecodeBounds = false; | |
return BitmapFactory.decodeByteArray(data, offset, data.length, options); | |
} | |
/** | |
* 获取bitmap | |
* | |
* @param res 资源对象 | |
* @param id 资源id | |
* @return bitmap | |
*/ | |
public static Bitmap getBitmap(Resources res, int id) { | |
if (res == null) return null; | |
return BitmapFactory.decodeResource(res, id); | |
} | |
/** | |
* 获取bitmap | |
* | |
* @param res 资源对象 | |
* @param id 资源id | |
* @param maxWidth 最大宽度 | |
* @param maxHeight 最大高度 | |
* @return bitmap | |
*/ | |
public static Bitmap getBitmap(Resources res, int id, int maxWidth, int maxHeight) { | |
if (res == null) return null; | |
BitmapFactory.Options options = new BitmapFactory.Options(); | |
options.inJustDecodeBounds = true; | |
BitmapFactory.decodeResource(res, id, options); | |
options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight); | |
options.inJustDecodeBounds = false; | |
return BitmapFactory.decodeResource(res, id, options); | |
} | |
/** | |
* 获取bitmap | |
* | |
* @param fd 文件描述 | |
* @return bitmap | |
*/ | |
public static Bitmap getBitmap(FileDescriptor fd) { | |
if (fd == null) return null; | |
return BitmapFactory.decodeFileDescriptor(fd); | |
} | |
/** | |
* 获取bitmap | |
* | |
* @param fd 文件描述 | |
* @param maxWidth 最大宽度 | |
* @param maxHeight 最大高度 | |
* @return bitmap | |
*/ | |
public static Bitmap getBitmap(FileDescriptor fd, int maxWidth, int maxHeight) { | |
if (fd == null) return null; | |
BitmapFactory.Options options = new BitmapFactory.Options(); | |
options.inJustDecodeBounds = true; | |
BitmapFactory.decodeFileDescriptor(fd, null, options); | |
options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight); | |
options.inJustDecodeBounds = false; | |
return BitmapFactory.decodeFileDescriptor(fd, null, options); | |
} | |
/** | |
* 缩放图片 | |
* | |
* @param src 源图片 | |
* @param newWidth 新宽度 | |
* @param newHeight 新高度 | |
* @return 缩放后的图片 | |
*/ | |
public static Bitmap scale(Bitmap src, int newWidth, int newHeight) { | |
return scale(src, newWidth, newHeight, false); | |
} | |
/** | |
* 缩放图片 | |
* | |
* @param src 源图片 | |
* @param newWidth 新宽度 | |
* @param newHeight 新高度 | |
* @param recycle 是否回收 | |
* @return 缩放后的图片 | |
*/ | |
public static Bitmap scale(Bitmap src, int newWidth, int newHeight, boolean recycle) { | |
if (isEmptyBitmap(src)) return null; | |
Bitmap ret = Bitmap.createScaledBitmap(src, newWidth, newHeight, true); | |
if (recycle && !src.isRecycled()) src.recycle(); | |
return ret; | |
} | |
/** | |
* 缩放图片 | |
* | |
* @param src 源图片 | |
* @param scaleWidth 缩放宽度倍数 | |
* @param scaleHeight 缩放高度倍数 | |
* @return 缩放后的图片 | |
*/ | |
public static Bitmap scale(Bitmap src, float scaleWidth, float scaleHeight) { | |
return scale(src, scaleWidth, scaleHeight, false); | |
} | |
/** | |
* 缩放图片 | |
* | |
* @param src 源图片 | |
* @param scaleWidth 缩放宽度倍数 | |
* @param scaleHeight 缩放高度倍数 | |
* @param recycle 是否回收 | |
* @return 缩放后的图片 | |
*/ | |
public static Bitmap scale(Bitmap src, float scaleWidth, float scaleHeight, boolean recycle) { | |
if (isEmptyBitmap(src)) return null; | |
Matrix matrix = new Matrix(); | |
matrix.setScale(scaleWidth, scaleHeight); | |
Bitmap ret = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, true); | |
if (recycle && !src.isRecycled()) src.recycle(); | |
return ret; | |
} | |
/** | |
* 裁剪图片 | |
* | |
* @param src 源图片 | |
* @param x 开始坐标x | |
* @param y 开始坐标y | |
* @param width 裁剪宽度 | |
* @param height 裁剪高度 | |
* @return 裁剪后的图片 | |
*/ | |
public static Bitmap clip(Bitmap src, int x, int y, int width, int height) { | |
return clip(src, x, y, width, height, false); | |
} | |
/** | |
* 裁剪图片 | |
* | |
* @param src 源图片 | |
* @param x 开始坐标x | |
* @param y 开始坐标y | |
* @param width 裁剪宽度 | |
* @param height 裁剪高度 | |
* @param recycle 是否回收 | |
* @return 裁剪后的图片 | |
*/ | |
public static Bitmap clip(Bitmap src, int x, int y, int width, int height, boolean recycle) { | |
if (isEmptyBitmap(src)) return null; | |
Bitmap ret = Bitmap.createBitmap(src, x, y, width, height); | |
if (recycle && !src.isRecycled()) src.recycle(); | |
return ret; | |
} | |
/** | |
* 倾斜图片 | |
* | |
* @param src 源图片 | |
* @param kx 倾斜因子x | |
* @param ky 倾斜因子y | |
* @return 倾斜后的图片 | |
*/ | |
public static Bitmap skew(Bitmap src, float kx, float ky) { | |
return skew(src, kx, ky, 0, 0, false); | |
} | |
/** | |
* 倾斜图片 | |
* | |
* @param src 源图片 | |
* @param kx 倾斜因子x | |
* @param ky 倾斜因子y | |
* @param recycle 是否回收 | |
* @return 倾斜后的图片 | |
*/ | |
public static Bitmap skew(Bitmap src, float kx, float ky, boolean recycle) { | |
return skew(src, kx, ky, 0, 0, recycle); | |
} | |
/** | |
* 倾斜图片 | |
* | |
* @param src 源图片 | |
* @param kx 倾斜因子x | |
* @param ky 倾斜因子y | |
* @param px 平移因子x | |
* @param py 平移因子y | |
* @return 倾斜后的图片 | |
*/ | |
public static Bitmap skew(Bitmap src, float kx, float ky, float px, float py) { | |
return skew(src, kx, ky, px, py, false); | |
} | |
/** | |
* 倾斜图片 | |
* | |
* @param src 源图片 | |
* @param kx 倾斜因子x | |
* @param ky 倾斜因子y | |
* @param px 平移因子x | |
* @param py 平移因子y | |
* @param recycle 是否回收 | |
* @return 倾斜后的图片 | |
*/ | |
public static Bitmap skew(Bitmap src, float kx, float ky, float px, float py, boolean recycle) { | |
if (isEmptyBitmap(src)) return null; | |
Matrix matrix = new Matrix(); | |
matrix.setSkew(kx, ky, px, py); | |
Bitmap ret = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, true); | |
if (recycle && !src.isRecycled()) src.recycle(); | |
return ret; | |
} | |
/** | |
* 旋转图片 | |
* | |
* @param src 源图片 | |
* @param degrees 旋转角度 | |
* @param px 旋转点横坐标 | |
* @param py 旋转点纵坐标 | |
* @return 旋转后的图片 | |
*/ | |
public static Bitmap rotate(Bitmap src, int degrees, float px, float py) { | |
return rotate(src, degrees, px, py, false); | |
} | |
/** | |
* 旋转图片 | |
* | |
* @param src 源图片 | |
* @param degrees 旋转角度 | |
* @param px 旋转点横坐标 | |
* @param py 旋转点纵坐标 | |
* @param recycle 是否回收 | |
* @return 旋转后的图片 | |
*/ | |
public static Bitmap rotate(Bitmap src, int degrees, float px, float py, boolean recycle) { | |
if (isEmptyBitmap(src)) return null; | |
if (degrees == 0) return src; | |
Matrix matrix = new Matrix(); | |
matrix.setRotate(degrees, px, py); | |
Bitmap ret = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, true); | |
if (recycle && !src.isRecycled()) src.recycle(); | |
return ret; | |
} | |
/** | |
* 获取图片旋转角度 | |
* | |
* @param filePath 文件路径 | |
* @return 旋转角度 | |
*/ | |
public static int getRotateDegree(String filePath) { | |
int degree = 0; | |
try { | |
ExifInterface exifInterface = new ExifInterface(filePath); | |
int orientation = exifInterface.getAttributeInt( | |
ExifInterface.TAG_ORIENTATION, | |
ExifInterface.ORIENTATION_NORMAL); | |
switch (orientation) { | |
default: | |
case ExifInterface.ORIENTATION_ROTATE_90: | |
degree = 90; | |
break; | |
case ExifInterface.ORIENTATION_ROTATE_180: | |
degree = 180; | |
break; | |
case ExifInterface.ORIENTATION_ROTATE_270: | |
degree = 270; | |
break; | |
} | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
return degree; | |
} | |
/** | |
* 转为圆形图片 | |
* | |
* @param src 源图片 | |
* @return 圆形图片 | |
*/ | |
public static Bitmap toRound(Bitmap src) { | |
return toRound(src, false); | |
} | |
/** | |
* 转为圆形图片 | |
* | |
* @param src 源图片 | |
* @param recycle 是否回收 | |
* @return 圆形图片 | |
*/ | |
public static Bitmap toRound(Bitmap src, boolean recycle) { | |
if (isEmptyBitmap(src)) return null; | |
int width = src.getWidth(); | |
int height = src.getHeight(); | |
int radius = Math.min(width, height) >> 1; | |
Bitmap ret = Bitmap.createBitmap(width, height, src.getConfig()); | |
Paint paint = new Paint(); | |
Canvas canvas = new Canvas(ret); | |
Rect rect = new Rect(0, 0, width, height); | |
paint.setAntiAlias(true); | |
canvas.drawARGB(0, 0, 0, 0); | |
canvas.drawCircle(width >> 1, height >> 1, radius, paint); | |
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); | |
canvas.drawBitmap(src, rect, rect, paint); | |
if (recycle && !src.isRecycled()) src.recycle(); | |
return ret; | |
} | |
/** | |
* 转为圆角图片 | |
* | |
* @param src 源图片 | |
* @param radius 圆角的度数 | |
* @return 圆角图片 | |
*/ | |
public static Bitmap toRoundCorner(Bitmap src, float radius) { | |
return toRoundCorner(src, radius, false); | |
} | |
/** | |
* 转为圆角图片 | |
* | |
* @param src 源图片 | |
* @param radius 圆角的度数 | |
* @param recycle 是否回收 | |
* @return 圆角图片 | |
*/ | |
public static Bitmap toRoundCorner(Bitmap src, float radius, boolean recycle) { | |
if (null == src) return null; | |
int width = src.getWidth(); | |
int height = src.getHeight(); | |
Bitmap ret = Bitmap.createBitmap(width, height, src.getConfig()); | |
Paint paint = new Paint(); | |
Canvas canvas = new Canvas(ret); | |
Rect rect = new Rect(0, 0, width, height); | |
paint.setAntiAlias(true); | |
canvas.drawRoundRect(new RectF(rect), radius, radius, paint); | |
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); | |
canvas.drawBitmap(src, rect, rect, paint); | |
if (recycle && !src.isRecycled()) src.recycle(); | |
return ret; | |
} | |
/** | |
* 快速模糊 | |
* <p>先缩小原图,对小图进行模糊,再放大回原先尺寸</p> | |
* | |
* @param src 源图片 | |
* @param scale 缩放比例(0...1) | |
* @param radius 模糊半径 | |
* @return 模糊后的图片 | |
*/ | |
public static Bitmap fastBlur(Bitmap src, | |
@FloatRange(from = 0, to = 1, fromInclusive = false) float scale, | |
@FloatRange(from = 0, to = 25, fromInclusive = false) float radius) { | |
return fastBlur(src, scale, radius, false); | |
} | |
/** | |
* 快速模糊图片 | |
* <p>先缩小原图,对小图进行模糊,再放大回原先尺寸</p> | |
* | |
* @param src 源图片 | |
* @param scale 缩放比例(0...1) | |
* @param radius 模糊半径(0...25) | |
* @param recycle 是否回收 | |
* @return 模糊后的图片 | |
*/ | |
public static Bitmap fastBlur(Bitmap src, | |
@FloatRange(from = 0, to = 1, fromInclusive = false) float scale, | |
@FloatRange(from = 0, to = 25, fromInclusive = false) float radius, | |
boolean recycle) { | |
if (isEmptyBitmap(src)) return null; | |
int width = src.getWidth(); | |
int height = src.getHeight(); | |
int scaleWidth = (int) (width * scale + 0.5f); | |
int scaleHeight = (int) (height * scale + 0.5f); | |
if (scaleWidth == 0 || scaleHeight == 0) return null; | |
Bitmap scaleBitmap = Bitmap.createScaledBitmap(src, scaleWidth, scaleHeight, true); | |
Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG); | |
Canvas canvas = new Canvas(); | |
PorterDuffColorFilter filter = new PorterDuffColorFilter( | |
Color.TRANSPARENT, PorterDuff.Mode.SRC_ATOP); | |
paint.setColorFilter(filter); | |
canvas.scale(scale, scale); | |
canvas.drawBitmap(scaleBitmap, 0, 0, paint); | |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { | |
scaleBitmap = renderScriptBlur(Utils.getContext(), scaleBitmap, radius); | |
} else { | |
scaleBitmap = stackBlur(scaleBitmap, (int) radius, recycle); | |
} | |
if (scale == 1) return scaleBitmap; | |
Bitmap ret = Bitmap.createScaledBitmap(scaleBitmap, width, height, true); | |
if (scaleBitmap != null && !scaleBitmap.isRecycled()) scaleBitmap.recycle(); | |
if (recycle && !src.isRecycled()) src.recycle(); | |
return ret; | |
} | |
/** | |
* renderScript模糊图片 | |
* <p>API大于17</p> | |
* | |
* @param context 上下文 | |
* @param src 源图片 | |
* @param radius 模糊半径(0...25) | |
* @return 模糊后的图片 | |
*/ | |
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) | |
public static Bitmap renderScriptBlur(Context context, Bitmap src, @FloatRange(from = 0, to = 25, fromInclusive = false) float radius) { | |
if (isEmptyBitmap(src)) return null; | |
RenderScript rs = null; | |
try { | |
rs = RenderScript.create(context); | |
rs.setMessageHandler(new RenderScript.RSMessageHandler()); | |
Allocation input = Allocation.createFromBitmap(rs, src, Allocation.MipmapControl.MIPMAP_NONE, Allocation | |
.USAGE_SCRIPT); | |
Allocation output = Allocation.createTyped(rs, input.getType()); | |
ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); | |
blurScript.setInput(input); | |
blurScript.setRadius(radius); | |
blurScript.forEach(output); | |
output.copyTo(src); | |
} finally { | |
if (rs != null) { | |
rs.destroy(); | |
} | |
} | |
return src; | |
} | |
/** | |
* stack模糊图片 | |
* | |
* @param src 源图片 | |
* @param radius 模糊半径 | |
* @param recycle 是否回收 | |
* @return stack模糊后的图片 | |
*/ | |
public static Bitmap stackBlur(Bitmap src, int radius, boolean recycle) { | |
Bitmap ret; | |
if (recycle) { | |
ret = src; | |
} else { | |
ret = src.copy(src.getConfig(), true); | |
} | |
if (radius < 1) { | |
return null; | |
} | |
int w = ret.getWidth(); | |
int h = ret.getHeight(); | |
int[] pix = new int[w * h]; | |
ret.getPixels(pix, 0, w, 0, 0, w, h); | |
int wm = w - 1; | |
int hm = h - 1; | |
int wh = w * h; | |
int div = radius + radius + 1; | |
int r[] = new int[wh]; | |
int g[] = new int[wh]; | |
int b[] = new int[wh]; | |
int rsum, gsum, bsum, x, y, i, p, yp, yi, yw; | |
int vmin[] = new int[Math.max(w, h)]; | |
int divsum = (div + 1) >> 1; | |
divsum *= divsum; | |
int dv[] = new int[256 * divsum]; | |
for (i = 0; i < 256 * divsum; i++) { | |
dv[i] = (i / divsum); | |
} | |
yw = yi = 0; | |
int[][] stack = new int[div][3]; | |
int stackpointer; | |
int stackstart; | |
int[] sir; | |
int rbs; | |
int r1 = radius + 1; | |
int routsum, goutsum, boutsum; | |
int rinsum, ginsum, binsum; | |
for (y = 0; y < h; y++) { | |
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; | |
for (i = -radius; i <= radius; i++) { | |
p = pix[yi + Math.min(wm, Math.max(i, 0))]; | |
sir = stack[i + radius]; | |
sir[0] = (p & 0xff0000) >> 16; | |
sir[1] = (p & 0x00ff00) >> 8; | |
sir[2] = (p & 0x0000ff); | |
rbs = r1 - Math.abs(i); | |
rsum += sir[0] * rbs; | |
gsum += sir[1] * rbs; | |
bsum += sir[2] * rbs; | |
if (i > 0) { | |
rinsum += sir[0]; | |
ginsum += sir[1]; | |
binsum += sir[2]; | |
} else { | |
routsum += sir[0]; | |
goutsum += sir[1]; | |
boutsum += sir[2]; | |
} | |
} | |
stackpointer = radius; | |
for (x = 0; x < w; x++) { | |
r[yi] = dv[rsum]; | |
g[yi] = dv[gsum]; | |
b[yi] = dv[bsum]; | |
rsum -= routsum; | |
gsum -= goutsum; | |
bsum -= boutsum; | |
stackstart = stackpointer - radius + div; | |
sir = stack[stackstart % div]; | |
routsum -= sir[0]; | |
goutsum -= sir[1]; | |
boutsum -= sir[2]; | |
if (y == 0) { | |
vmin[x] = Math.min(x + radius + 1, wm); | |
} | |
p = pix[yw + vmin[x]]; | |
sir[0] = (p & 0xff0000) >> 16; | |
sir[1] = (p & 0x00ff00) >> 8; | |
sir[2] = (p & 0x0000ff); | |
rinsum += sir[0]; | |
ginsum += sir[1]; | |
binsum += sir[2]; | |
rsum += rinsum; | |
gsum += ginsum; | |
bsum += binsum; | |
stackpointer = (stackpointer + 1) % div; | |
sir = stack[(stackpointer) % div]; | |
routsum += sir[0]; | |
goutsum += sir[1]; | |
boutsum += sir[2]; | |
rinsum -= sir[0]; | |
ginsum -= sir[1]; | |
binsum -= sir[2]; | |
yi++; | |
} | |
yw += w; | |
} | |
for (x = 0; x < w; x++) { | |
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; | |
yp = -radius * w; | |
for (i = -radius; i <= radius; i++) { | |
yi = Math.max(0, yp) + x; | |
sir = stack[i + radius]; | |
sir[0] = r[yi]; | |
sir[1] = g[yi]; | |
sir[2] = b[yi]; | |
rbs = r1 - Math.abs(i); | |
rsum += r[yi] * rbs; | |
gsum += g[yi] * rbs; | |
bsum += b[yi] * rbs; | |
if (i > 0) { | |
rinsum += sir[0]; | |
ginsum += sir[1]; | |
binsum += sir[2]; | |
} else { | |
routsum += sir[0]; | |
goutsum += sir[1]; | |
boutsum += sir[2]; | |
} | |
if (i < hm) { | |
yp += w; | |
} | |
} | |
yi = x; | |
stackpointer = radius; | |
for (y = 0; y < h; y++) { | |
// Preserve alpha channel: ( 0xff000000 & pix[yi] ) | |
pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum]; | |
rsum -= routsum; | |
gsum -= goutsum; | |
bsum -= boutsum; | |
stackstart = stackpointer - radius + div; | |
sir = stack[stackstart % div]; | |
routsum -= sir[0]; | |
goutsum -= sir[1]; | |
boutsum -= sir[2]; | |
if (x == 0) { | |
vmin[y] = Math.min(y + r1, hm) * w; | |
} | |
p = x + vmin[y]; | |
sir[0] = r[p]; | |
sir[1] = g[p]; | |
sir[2] = b[p]; | |
rinsum += sir[0]; | |
ginsum += sir[1]; | |
binsum += sir[2]; | |
rsum += rinsum; | |
gsum += ginsum; | |
bsum += binsum; | |
stackpointer = (stackpointer + 1) % div; | |
sir = stack[stackpointer]; | |
routsum += sir[0]; | |
goutsum += sir[1]; | |
boutsum += sir[2]; | |
rinsum -= sir[0]; | |
ginsum -= sir[1]; | |
binsum -= sir[2]; | |
yi += w; | |
} | |
} | |
ret.setPixels(pix, 0, w, 0, 0, w, h); | |
return ret; | |
} | |
/** | |
* 添加颜色边框 | |
* | |
* @param src 源图片 | |
* @param borderWidth 边框宽度 | |
* @param color 边框的颜色值 | |
* @return 带颜色边框图 | |
*/ | |
public static Bitmap addFrame(Bitmap src, int borderWidth, int color) { | |
return addFrame(src, borderWidth, color, false); | |
} | |
/** | |
* 添加颜色边框 | |
* | |
* @param src 源图片 | |
* @param borderWidth 边框宽度 | |
* @param color 边框的颜色值 | |
* @param recycle 是否回收 | |
* @return 带颜色边框图 | |
*/ | |
public static Bitmap addFrame(Bitmap src, int borderWidth, int color, boolean recycle) { | |
if (isEmptyBitmap(src)) return null; | |
int doubleBorder = borderWidth << 1; | |
int newWidth = src.getWidth() + doubleBorder; | |
int newHeight = src.getHeight() + doubleBorder; | |
Bitmap ret = Bitmap.createBitmap(newWidth, newHeight, src.getConfig()); | |
Canvas canvas = new Canvas(ret); | |
Rect rect = new Rect(0, 0, newWidth, newHeight); | |
Paint paint = new Paint(); | |
paint.setColor(color); | |
paint.setStyle(Paint.Style.STROKE); | |
// setStrokeWidth是居中画的,所以要两倍的宽度才能画,否则有一半的宽度是空的 | |
paint.setStrokeWidth(doubleBorder); | |
canvas.drawRect(rect, paint); | |
canvas.drawBitmap(src, borderWidth, borderWidth, null); | |
if (recycle && !src.isRecycled()) src.recycle(); | |
return ret; | |
} | |
/** | |
* 添加倒影 | |
* | |
* @param src 源图片的 | |
* @param reflectionHeight 倒影高度 | |
* @return 带倒影图片 | |
*/ | |
public static Bitmap addReflection(Bitmap src, int reflectionHeight) { | |
return addReflection(src, reflectionHeight, false); | |
} | |
/** | |
* 添加倒影 | |
* | |
* @param src 源图片的 | |
* @param reflectionHeight 倒影高度 | |
* @param recycle 是否回收 | |
* @return 带倒影图片 | |
*/ | |
public static Bitmap addReflection(Bitmap src, int reflectionHeight, boolean recycle) { | |
if (isEmptyBitmap(src)) return null; | |
// 原图与倒影之间的间距 | |
final int REFLECTION_GAP = 0; | |
int srcWidth = src.getWidth(); | |
int srcHeight = src.getHeight(); | |
Matrix matrix = new Matrix(); | |
matrix.preScale(1, -1); | |
Bitmap reflectionBitmap = Bitmap.createBitmap(src, 0, srcHeight - reflectionHeight, | |
srcWidth, reflectionHeight, matrix, false); | |
Bitmap ret = Bitmap.createBitmap(srcWidth, srcHeight + reflectionHeight, src.getConfig()); | |
Canvas canvas = new Canvas(ret); | |
canvas.drawBitmap(src, 0, 0, null); | |
canvas.drawBitmap(reflectionBitmap, 0, srcHeight + REFLECTION_GAP, null); | |
Paint paint = new Paint(); | |
paint.setAntiAlias(true); | |
LinearGradient shader = new LinearGradient(0, srcHeight, | |
0, ret.getHeight() + REFLECTION_GAP, | |
0x70FFFFFF, 0x00FFFFFF, Shader.TileMode.MIRROR); | |
paint.setShader(shader); | |
paint.setXfermode(new PorterDuffXfermode(android.graphics.PorterDuff.Mode.DST_IN)); | |
canvas.drawRect(0, srcHeight + REFLECTION_GAP, | |
srcWidth, ret.getHeight(), paint); | |
if (!reflectionBitmap.isRecycled()) reflectionBitmap.recycle(); | |
if (recycle && !src.isRecycled()) src.recycle(); | |
return ret; | |
} | |
/** | |
* 添加文字水印 | |
* | |
* @param src 源图片 | |
* @param content 水印文本 | |
* @param textSize 水印字体大小 | |
* @param color 水印字体颜色 | |
* @param x 起始坐标x | |
* @param y 起始坐标y | |
* @return 带有文字水印的图片 | |
*/ | |
public static Bitmap addTextWatermark(Bitmap src, String content, int textSize, int color, float x, | |
float y) { | |
return addTextWatermark(src, content, textSize, color, x, y, false); | |
} | |
/** | |
* 添加文字水印 | |
* | |
* @param src 源图片 | |
* @param content 水印文本 | |
* @param textSize 水印字体大小 | |
* @param color 水印字体颜色 | |
* @param x 起始坐标x | |
* @param y 起始坐标y | |
* @param recycle 是否回收 | |
* @return 带有文字水印的图片 | |
*/ | |
public static Bitmap addTextWatermark(Bitmap src, String content, float textSize, int color, float x, | |
float y, boolean recycle) { | |
if (isEmptyBitmap(src) || content == null) return null; | |
Bitmap ret = src.copy(src.getConfig(), true); | |
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); | |
Canvas canvas = new Canvas(ret); | |
paint.setColor(color); | |
paint.setTextSize(textSize); | |
Rect bounds = new Rect(); | |
paint.getTextBounds(content, 0, content.length(), bounds); | |
canvas.drawText(content, x, y + textSize, paint); | |
if (recycle && !src.isRecycled()) src.recycle(); | |
return ret; | |
} | |
/** | |
* 添加图片水印 | |
* | |
* @param src 源图片 | |
* @param watermark 图片水印 | |
* @param x 起始坐标x | |
* @param y 起始坐标y | |
* @param alpha 透明度 | |
* @return 带有图片水印的图片 | |
*/ | |
public static Bitmap addImageWatermark(Bitmap src, Bitmap watermark, int x, int y, int alpha) { | |
return addImageWatermark(src, watermark, x, y, alpha, false); | |
} | |
/** | |
* 添加图片水印 | |
* | |
* @param src 源图片 | |
* @param watermark 图片水印 | |
* @param x 起始坐标x | |
* @param y 起始坐标y | |
* @param alpha 透明度 | |
* @param recycle 是否回收 | |
* @return 带有图片水印的图片 | |
*/ | |
public static Bitmap addImageWatermark(Bitmap src, Bitmap watermark, int x, int y, int alpha, boolean recycle) { | |
if (isEmptyBitmap(src)) return null; | |
Bitmap ret = src.copy(src.getConfig(), true); | |
if (!isEmptyBitmap(watermark)) { | |
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); | |
Canvas canvas = new Canvas(ret); | |
paint.setAlpha(alpha); | |
canvas.drawBitmap(watermark, x, y, paint); | |
} | |
if (recycle && !src.isRecycled()) src.recycle(); | |
return ret; | |
} | |
/** | |
* 转为alpha位图 | |
* | |
* @param src 源图片 | |
* @return alpha位图 | |
*/ | |
public static Bitmap toAlpha(Bitmap src) { | |
return toAlpha(src, false); | |
} | |
/** | |
* 转为alpha位图 | |
* | |
* @param src 源图片 | |
* @param recycle 是否回收 | |
* @return alpha位图 | |
*/ | |
public static Bitmap toAlpha(Bitmap src, Boolean recycle) { | |
if (isEmptyBitmap(src)) return null; | |
Bitmap ret = src.extractAlpha(); | |
if (recycle && !src.isRecycled()) src.recycle(); | |
return ret; | |
} | |
/** | |
* 转为灰度图片 | |
* | |
* @param src 源图片 | |
* @return 灰度图 | |
*/ | |
public static Bitmap toGray(Bitmap src) { | |
return toGray(src, false); | |
} | |
/** | |
* 转为灰度图片 | |
* | |
* @param src 源图片 | |
* @param recycle 是否回收 | |
* @return 灰度图 | |
*/ | |
public static Bitmap toGray(Bitmap src, boolean recycle) { | |
if (isEmptyBitmap(src)) return null; | |
Bitmap grayBitmap = Bitmap.createBitmap(src.getWidth(), | |
src.getHeight(), Bitmap.Config.ARGB_8888); | |
Canvas canvas = new Canvas(grayBitmap); | |
Paint paint = new Paint(); | |
ColorMatrix colorMatrix = new ColorMatrix(); | |
colorMatrix.setSaturation(0); | |
ColorMatrixColorFilter colorMatrixColorFilter = new ColorMatrixColorFilter(colorMatrix); | |
paint.setColorFilter(colorMatrixColorFilter); | |
canvas.drawBitmap(src, 0, 0, paint); | |
if (recycle && !src.isRecycled()) src.recycle(); | |
return grayBitmap; | |
} | |
/** | |
* 保存图片 | |
* | |
* @param src 源图片 | |
* @param filePath 要保存到的文件路径 | |
* @param format 格式 | |
* @return {@code true}: 成功<br>{@code false}: 失败 | |
*/ | |
public static boolean save(Bitmap src, String filePath, CompressFormat format) { | |
return save(src, FileUtils.getFileByPath(filePath), format, false); | |
} | |
/** | |
* 保存图片 | |
* | |
* @param src 源图片 | |
* @param file 要保存到的文件 | |
* @param format 格式 | |
* @return {@code true}: 成功<br>{@code false}: 失败 | |
*/ | |
public static boolean save(Bitmap src, File file, CompressFormat format) { | |
return save(src, file, format, false); | |
} | |
/** | |
* 保存图片 | |
* | |
* @param src 源图片 | |
* @param filePath 要保存到的文件路径 | |
* @param format 格式 | |
* @param recycle 是否回收 | |
* @return {@code true}: 成功<br>{@code false}: 失败 | |
*/ | |
public static boolean save(Bitmap src, String filePath, CompressFormat format, boolean recycle) { | |
return save(src, FileUtils.getFileByPath(filePath), format, recycle); | |
} | |
/** | |
* 保存图片 | |
* | |
* @param src 源图片 | |
* @param file 要保存到的文件 | |
* @param format 格式 | |
* @param recycle 是否回收 | |
* @return {@code true}: 成功<br>{@code false}: 失败 | |
*/ | |
public static boolean save(Bitmap src, File file, CompressFormat format, boolean recycle) { | |
if (isEmptyBitmap(src) || !FileUtils.createOrExistsFile(file)) return false; | |
System.out.println(src.getWidth() + ", " + src.getHeight()); | |
OutputStream os = null; | |
boolean ret = false; | |
try { | |
os = new BufferedOutputStream(new FileOutputStream(file)); | |
ret = src.compress(format, 100, os); | |
if (recycle && !src.isRecycled()) src.recycle(); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} finally { | |
CloseUtils.closeIO(os); | |
} | |
return ret; | |
} | |
/** | |
* 根据文件名判断文件是否为图片 | |
* | |
* @param file 文件 | |
* @return {@code true}: 是<br>{@code false}: 否 | |
*/ | |
public static boolean isImage(File file) { | |
return file != null && isImage(file.getPath()); | |
} | |
/** | |
* 根据文件名判断文件是否为图片 | |
* | |
* @param filePath 文件路径 | |
* @return {@code true}: 是<br>{@code false}: 否 | |
*/ | |
public static boolean isImage(String filePath) { | |
String path = filePath.toUpperCase(); | |
return path.endsWith(".PNG") || path.endsWith(".JPG") | |
|| path.endsWith(".JPEG") || path.endsWith(".BMP") | |
|| path.endsWith(".GIF"); | |
} | |
/** | |
* 获取图片类型 | |
* | |
* @param filePath 文件路径 | |
* @return 图片类型 | |
*/ | |
public static String getImageType(String filePath) { | |
return getImageType(FileUtils.getFileByPath(filePath)); | |
} | |
/** | |
* 获取图片类型 | |
* | |
* @param file 文件 | |
* @return 图片类型 | |
*/ | |
public static String getImageType(File file) { | |
if (file == null) return null; | |
InputStream is = null; | |
try { | |
is = new FileInputStream(file); | |
return getImageType(is); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
return null; | |
} finally { | |
CloseUtils.closeIO(is); | |
} | |
} | |
/** | |
* 流获取图片类型 | |
* | |
* @param is 图片输入流 | |
* @return 图片类型 | |
*/ | |
public static String getImageType(InputStream is) { | |
if (is == null) return null; | |
try { | |
byte[] bytes = new byte[8]; | |
return is.read(bytes, 0, 8) != -1 ? getImageType(bytes) : null; | |
} catch (IOException e) { | |
e.printStackTrace(); | |
return null; | |
} | |
} | |
/** | |
* 获取图片类型 | |
* | |
* @param bytes bitmap的前8字节 | |
* @return 图片类型 | |
*/ | |
public static String getImageType(byte[] bytes) { | |
if (isJPEG(bytes)) return "JPEG"; | |
if (isGIF(bytes)) return "GIF"; | |
if (isPNG(bytes)) return "PNG"; | |
if (isBMP(bytes)) return "BMP"; | |
return null; | |
} | |
private static boolean isJPEG(byte[] b) { | |
return b.length >= 2 | |
&& (b[0] == (byte) 0xFF) && (b[1] == (byte) 0xD8); | |
} | |
private static boolean isGIF(byte[] b) { | |
return b.length >= 6 | |
&& b[0] == 'G' && b[1] == 'I' | |
&& b[2] == 'F' && b[3] == '8' | |
&& (b[4] == '7' || b[4] == '9') && b[5] == 'a'; | |
} | |
private static boolean isPNG(byte[] b) { | |
return b.length >= 8 | |
&& (b[0] == (byte) 137 && b[1] == (byte) 80 | |
&& b[2] == (byte) 78 && b[3] == (byte) 71 | |
&& b[4] == (byte) 13 && b[5] == (byte) 10 | |
&& b[6] == (byte) 26 && b[7] == (byte) 10); | |
} | |
private static boolean isBMP(byte[] b) { | |
return b.length >= 2 | |
&& (b[0] == 0x42) && (b[1] == 0x4d); | |
} | |
/** | |
* 判断bitmap对象是否为空 | |
* | |
* @param src 源图片 | |
* @return {@code true}: 是<br>{@code false}: 否 | |
*/ | |
private static boolean isEmptyBitmap(Bitmap src) { | |
return src == null || src.getWidth() == 0 || src.getHeight() == 0; | |
} | |
/******************************~~~~~~~~~ 下方和压缩有关 ~~~~~~~~~******************************/ | |
/** | |
* 按缩放压缩 | |
* | |
* @param src 源图片 | |
* @param newWidth 新宽度 | |
* @param newHeight 新高度 | |
* @return 缩放压缩后的图片 | |
*/ | |
public static Bitmap compressByScale(Bitmap src, int newWidth, int newHeight) { | |
return scale(src, newWidth, newHeight, false); | |
} | |
/** | |
* 按缩放压缩 | |
* | |
* @param src 源图片 | |
* @param newWidth 新宽度 | |
* @param newHeight 新高度 | |
* @param recycle 是否回收 | |
* @return 缩放压缩后的图片 | |
*/ | |
public static Bitmap compressByScale(Bitmap src, int newWidth, int newHeight, boolean recycle) { | |
return scale(src, newWidth, newHeight, recycle); | |
} | |
/** | |
* 按缩放压缩 | |
* | |
* @param src 源图片 | |
* @param scaleWidth 缩放宽度倍数 | |
* @param scaleHeight 缩放高度倍数 | |
* @return 缩放压缩后的图片 | |
*/ | |
public static Bitmap compressByScale(Bitmap src, float scaleWidth, float scaleHeight) { | |
return scale(src, scaleWidth, scaleHeight, false); | |
} | |
/** | |
* 按缩放压缩 | |
* | |
* @param src 源图片 | |
* @param scaleWidth 缩放宽度倍数 | |
* @param scaleHeight 缩放高度倍数 | |
* @param recycle 是否回收 | |
* @return 缩放压缩后的图片 | |
*/ | |
public static Bitmap compressByScale(Bitmap src, float scaleWidth, float scaleHeight, boolean recycle) { | |
return scale(src, scaleWidth, scaleHeight, recycle); | |
} | |
/** | |
* 按质量压缩 | |
* | |
* @param src 源图片 | |
* @param quality 质量 | |
* @return 质量压缩后的图片 | |
*/ | |
public static Bitmap compressByQuality(Bitmap src, @IntRange(from = 0, to = 100) int quality) { | |
return compressByQuality(src, quality, false); | |
} | |
/** | |
* 按质量压缩 | |
* | |
* @param src 源图片 | |
* @param quality 质量 | |
* @param recycle 是否回收 | |
* @return 质量压缩后的图片 | |
*/ | |
public static Bitmap compressByQuality(Bitmap src, @IntRange(from = 0, to = 100) int quality, boolean recycle) { | |
if (isEmptyBitmap(src)) return null; | |
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |
src.compress(Bitmap.CompressFormat.JPEG, quality, baos); | |
byte[] bytes = baos.toByteArray(); | |
if (recycle && !src.isRecycled()) src.recycle(); | |
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length); | |
} | |
/** | |
* 按质量压缩 | |
* | |
* @param src 源图片 | |
* @param maxByteSize 允许最大值字节数 | |
* @return 质量压缩压缩过的图片 | |
*/ | |
public static Bitmap compressByQuality(Bitmap src, long maxByteSize) { | |
return compressByQuality(src, maxByteSize, false); | |
} | |
/** | |
* 按质量压缩 | |
* | |
* @param src 源图片 | |
* @param maxByteSize 允许最大值字节数 | |
* @param recycle 是否回收 | |
* @return 质量压缩压缩过的图片 | |
*/ | |
public static Bitmap compressByQuality(Bitmap src, long maxByteSize, boolean recycle) { | |
if (isEmptyBitmap(src) || maxByteSize <= 0) return null; | |
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |
int quality = 100; | |
src.compress(CompressFormat.JPEG, quality, baos); | |
while (baos.toByteArray().length > maxByteSize && quality > 0) { | |
baos.reset(); | |
src.compress(CompressFormat.JPEG, quality -= 5, baos); | |
} | |
if (quality < 0) return null; | |
byte[] bytes = baos.toByteArray(); | |
if (recycle && !src.isRecycled()) src.recycle(); | |
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length); | |
} | |
/** | |
* 按采样大小压缩 | |
* | |
* @param src 源图片 | |
* @param sampleSize 采样率大小 | |
* @return 按采样率压缩后的图片 | |
*/ | |
public static Bitmap compressBySampleSize(Bitmap src, int sampleSize) { | |
return compressBySampleSize(src, sampleSize, false); | |
} | |
/** | |
* 按采样大小压缩 | |
* | |
* @param src 源图片 | |
* @param sampleSize 采样率大小 | |
* @param recycle 是否回收 | |
* @return 按采样率压缩后的图片 | |
*/ | |
public static Bitmap compressBySampleSize(Bitmap src, int sampleSize, boolean recycle) { | |
if (isEmptyBitmap(src)) return null; | |
BitmapFactory.Options options = new BitmapFactory.Options(); | |
options.inSampleSize = sampleSize; | |
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |
src.compress(Bitmap.CompressFormat.JPEG, 100, baos); | |
byte[] bytes = baos.toByteArray(); | |
if (recycle && !src.isRecycled()) src.recycle(); | |
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options); | |
} | |
private static boolean isSpace(String s) { | |
if (s == null) return true; | |
for (int i = 0, len = s.length(); i < len; ++i) { | |
if (!Character.isWhitespace(s.charAt(i))) { | |
return false; | |
} | |
} | |
return true; | |
} | |
} |
图片相关→ImageUtils
最新推荐文章于 2022-06-22 19:54:03 发布