Android处理Bitmap的一些方法

简介:

# 文件与Bitmap间的方法


1. 从文件载入Bitmap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
  * @brief 从文件载入Bitmap
  * @param path 图片路径
  * @param opts 选项
  * @return Bitmap
  */
public  Bitmap loadFromFile(String path, Options opts) {
     try  {
         File f =  new  File(path);
         if  (!f.exists() || f.isDirectory()) {
             return  null ;
         }
         Bitmap bm = BitmapFactory.decodeFile(path, opts);
         return  bm;
     catch  (Exception e) {
         return  null ;
     }
}
/**
  * @brief 从文件载入Bitmap
  * @param path 图片路径
  * @return Bitmap
  */
public  Bitmap loadFromFile(String path) {
     return  loadFromFile(path,  null );
}


2. 载入取样的Bitmap


原宽度和高度的各1/sampleSize大小。


显示图片文件时一般都是取样图,否则很容易outofmemory。


1
2
3
4
5
6
7
8
9
/**
  * @brief 从文件载入采样后的Bitmap
  * @see android.graphics.BitmapFactory.Options#inSampleSize
  */
public  Bitmap loadSampleSize(String path,  int  sampleSize) {
     Options opts =  new  Options();
     opts.inSampleSize = sampleSize;
     return  loadFromFile(path, opts);
}


3. 载入Bitmap边框


其返回Bitmap为null,但Options.outxxx会被填充值。包括outHeight, outWidth, outMimeType。


只读取其高宽信息的话,就不需要读取全部Bitmap了。可结合上个方法,获取倍数缩小的样图。


1
2
3
4
5
6
7
8
9
10
/**
  * @brief 从文件载入只获边框的Bitmap
  * @see android.graphics.BitmapFactory.Options#inJustDecodeBounds
  */
public  Options loadJustDecodeBounds(String path) {
     Options opts =  new  Options();
     opts.inJustDecodeBounds =  true ;
     loadFromFile(path, opts);
     return  opts;
}


4. 保存Bitmap至文件


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
  * @brief 保存Bitmap至文件
  * @param bm Bitmap
  * @param path 图片路径
  * @return 成功与否
  */
public  boolean  compressBitmap(Bitmap bm, String path) {
     FileOutputStream out =  null ;
     try  {
         out =  new  FileOutputStream(path);
         bm.compress(Bitmap.CompressFormat.JPEG,  100 , out);
         out.flush();
     catch  (Exception e) {
         return  false ;
     finally  {
         try  {
             if  (out !=  null ) {
                 out.close();
             }
         catch  (IOException e) {
         }
     }
     return  true ;
}


5. 读取图片方向信息


Bitmap图片的方法==!!!


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
  * @brief 读取图片方向信息
  * @param path 图片路径
  * @return 角度
  */
public  int  readPhotoDegree(String path) {
     int  degree =  0 ;
     try  {
         ExifInterface exifInterface =  new  ExifInterface(path);
         int  orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                 ExifInterface.ORIENTATION_NORMAL);
         switch  (orientation) {
         case  ExifInterface.ORIENTATION_ROTATE_90:
             degree =  90 ;
             break ;
         case  ExifInterface.ORIENTATION_ROTATE_180:
             degree =  180 ;
             break ;
         case  ExifInterface.ORIENTATION_ROTATE_270:
             degree =  270 ;
             break ;
         default :
             degree =  0 ;
         }
     catch  (IOException e) {
         e.printStackTrace();
     }
     return  degree;
}


# 处理Bitmap的方法


1. 生成缩略图


1
2
3
4
public  Bitmap extractThumbnail(Bitmap src,  int  width,  int  height) {
     return  ThumbnailUtils.extractThumbnail(src, width, height,
             ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
}


2. 缩放


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
  * @brief 缩放Bitmap,自动回收原Bitmap
  * @see ImageUtil#scaleBitmap(Bitmap, int, int, boolean)
  */
public  Bitmap scaleBitmap(Bitmap src,  int  dstWidth,  int  dstHeight) {
     return  scaleBitmap(src, dstWidth, dstHeight,  true );
}
/**
  * @brief 缩放Bitmap
  * @param src 源Bitmap
  * @param dstWidth 目标宽度
  * @param dstHeight 目标高度
  * @param isRecycle 是否回收原图像
  * @return Bitmap
  */
public  Bitmap scaleBitmap(Bitmap src,  int  dstWidth,  int  dstHeight,  boolean  isRecycle) {
     if  (src.getWidth() == dstWidth && src.getHeight() == dstHeight) {
         return  src;
     }
     Bitmap dst = Bitmap.createScaledBitmap(src, dstWidth, dstHeight,  false );
     if  (isRecycle && dst != src) {
         src.recycle();
     }
     return  dst;
}


3. 裁剪


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
  * @brief 裁剪Bitmap,自动回收原Bitmap
  * @see ImageUtil#cropBitmap(Bitmap, int, int, int, int, boolean)
  */
public  Bitmap cropBitmap(Bitmap src,  int  x,  int  y,  int  width,  int  height) {
     return  cropBitmap(src, x, y, width, height,  true );
}
/**
  * @brief 裁剪Bitmap
  * @param src 源Bitmap
  * @param x 开始x坐标
  * @param y 开始y坐标
  * @param width 截取宽度
  * @param height 截取高度
  * @param isRecycle 是否回收原图像
  * @return Bitmap
  */
public  Bitmap cropBitmap(Bitmap src,  int  x,  int  y,  int  width,  int  height,  boolean  isRecycle) {
     if  (x ==  0  && y ==  0  && width == src.getWidth() && height == src.getHeight()) {
         return  src;
     }
     Bitmap dst = Bitmap.createBitmap(src, x, y, width, height);
     if  (isRecycle && dst != src) {
         src.recycle();
     }
     return  dst;
}


4. 旋转


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
  * @brief 旋转Bitmap,自动回收原Bitmap
  * @see ImageUtil#rotateBitmap(Bitmap, int, boolean)
  */
public  Bitmap rotateBitmap(Bitmap src,  int  degree) {
     return  rotateBitmap(src, degree,  true );
}
/**
  * @brief 旋转Bitmap,顺时针
  * @param src 源Bitmap
  * @param degree 旋转角度
  * @param isRecycle 是否回收原图像
  * @return Bitmap
  */
public  Bitmap rotateBitmap(Bitmap src,  int  degree,  boolean  isRecycle) {
     if  (degree %  360  ==  0 ) {
         return  src;
     }
     int  w = src.getWidth();
     int  h = src.getHeight();
     Matrix matrix =  new  Matrix();
     matrix.postRotate(degree);
     Bitmap dst = Bitmap.createBitmap(src,  0 0 , w, h, matrix,  true );
     if  (isRecycle && dst != src) {
         src.recycle();
     }
     return  dst;
}


# OpenCV处理Bitmap的方法


除了导入OpenCV的jar包,我们只需要libopencv_java.so,就可以下做进行操作了。


1. 常规性的init


1
2
3
4
5
static  {
     if  (!OpenCVLoader.initDebug()) {
         Log.e(TAG,  "OpenCVLoader initDebug failed." );
     }
}


2. 常规性处理流程


bmp -> mat -> 接口处理 -> mat_new -> bmp_new。


1
2
3
4
5
6
7
8
9
10
11
12
13
private  interface  IHandler {
     Mat proc(Mat mat_bmp);
}
private  Bitmap handle(Bitmap src, IHandler handler) {
     Mat mat_bmp =  new  Mat(src.getHeight(), src.getWidth(), CvType.CV_8UC4);
     Utils.bitmapToMat(src, mat_bmp,  false );  // Bitmap->Mat
     Mat mat_new = handler.proc(mat_bmp);  // handle mat
     Bitmap bmp_new = Bitmap.createBitmap(mat_new.cols(), mat_new.rows(),
             Bitmap.Config.ARGB_8888);
     Utils.matToBitmap(mat_new, bmp_new,  false );  // Mat->Bitmap
     src.recycle();
     return  bmp_new;
}


3. 缩放


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
  * @brief 缩放Bitmap
  * @param src 源Bitmap
  * @param dstWidth 目标宽度
  * @param dstHeight 目标高度
  * @return Bitmap
  */
public  Bitmap scaleBitmap2(Bitmap src,  final  int  dstWidth,  final  int  dstHeight) {
     if  (src.getWidth() == dstWidth && src.getHeight() == dstHeight) {
         return  src;
     }
     return  handle(src,  new  IHandler() {
         @Override
         public  Mat proc(Mat mat_bmp) {
             Mat mat_new =  new  Mat();
             Imgproc.resize(mat_bmp, mat_new,  new  Size(dstWidth, dstHeight));
             return  mat_new;
         }
     });
}


4. 裁剪


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
  * @brief 裁剪Bitmap
  * @param src 源Bitmap
  * @param x 开始x坐标
  * @param y 开始y坐标
  * @param width 截取宽度
  * @param height 截取高度
  * @return Bitmap
  */
public  Bitmap cropBitmap2(Bitmap src,  final  int  x,  final  int  y,  final  int  width,
         final  int  height) {
     if  (x ==  0  && y ==  0  && width == src.getWidth() && height == src.getHeight()) {
         return  src;
     }
     if  (x + width > src.getWidth()) {
         throw  new  IllegalArgumentException( "x + width must be <= bitmap.width()" );
     }
     if  (y + height > src.getHeight()) {
         throw  new  IllegalArgumentException( "y + height must be <= bitmap.height()" );
     }
     return  handle(src,  new  IHandler() {
         @Override
         public  Mat proc(Mat mat_bmp) {
             Rect roi =  new  Rect(x, y, width, height);
             Mat mat_new =  new  Mat(mat_bmp, roi);
             return  mat_new;
         }
     });
}


5. 旋转


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/**
  * @brief 旋转Bitmap,逆时针
  * @param src 源Bitmap
  * @param degree 旋转角度
  * @return Bitmap
  * @see <a href="http://stackoverflow.com/questions/12852578/image-rotation-with-opencv-in-android-cuts-off-the-edges-of-an-image">More</a>
  */
public  Bitmap rotateBitmap2(Bitmap src,  final  int  degree) {
     if  (degree %  360  ==  0 ) {
         return  src;
     }
     return  handle(src,  new  IHandler() {
         @Override
         public  Mat proc(Mat mat_bmp) {
             // 计算旋转后图像的宽高
             double  radians = Math.toRadians(degree);
             double  sin = Math.abs(Math.sin(radians));
             double  cos = Math.abs(Math.cos(radians));
             int  width = mat_bmp.width();
             int  height = mat_bmp.height();
             int  newWidth = ( int ) (width * cos + height * sin);
             int  newHeight = ( int ) (width * sin + height * cos);
             // 能把原图像和旋转后图像同时放入的外框
             int  frameWidth = Math.max(width, newWidth);
             int  frameHeight = Math.max(height, newHeight);
             Size frameSize =  new  Size(frameWidth, frameHeight);
             Mat mat_frame =  new  Mat(frameSize, mat_bmp.type());
             // 将原图像copy进外框
             int  offsetX = (frameWidth - width) /  2 ;
             int  offsetY = (frameHeight - height) /  2 ;
             Mat mat_frame_submat = mat_frame.submat(offsetY, offsetY + height, offsetX, offsetX
                     + width);
             mat_bmp.copyTo(mat_frame_submat);
             // 旋转外框
             Point center =  new  Point(frameWidth /  2 , frameHeight /  2 );
             Mat mat_rot = Imgproc.getRotationMatrix2D(center, degree,  1.0 );
             Mat mat_res =  new  Mat();  // result
             Imgproc.warpAffine(mat_frame, mat_res, mat_rot, frameSize, Imgproc.INTER_LINEAR,
                     Imgproc.BORDER_CONSTANT, Scalar.all( 0 ));
             // 从旋转后的外框获取新图像
             offsetX = (frameWidth - newWidth) /  2 ;
             offsetY = (frameHeight - newHeight) /  2 ;
             Mat mat_res_submat = mat_res.submat(offsetY, offsetY + newHeight, offsetX, offsetX
                     + newWidth);
             return  mat_res_submat;
         }
     });
}


6. Bitmap效果器


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/**
  * @brief Bitmap效果器
  * @author join
  */
public  static  class  Effector {
     private  Config config;
     private  Mat mat;
     private  boolean  isGray;
     private  Mat mSepiaKernel;
     /**
      * @brief 构造函数
      * @param bmp 源Bitmap
      * @param config 'ARGB_8888' or 'RGB_565'
      */
     public  Effector(Bitmap bmp, Config config) {
         Mat mat_bmp =  new  Mat(bmp.getHeight(), bmp.getWidth(), CvType.CV_8UC4);
         Utils.bitmapToMat(bmp, mat_bmp,  false );  // Bitmap->Mat
         this .mat = mat_bmp;
         this .config = config;
         this .isGray =  false ;
     }
     /**
      * @brief 构造函数,config默认为RGB_565
      * @see #BitmapUtil(Bitmap, Config)
      */
     public  Effector(Bitmap bmp) {
         this (bmp, Bitmap.Config.RGB_565);
     }
     /**
      * @brief 创建Bitmap
      * @return Bitmap
      */
     public  Bitmap create() {
         Mat mat_new =  this .mat;
         if  (isGray) {
             Mat mat_gray =  new  Mat(mat_new.rows(), mat_new.cols(), CvType.CV_8UC4);
             Imgproc.cvtColor(mat_new, mat_gray, Imgproc.COLOR_GRAY2BGRA,  4 );  // 转为灰度4通道Mat
             mat_new = mat_gray;
         }
         Bitmap bmp_new = Bitmap.createBitmap(mat_new.cols(), mat_new.rows(),  this .config);
         Utils.matToBitmap(mat_new, bmp_new,  false );  // Mat->Bitmap
         return  bmp_new;
     }
     /**
      * @brief 灰度化Bitmap
      */
     public  Effector gray() {
         Mat mat_bmp =  this .mat;
         Mat mat_gray =  new  Mat();
         Imgproc.cvtColor(mat_bmp, mat_gray, Imgproc.COLOR_BGRA2GRAY,  1 );  // 转为灰度单通道Mat
         this .mat = mat_gray;
         this .isGray =  true ;
         return  this ;
     }
     /**
      * @brief Bitmap二值化
      * @pre 需先灰度化{@link #gray()}
      * @param thresh 阈值。type为THRESH_OTSU时无用,其自适应区域阈值。
      * @param maxval 最大值。type为THRESH_BINARY或THRESH_BINARY_INV时才使用。
      * @param type 运算类型
      * @see Imgproc#threshold(Mat, Mat, double, double, int)
      * @see THRESH_OTSU: {@link Imgproc#adaptiveThreshold(Mat, Mat, double, int, int, int, double)}
      */
     public  Effector threshold( double  thresh,  double  maxval,  int  type) {
         if  (!isGray) {
             // throw new IllegalArgumentException("must call gray() before this.");
             gray();
         }
         Mat mat_gray =  this .mat;
         Imgproc.threshold(mat_gray, mat_gray, thresh, maxval, type);
         return  this ;
     }
     /**
      * @brief Bitmap二值化
      * @details thresh: 127; maxval: 255; type: THRESH_OTSU;
      * @see #threshold(double, double, int)
      */
     public  Effector threshold() {
         return  threshold( 127 255 , Imgproc.THRESH_OTSU);
     }
     /**
      * @brief Canny算子边缘检测
      * @param threshold1 控制边缘连接的下限阈值
      * @param threshold2 控制强边缘的初始分割的上阈限值
      *  如果一个像素的梯度大于上阈限值,则被认为是边缘像素,如果小于下限阈值,则被抛弃。
      *  如果该点的梯度在两者之间则当这个点与高于上阈限值的像素点连接时我们才保留,否则抛弃。
      */
     public  Effector canny( final  double  threshold1,  final  double  threshold2) {
         Mat mat =  this .mat;
         Imgproc.Canny(mat, mat, threshold1, threshold2,  3 false );  // Canny边缘检测
         return  this ;
     }
     /**
      * @brief Canny边缘检测,返回为RGB_565
      * @details threshold1: 80; threshold2: 90;
      * @see #canny(Bitmap, Config)
      */
     public  Effector canny() {
         return  canny( 80 90 );
     }
     /**
      * @brief Sobel处理
      */
     public  Effector sobel() {
         Mat mat =  this .mat;
         Imgproc.Sobel(mat, mat, CvType.CV_8U,  1 1 );  // 一阶差分
         Core.convertScaleAbs(mat, mat,  10 0 );  // 线性变换
         return  this ;
     }
     /**
      * @brief 棕褐色
      */
     public  Effector sepia() {
         Mat mat =  this .mat;
         Core.transform(mat, mat, getSepiaKernel());
         return  this ;
     }
     private  Mat getSepiaKernel() {
         if  (mSepiaKernel !=  null ) {
             return  mSepiaKernel;
         }
         mSepiaKernel =  new  Mat( 4 4 , CvType.CV_32F);
         mSepiaKernel.put( 0 0 /* R */0.189f, 0.769f, 0.393f, 0f);
         mSepiaKernel.put(1, 0, /* G */0.168f, 0.686f, 0.349f, 0f);
         mSepiaKernel.put(2, 0, /* B */0.131f, 0.534f, 0.272f, 0f);
         mSepiaKernel.put(3, 0, /* A */ 0 .000f,  0 .000f,  0 .000f, 1f);
         return  mSepiaKernel;
     }
}


# Over


常用的一些方法就这样了^^。



     本文转自winorlose2000 51CTO博客,原文链接:http://blog.51cto.com/vaero/1202128,如需转载请自行联系原作者




相关文章
|
4月前
|
XML Android开发 数据格式
[Android]Bitmap Drawable
[Android]Bitmap Drawable
29 0
|
12月前
|
缓存 Java Android开发
Android C++系列:JNI操作Bitmap
在 Android 通过 JNI 去调用 Bitmap,通过 CMake 去编 so 动态链接库的话,需要添加 jnigraphics 图像库。
347 0
|
Android开发
Android关于Bitmap的缩放方法
最近要将图片传给服务器,但是服务器限制了图片的大小,所以我查询了许多相关文章,现在将其罗列出来。
975 0
|
Java API Android开发
|
前端开发 开发工具 Android开发
|
前端开发 Android开发 图形学
|
前端开发 Android开发

热门文章

最新文章