Android处理Bitmap的一些方法

时间:2021-04-09 20:25:38

http://www.it165.net/pro/html/201305/5795.html

# 文件与Bitmap间的方法

1. 从文件载入Bitmap

01./**
02.* @brief 从文件载入Bitmap
03.* @param path 图片路径
04.* @param opts 选项
05.* @return Bitmap
06.*/
07.public Bitmap loadFromFile(String path, Options opts) {
08.try {
09.File f = new File(path);
10.if (!f.exists() || f.isDirectory()) {
11.return null;
12.}
13.Bitmap bm = BitmapFactory.decodeFile(path, opts);
14.return bm;
15.catch (Exception e) {
16.return null;
17.}
18.}
19./**
20.* @brief 从文件载入Bitmap
21.* @param path 图片路径
22.* @return Bitmap
23.*/
24.public Bitmap loadFromFile(String path) {
25.return loadFromFile(path, null);
26.}

2. 载入取样的Bitmap

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

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

01./**
02.* @brief 从文件载入采样后的Bitmap
03.* @see android.graphics.BitmapFactory.Options#inSampleSize
04.*/
05.public Bitmap loadSampleSize(String path, int sampleSize) {
06.Options opts = new Options();
07.opts.inSampleSize = sampleSize;
08.return loadFromFile(path, opts);
09.}

3. 载入Bitmap边框

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

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

01./**
02.* @brief 从文件载入只获边框的Bitmap www.it165.net
03.* @see android.graphics.BitmapFactory.Options#inJustDecodeBounds
04.*/
05.public Options loadJustDecodeBounds(String path) {
06.Options opts = new Options();
07.opts.inJustDecodeBounds = true;
08.loadFromFile(path, opts);
09.return opts;
10.}

4. 保存Bitmap至文件

01./**
02.* @brief 保存Bitmap至文件
03.* @param bm Bitmap
04.* @param path 图片路径
05.* @return 成功与否
06.*/
07.public boolean compressBitmap(Bitmap bm, String path) {
08.FileOutputStream out = null;
09.try {
10.out = new FileOutputStream(path);
11.bm.compress(Bitmap.CompressFormat.JPEG, 100, out);
12.out.flush();
13.catch (Exception e) {
14.return false;
15.} finally {
16.try {
17.if (out != null) {
18.out.close();
19.}
20.catch (IOException e) {
21.}
22.}
23.return true;
24.}

5. 读取图片方向信息

Bitmap图片的方法==!!!

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

# 处理Bitmap的方法

1. 生成缩略图

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

2. 缩放

01./**
02.* @brief 缩放Bitmap,自动回收原Bitmap
03.* @see ImageUtil#scaleBitmap(Bitmap, int, int, boolean)
04.*/
05.public Bitmap scaleBitmap(Bitmap src, int dstWidth, int dstHeight) {
06.return scaleBitmap(src, dstWidth, dstHeight, true);
07.}
08./**
09.* @brief 缩放Bitmap
10.* @param src 源Bitmap
11.* @param dstWidth 目标宽度
12.* @param dstHeight 目标高度
13.* @param isRecycle 是否回收原图像
14.* @return Bitmap
15.*/
16.public Bitmap scaleBitmap(Bitmap src, int dstWidth, int dstHeight, boolean isRecycle) {
17.if (src.getWidth() == dstWidth && src.getHeight() == dstHeight) {
18.return src;
19.}
20.Bitmap dst = Bitmap.createScaledBitmap(src, dstWidth, dstHeight, false);
21.if (isRecycle && dst != src) {
22.src.recycle();
23.}
24.return dst;
25.}

3. 裁剪

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

4. 旋转

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

# OpenCV处理Bitmap的方法

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

1. 常规性的init

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

2. 常规性处理流程

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

01.private interface IHandler {
02.Mat proc(Mat mat_bmp);
03.}
04.private Bitmap handle(Bitmap src, IHandler handler) {
05.Mat mat_bmp = new Mat(src.getHeight(), src.getWidth(), CvType.CV_8UC4);
06.Utils.bitmapToMat(src, mat_bmp, false); // Bitmap->Mat
07.Mat mat_new = handler.proc(mat_bmp); // handle mat
08.Bitmap bmp_new = Bitmap.createBitmap(mat_new.cols(), mat_new.rows(),
09.Bitmap.Config.ARGB_8888);
10.Utils.matToBitmap(mat_new, bmp_new, false); // Mat->Bitmap
11.src.recycle();
12.return bmp_new;
13.}

3. 缩放

01./**
02.* @brief 缩放Bitmap
03.* @param src 源Bitmap
04.* @param dstWidth 目标宽度
05.* @param dstHeight 目标高度
06.* @return Bitmap
07.*/
08.public Bitmap scaleBitmap2(Bitmap src, final int dstWidth, final int dstHeight) {
09.if (src.getWidth() == dstWidth && src.getHeight() == dstHeight) {
10.return src;
11.}
12.return handle(src, new IHandler() {
13.@Override
14.public Mat proc(Mat mat_bmp) {
15.Mat mat_new = new Mat();
16.Imgproc.resize(mat_bmp, mat_new, new Size(dstWidth, dstHeight));
17.return mat_new;
18.}
19.});
20.}

4. 裁剪

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

5. 旋转

01./**
02.* @brief 旋转Bitmap,逆时针
03.* @param src 源Bitmap
04.* @param degree 旋转角度
05.* @return Bitmap
07.*/
08.public Bitmap rotateBitmap2(Bitmap src, final int degree) {
09.if (degree % 360 == 0) {
10.return src;
11.}
12.return handle(src, new IHandler() {
13.@Override
14.public Mat proc(Mat mat_bmp) {
15.// 计算旋转后图像的宽高
16.double radians = Math.toRadians(degree);
17.double sin = Math.abs(Math.sin(radians));
18.double cos = Math.abs(Math.cos(radians));
19.int width = mat_bmp.width();
20.int height = mat_bmp.height();
21.int newWidth = (int) (width * cos + height * sin);
22.int newHeight = (int) (width * sin + height * cos);
23.// 能把原图像和旋转后图像同时放入的外框
24.int frameWidth = Math.max(width, newWidth);
25.int frameHeight = Math.max(height, newHeight);
26.Size frameSize = new Size(frameWidth, frameHeight);
27.Mat mat_frame = new Mat(frameSize, mat_bmp.type());
28.// 将原图像copy进外框
29.int offsetX = (frameWidth - width) / 2;
30.int offsetY = (frameHeight - height) / 2;
31.Mat mat_frame_submat = mat_frame.submat(offsetY, offsetY + height, offsetX, offsetX
32.+ width);
33.mat_bmp.copyTo(mat_frame_submat);
34.// 旋转外框
35.Point center = new Point(frameWidth / 2, frameHeight / 2);
36.Mat mat_rot = Imgproc.getRotationMatrix2D(center, degree, 1.0);
37.Mat mat_res = new Mat(); // result
38.Imgproc.warpAffine(mat_frame, mat_res, mat_rot, frameSize, Imgproc.INTER_LINEAR,
39.Imgproc.BORDER_CONSTANT, Scalar.all(0));
40.// 从旋转后的外框获取新图像
41.offsetX = (frameWidth - newWidth) / 2;
42.offsetY = (frameHeight - newHeight) / 2;
43.Mat mat_res_submat = mat_res.submat(offsetY, offsetY + newHeight, offsetX, offsetX
44.+ newWidth);
45.return mat_res_submat;
46.}
47.});
48.}

6. Bitmap效果器

001./**
002.* @brief Bitmap效果器
003.* @author join
004.*/
005.public static class Effector {
006.private Config config;
007.private Mat mat;
008.private boolean isGray;
009.private Mat mSepiaKernel;
010./**
011.* @brief 构造函数
012.* @param bmp 源Bitmap
013.* @param config 'ARGB_8888' or 'RGB_565'
014.*/
015.public Effector(Bitmap bmp, Config config) {
016.Mat mat_bmp = new Mat(bmp.getHeight(), bmp.getWidth(), CvType.CV_8UC4);
017.Utils.bitmapToMat(bmp, mat_bmp, false); // Bitmap->Mat
018.this.mat = mat_bmp;
019.this.config = config;
020.this.isGray = false;
021.}
022./**
023.* @brief 构造函数,config默认为RGB_565
024.* @see #BitmapUtil(Bitmap, Config)
025.*/
026.public Effector(Bitmap bmp) {
027.this(bmp, Bitmap.Config.RGB_565);
028.}
029./**
030.* @brief 创建Bitmap
031.* @return Bitmap
032.*/
033.public Bitmap create() {
034.Mat mat_new = this.mat;
035.if (isGray) {
036.Mat mat_gray = new Mat(mat_new.rows(), mat_new.cols(), CvType.CV_8UC4);
037.Imgproc.cvtColor(mat_new, mat_gray, Imgproc.COLOR_GRAY2BGRA, 4); // 转为灰度4通道Mat
038.mat_new = mat_gray;
039.}
040.Bitmap bmp_new = Bitmap.createBitmap(mat_new.cols(), mat_new.rows(), this.config);
041.Utils.matToBitmap(mat_new, bmp_new, false); // Mat->Bitmap
042.return bmp_new;
043.}
044./**
045.* @brief 灰度化Bitmap
046.*/
047.public Effector gray() {
048.Mat mat_bmp = this.mat;
049.Mat mat_gray = new Mat();
050.Imgproc.cvtColor(mat_bmp, mat_gray, Imgproc.COLOR_BGRA2GRAY, 1); // 转为灰度单通道Mat
051.this.mat = mat_gray;
052.this.isGray = true;
053.return this;
054.}
055./**
056.* @brief Bitmap二值化
057.* @pre 需先灰度化{@link #gray()}
058.* @param thresh 阈值。type为THRESH_OTSU时无用,其自适应区域阈值。
059.* @param maxval 最大值。type为THRESH_BINARY或THRESH_BINARY_INV时才使用。
060.* @param type 运算类型
061.* @see Imgproc#threshold(Mat, Mat, double, double, int)
062.* @see THRESH_OTSU: {@link Imgproc#adaptiveThreshold(Mat, Mat, double, int, int, int, double)}
063.*/
064.public Effector threshold(double thresh, double maxval, int type) {
065.if (!isGray) {
066.// throw new IllegalArgumentException("must call gray() before this.");
067.gray();
068.}
069.Mat mat_gray = this.mat;
070.Imgproc.threshold(mat_gray, mat_gray, thresh, maxval, type);
071.return this;
072.}
073./**
074.* @brief Bitmap二值化
075.* @details thresh: 127; maxval: 255; type: THRESH_OTSU;
076.* @see #threshold(double, double, int)
077.*/
078.public Effector threshold() {
079.return threshold(127, 255, Imgproc.THRESH_OTSU);
080.}
081./**
082.* @brief Canny算子边缘检测
083.* @param threshold1 控制边缘连接的下限阈值
084.* @param threshold2 控制强边缘的初始分割的上阈限值
085.*  如果一个像素的梯度大于上阈限值,则被认为是边缘像素,如果小于下限阈值,则被抛弃。
086.*  如果该点的梯度在两者之间则当这个点与高于上阈限值的像素点连接时我们才保留,否则抛弃。
087.*/
088.public Effector canny(final double threshold1, final double threshold2) {
089.Mat mat = this.mat;
090.Imgproc.Canny(mat, mat, threshold1, threshold2, 3, false); // Canny边缘检测
091.return this;
092.}
093./**
094.* @brief Canny边缘检测,返回为RGB_565
095.* @details threshold1: 80; threshold2: 90;
096.* @see #canny(Bitmap, Config)
097.*/
098.public Effector canny() {
099.return canny(80, 90);
100.}
101./**
102.* @brief Sobel处理
103.*/
104.public Effector sobel() {
105.Mat mat = this.mat;
106.Imgproc.Sobel(mat, mat, CvType.CV_8U, 1, 1); // 一阶差分
107.Core.convertScaleAbs(mat, mat, 10, 0); // 线性变换
108.return this;
109.}
110./**
111.* @brief 棕褐色
112.*/
113.public Effector sepia() {
114.Mat mat = this.mat;
115.Core.transform(mat, mat, getSepiaKernel());
116.return this;
117.}
118.private Mat getSepiaKernel() {
119.if (mSepiaKernel != null) {
120.return mSepiaKernel;
121.}
122.mSepiaKernel = new Mat(4, 4, CvType.CV_32F);
123.mSepiaKernel.put(0, 0, /* R */0.189f, 0.769f, 0.393f, 0f);
124.mSepiaKernel.put(1, 0, /* G */0.168f, 0.686f, 0.349f, 0f);
125.mSepiaKernel.put(2, 0, /* B */0.131f, 0.534f, 0.272f, 0f);
126.mSepiaKernel.put(3, 0, /* A */0.000f, 0.000f, 0.000f, 1f);
127.return mSepiaKernel;
128.}
129.}

# Over

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