|
@@ -0,0 +1,483 @@
|
|
|
+
|
|
|
+package com.tjzhxx.union.public_store;
|
|
|
+
|
|
|
+import android.content.ContentValues;
|
|
|
+import android.content.Context;
|
|
|
+import android.database.Cursor;
|
|
|
+import android.graphics.Bitmap;
|
|
|
+import android.graphics.Bitmap.Config;
|
|
|
+import android.graphics.BitmapFactory;
|
|
|
+import android.graphics.Canvas;
|
|
|
+import android.graphics.Paint;
|
|
|
+import android.graphics.PorterDuff.Mode;
|
|
|
+import android.graphics.PorterDuffXfermode;
|
|
|
+import android.graphics.Rect;
|
|
|
+import android.graphics.RectF;
|
|
|
+import android.graphics.drawable.BitmapDrawable;
|
|
|
+import android.graphics.drawable.Drawable;
|
|
|
+import android.media.ThumbnailUtils;
|
|
|
+import android.net.Uri;
|
|
|
+import android.os.ParcelFileDescriptor;
|
|
|
+import android.provider.MediaStore;
|
|
|
+
|
|
|
+import java.io.BufferedOutputStream;
|
|
|
+import java.io.ByteArrayOutputStream;
|
|
|
+import java.io.File;
|
|
|
+import java.io.FileDescriptor;
|
|
|
+import java.io.FileNotFoundException;
|
|
|
+import java.io.FileOutputStream;
|
|
|
+import java.io.IOException;
|
|
|
+
|
|
|
+public class ImageUtils {
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 转换图片成圆形
|
|
|
+ *
|
|
|
+ * @param bitmap 传入Bitmap对象
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static Bitmap toRoundBitmap(Bitmap bitmap) {
|
|
|
+ int width = bitmap.getWidth();
|
|
|
+ int height = bitmap.getHeight();
|
|
|
+ float roundPx;
|
|
|
+ float left, top, right, bottom, dst_left, dst_top, dst_right, dst_bottom;
|
|
|
+ if (width <= height) {
|
|
|
+ roundPx = width / 2;
|
|
|
+ top = 0;
|
|
|
+ bottom = width;
|
|
|
+ left = 0;
|
|
|
+ right = width;
|
|
|
+ height = width;
|
|
|
+ dst_left = 0;
|
|
|
+ dst_top = 0;
|
|
|
+ dst_right = width;
|
|
|
+ dst_bottom = width;
|
|
|
+ } else {
|
|
|
+ roundPx = height / 2;
|
|
|
+ float clip = (width - height) / 2;
|
|
|
+ left = clip;
|
|
|
+ right = width - clip;
|
|
|
+ top = 0;
|
|
|
+ bottom = height;
|
|
|
+ width = height;
|
|
|
+ dst_left = 0;
|
|
|
+ dst_top = 0;
|
|
|
+ dst_right = height;
|
|
|
+ dst_bottom = height;
|
|
|
+ }
|
|
|
+ Bitmap output = Bitmap.createBitmap(width, height, Config.ARGB_8888);
|
|
|
+ Canvas canvas = new Canvas(output);
|
|
|
+ if (output.isRecycled()) {
|
|
|
+ output.recycle();
|
|
|
+ }
|
|
|
+ final int color = 0xff424242;
|
|
|
+ final Paint paint = new Paint();
|
|
|
+ final Rect src = new Rect((int) left, (int) top, (int) right, (int) bottom);
|
|
|
+ final Rect dst = new Rect((int) dst_left, (int) dst_top, (int) dst_right, (int) dst_bottom);
|
|
|
+ final RectF rectF = new RectF(dst);
|
|
|
+
|
|
|
+ paint.setAntiAlias(true);
|
|
|
+
|
|
|
+ canvas.drawARGB(0, 0, 0, 0);
|
|
|
+ paint.setColor(color);
|
|
|
+ canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
|
|
|
+
|
|
|
+ paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
|
|
|
+ canvas.drawBitmap(bitmap, src, dst, paint);
|
|
|
+ if (bitmap.isRecycled()) {
|
|
|
+ bitmap.recycle();
|
|
|
+ }
|
|
|
+ return output;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * uri转bitmap类型并旋转为正常图片
|
|
|
+ *
|
|
|
+ * @param context context
|
|
|
+ * @param uri uri
|
|
|
+ * @return 返回旋转后为正常图片的bitmap类型
|
|
|
+ */
|
|
|
+ private static Bitmap uriToBitmap(Context context, Uri uri, BitmapFactory.Options options) {
|
|
|
+ ParcelFileDescriptor parcelFileDescriptor = null;
|
|
|
+ FileDescriptor fileDescriptor = null;
|
|
|
+// ExifInterface exifInterface = null;
|
|
|
+ Bitmap tagBitmap = null;
|
|
|
+ try {
|
|
|
+ parcelFileDescriptor = context.getContentResolver().openFileDescriptor(uri, "r");
|
|
|
+ if (parcelFileDescriptor != null && parcelFileDescriptor.getFileDescriptor() != null) {
|
|
|
+
|
|
|
+ fileDescriptor = parcelFileDescriptor.getFileDescriptor();
|
|
|
+ //1.转换uri为bitmap类型
|
|
|
+ tagBitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
|
|
|
+ parcelFileDescriptor.close();
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ } finally {
|
|
|
+ try {
|
|
|
+ if (parcelFileDescriptor != null) {
|
|
|
+ parcelFileDescriptor.close();
|
|
|
+ }
|
|
|
+ } catch (IOException e) {
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return tagBitmap;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 质量压缩
|
|
|
+ *
|
|
|
+ * @param bmp
|
|
|
+ * @param file
|
|
|
+ */
|
|
|
+ public static void compressBmpToFile(Bitmap bmp, File file, String outPath, int maxSize) {
|
|
|
+ if (bmp == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ //设置压缩后图片不超过3M
|
|
|
+ int maxKB = maxSize;
|
|
|
+ //创建一个缓存区
|
|
|
+ ByteArrayOutputStream mByteArrayOutputStream = new ByteArrayOutputStream();
|
|
|
+ //默认压缩质量(不压缩)
|
|
|
+ int options = 100;
|
|
|
+ //压缩后的大小
|
|
|
+ long endKB = file.length();
|
|
|
+ do {
|
|
|
+ //清空缓存区
|
|
|
+ mByteArrayOutputStream.reset();
|
|
|
+ //将数据写入缓存区
|
|
|
+ bmp.compress(Bitmap.CompressFormat.JPEG, options, mByteArrayOutputStream);
|
|
|
+ //降低质量
|
|
|
+ options -= 10;
|
|
|
+ //重新计算缓存区数据大小
|
|
|
+ endKB = mByteArrayOutputStream.toByteArray().length;
|
|
|
+ //如果压缩系数小于0的时候直接跳出循环
|
|
|
+ if (options <= 0) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } while (endKB / 1024 > maxKB);
|
|
|
+ //创建一个输入流
|
|
|
+ FileOutputStream mFileOutputStream = null;
|
|
|
+ BufferedOutputStream mBufferedOutputStream = null;
|
|
|
+ //创建一个空文件
|
|
|
+ try {
|
|
|
+ File outFile = new File(outPath);
|
|
|
+ if (!outFile.exists()) {
|
|
|
+ // 先得到文件的上级目录,并创建上级目录,在创建文件
|
|
|
+ outFile.getParentFile().mkdir();
|
|
|
+ outFile.createNewFile();
|
|
|
+
|
|
|
+ }
|
|
|
+ mFileOutputStream = new FileOutputStream(outFile);
|
|
|
+ mBufferedOutputStream = new BufferedOutputStream(mFileOutputStream);
|
|
|
+ //将压缩后的数据写入都空文件中
|
|
|
+ mBufferedOutputStream.write(mByteArrayOutputStream.toByteArray());
|
|
|
+ } catch (FileNotFoundException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ } catch (IOException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ } finally {
|
|
|
+ try {
|
|
|
+ if (mByteArrayOutputStream != null && mBufferedOutputStream != null && mFileOutputStream != null) {
|
|
|
+ //关闭流
|
|
|
+ mByteArrayOutputStream.flush();
|
|
|
+ mBufferedOutputStream.flush();
|
|
|
+ mFileOutputStream.close();
|
|
|
+ mBufferedOutputStream.close();
|
|
|
+ mByteArrayOutputStream.close();
|
|
|
+ }
|
|
|
+ } catch (IOException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static BitMapWH getBitMapWH(File srcPath) {
|
|
|
+ BitmapFactory.Options newOpts = new BitmapFactory.Options();
|
|
|
+ // 开始读入图片,此时把options.inJustDecodeBounds 设回true了
|
|
|
+ newOpts.inJustDecodeBounds = true;
|
|
|
+ Bitmap bitmap = BitmapFactory.decodeFile(srcPath.getAbsolutePath(), newOpts);// 此时返回bm为空
|
|
|
+ int w = newOpts.outWidth;
|
|
|
+ int h = newOpts.outHeight;
|
|
|
+ return new BitMapWH(w, h);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static class BitMapWH {
|
|
|
+ private int w;
|
|
|
+ private int h;
|
|
|
+
|
|
|
+ public BitMapWH(int w, int h) {
|
|
|
+ this.w = w;
|
|
|
+ this.h = h;
|
|
|
+ }
|
|
|
+
|
|
|
+ public int getW() {
|
|
|
+ return w;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setW(int w) {
|
|
|
+ this.w = w;
|
|
|
+ }
|
|
|
+
|
|
|
+ public int getH() {
|
|
|
+ return h;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setH(int h) {
|
|
|
+ this.h = h;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据path压缩
|
|
|
+ *
|
|
|
+ * @param file
|
|
|
+ */
|
|
|
+ public static void compressBmp(File file, String outPath, int maxSize) {
|
|
|
+ if (!file.exists()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ BitmapFactory.Options newOpts = new BitmapFactory.Options();
|
|
|
+ // 开始读入图片,此时把options.inJustDecodeBounds 设回true了
|
|
|
+ newOpts.inJustDecodeBounds = true;
|
|
|
+ BitmapFactory.decodeFile(file.getAbsolutePath(), newOpts);
|
|
|
+ coundScale(newOpts);
|
|
|
+ newOpts.inJustDecodeBounds = false;
|
|
|
+ Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath(), newOpts);
|
|
|
+ compressBmpToFile(bitmap, file, outPath, maxSize);// 压缩好比例大小后再进行质量压缩
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据path压缩
|
|
|
+ *
|
|
|
+ * @param file
|
|
|
+ */
|
|
|
+
|
|
|
+ public static void compressBmp(Context context, File file, String outPath, int maxSize) {
|
|
|
+ if (!file.exists()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ BitmapFactory.Options newOpts = new BitmapFactory.Options();
|
|
|
+ // 开始读入图片,此时把options.inJustDecodeBounds 设回true了
|
|
|
+ newOpts.inJustDecodeBounds = true;
|
|
|
+ BitmapFactory.decodeFile(file.getAbsolutePath(), newOpts);
|
|
|
+ coundScale(newOpts);
|
|
|
+ newOpts.inJustDecodeBounds = false;
|
|
|
+ //google需要,因为google没有加 android:requestLegacyExternalStorage = "true",所以 BitmapFactory.decodeFile会返回为null
|
|
|
+ Bitmap bitmap = uriToBitmap(context, getImageContentUri(context, file.getAbsolutePath()), newOpts);
|
|
|
+// Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath(), newOpts);
|
|
|
+ compressBmpToFile(bitmap, file, outPath, maxSize);// 压缩好比例大小后再进行质量压缩
|
|
|
+ if (bitmap != null) {
|
|
|
+ bitmap.recycle();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static Uri getImageContentUri(Context context, String path) {
|
|
|
+ Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
|
|
+ new String[]{MediaStore.Images.Media._ID}, MediaStore.Images.Media.DATA + "=? ",
|
|
|
+ new String[]{path}, null);
|
|
|
+ if (cursor != null && cursor.moveToFirst()) {
|
|
|
+ int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
|
|
|
+ Uri baseUri = Uri.parse("content://media/external/images/media");
|
|
|
+ cursor.close();
|
|
|
+ return Uri.withAppendedPath(baseUri, "" + id);
|
|
|
+ } else {
|
|
|
+ // 如果图片不在手机的共享图片数据库,就先把它插入。
|
|
|
+ if (new File(path).exists()) {
|
|
|
+ ContentValues values = new ContentValues();
|
|
|
+ values.put(MediaStore.Images.Media.DATA, path);
|
|
|
+ return context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
|
|
|
+ } else {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算缩放比例,防止OOM
|
|
|
+ *
|
|
|
+ * @param options BitmapFactory.Options
|
|
|
+ */
|
|
|
+ private static void coundScale(BitmapFactory.Options options) {
|
|
|
+ if (options != null) {
|
|
|
+ //原图的尺寸
|
|
|
+ int orginalWidht = options.outWidth;
|
|
|
+ int orginalHieght = options.outHeight;
|
|
|
+ //如果图片尺寸大于一定尺寸的时候进行缩放
|
|
|
+ if (orginalWidht > 1080 || orginalHieght > 1920) {
|
|
|
+ //缩小倍数
|
|
|
+ int scale = 1;
|
|
|
+
|
|
|
+ if (orginalWidht > orginalHieght) {
|
|
|
+ //长图片的时候(以宽度为基准缩小)
|
|
|
+ scale = orginalWidht / 1080;
|
|
|
+ } else if (orginalWidht < orginalHieght) {
|
|
|
+ //高图的时候(以高度为基准缩小)
|
|
|
+ scale = orginalHieght / 1920;
|
|
|
+ } else {
|
|
|
+ //正方形图的时候(以宽度为基准缩小)
|
|
|
+ scale = orginalWidht / 1080;
|
|
|
+ }
|
|
|
+ options.inSampleSize = scale;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 水平方向模糊度
|
|
|
+ */
|
|
|
+ private static float hRadius = 10;
|
|
|
+ /**
|
|
|
+ * 竖直方向模糊度
|
|
|
+ */
|
|
|
+ private static float vRadius = 10;
|
|
|
+ /**
|
|
|
+ * 模糊迭代度
|
|
|
+ */
|
|
|
+ private static int iterations = 7;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 高斯模糊
|
|
|
+ */
|
|
|
+ public static Drawable BoxBlurFilter(Bitmap bmp) {
|
|
|
+ int width = bmp.getWidth();
|
|
|
+ int height = bmp.getHeight();
|
|
|
+ int[] inPixels = new int[width * height];
|
|
|
+ int[] outPixels = new int[width * height];
|
|
|
+ Bitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
|
|
|
+ bmp.getPixels(inPixels, 0, width, 0, 0, width, height);
|
|
|
+ for (int i = 0; i < iterations; i++) {
|
|
|
+ blur(inPixels, outPixels, width, height, hRadius);
|
|
|
+ blur(outPixels, inPixels, height, width, vRadius);
|
|
|
+ }
|
|
|
+ blurFractional(inPixels, outPixels, width, height, hRadius);
|
|
|
+ blurFractional(outPixels, inPixels, height, width, vRadius);
|
|
|
+ bitmap.setPixels(inPixels, 0, width, 0, 0, width, height);
|
|
|
+ Drawable drawable = new BitmapDrawable(bitmap);
|
|
|
+ return drawable;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void blur(int[] in, int[] out, int width, int height, float radius) {
|
|
|
+ int widthMinus1 = width - 1;
|
|
|
+ int r = (int) radius;
|
|
|
+ int tableSize = 2 * r + 1;
|
|
|
+ int divide[] = new int[256 * tableSize];
|
|
|
+
|
|
|
+ for (int i = 0; i < 256 * tableSize; i++)
|
|
|
+ divide[i] = i / tableSize;
|
|
|
+
|
|
|
+ int inIndex = 0;
|
|
|
+
|
|
|
+ for (int y = 0; y < height; y++) {
|
|
|
+ int outIndex = y;
|
|
|
+ int ta = 0, tr = 0, tg = 0, tb = 0;
|
|
|
+
|
|
|
+ for (int i = -r; i <= r; i++) {
|
|
|
+ int rgb = in[inIndex + clamp(i, 0, width - 1)];
|
|
|
+ ta += (rgb >> 24) & 0xff;
|
|
|
+ tr += (rgb >> 16) & 0xff;
|
|
|
+ tg += (rgb >> 8) & 0xff;
|
|
|
+ tb += rgb & 0xff;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (int x = 0; x < width; x++) {
|
|
|
+ out[outIndex] = (divide[ta] << 24) | (divide[tr] << 16) | (divide[tg] << 8) | divide[tb];
|
|
|
+
|
|
|
+ int i1 = x + r + 1;
|
|
|
+ if (i1 > widthMinus1)
|
|
|
+ i1 = widthMinus1;
|
|
|
+ int i2 = x - r;
|
|
|
+ if (i2 < 0)
|
|
|
+ i2 = 0;
|
|
|
+ int rgb1 = in[inIndex + i1];
|
|
|
+ int rgb2 = in[inIndex + i2];
|
|
|
+
|
|
|
+ ta += ((rgb1 >> 24) & 0xff) - ((rgb2 >> 24) & 0xff);
|
|
|
+ tr += ((rgb1 & 0xff0000) - (rgb2 & 0xff0000)) >> 16;
|
|
|
+ tg += ((rgb1 & 0xff00) - (rgb2 & 0xff00)) >> 8;
|
|
|
+ tb += (rgb1 & 0xff) - (rgb2 & 0xff);
|
|
|
+ outIndex += height;
|
|
|
+ }
|
|
|
+ inIndex += width;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void blurFractional(int[] in, int[] out, int width, int height, float radius) {
|
|
|
+ radius -= (int) radius;
|
|
|
+ float f = 1.0f / (1 + 2 * radius);
|
|
|
+ int inIndex = 0;
|
|
|
+
|
|
|
+ for (int y = 0; y < height; y++) {
|
|
|
+ int outIndex = y;
|
|
|
+
|
|
|
+ out[outIndex] = in[0];
|
|
|
+ outIndex += height;
|
|
|
+ for (int x = 1; x < width - 1; x++) {
|
|
|
+ int i = inIndex + x;
|
|
|
+ int rgb1 = in[i - 1];
|
|
|
+ int rgb2 = in[i];
|
|
|
+ int rgb3 = in[i + 1];
|
|
|
+
|
|
|
+ int a1 = (rgb1 >> 24) & 0xff;
|
|
|
+ int r1 = (rgb1 >> 16) & 0xff;
|
|
|
+ int g1 = (rgb1 >> 8) & 0xff;
|
|
|
+ int b1 = rgb1 & 0xff;
|
|
|
+ int a2 = (rgb2 >> 24) & 0xff;
|
|
|
+ int r2 = (rgb2 >> 16) & 0xff;
|
|
|
+ int g2 = (rgb2 >> 8) & 0xff;
|
|
|
+ int b2 = rgb2 & 0xff;
|
|
|
+ int a3 = (rgb3 >> 24) & 0xff;
|
|
|
+ int r3 = (rgb3 >> 16) & 0xff;
|
|
|
+ int g3 = (rgb3 >> 8) & 0xff;
|
|
|
+ int b3 = rgb3 & 0xff;
|
|
|
+ a1 = a2 + (int) ((a1 + a3) * radius);
|
|
|
+ r1 = r2 + (int) ((r1 + r3) * radius);
|
|
|
+ g1 = g2 + (int) ((g1 + g3) * radius);
|
|
|
+ b1 = b2 + (int) ((b1 + b3) * radius);
|
|
|
+ a1 *= f;
|
|
|
+ r1 *= f;
|
|
|
+ g1 *= f;
|
|
|
+ b1 *= f;
|
|
|
+ out[outIndex] = (a1 << 24) | (r1 << 16) | (g1 << 8) | b1;
|
|
|
+ outIndex += height;
|
|
|
+ }
|
|
|
+ out[outIndex] = in[width - 1];
|
|
|
+ inIndex += width;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private Bitmap getImageThumbnail(String imagePath, int width, int height) {
|
|
|
+ Bitmap bitmap = null;
|
|
|
+ BitmapFactory.Options options = new BitmapFactory.Options();
|
|
|
+ options.inJustDecodeBounds = true;
|
|
|
+ // 获取这个图片的宽和高,注意此处的bitmap为null
|
|
|
+ BitmapFactory.decodeFile(imagePath, options);
|
|
|
+ options.inJustDecodeBounds = false; // 设为 false
|
|
|
+ // 计算缩放比
|
|
|
+ int h = options.outHeight;
|
|
|
+ int w = options.outWidth;
|
|
|
+ int beWidth = w / width;
|
|
|
+ int beHeight = h / height;
|
|
|
+ int be = 1;
|
|
|
+ if (beWidth < beHeight) {
|
|
|
+ be = beWidth;
|
|
|
+ } else {
|
|
|
+ be = beHeight;
|
|
|
+ }
|
|
|
+ if (be <= 0) {
|
|
|
+ be = 1;
|
|
|
+ }
|
|
|
+ options.inSampleSize = be;
|
|
|
+ // 重新读入图片,读取缩放后的bitmap,注意这次要把options.inJustDecodeBounds 设为 false
|
|
|
+ bitmap = BitmapFactory.decodeFile(imagePath, options);
|
|
|
+ // 利用ThumbnailUtils来创建缩略图,这里要指定要缩放哪个Bitmap对象
|
|
|
+ bitmap = ThumbnailUtils.extractThumbnail(bitmap, width, height,
|
|
|
+ ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
|
|
|
+ return bitmap;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static int clamp(int x, int a, int b) {
|
|
|
+ return (x < a) ? a : (x > b) ? b : x;
|
|
|
+ }
|
|
|
+}
|