Bitmap的常见操作(二.代码)——圆角,压缩图片,缩略图

简介: package com.testbitmapscale;import java.io.File;import java.io.FileInputStream;import java.
package com.testbitmapscale;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.Canvas;
import android.graphics.Matrix;
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.os.Bundle;
import android.os.Environment;
import android.widget.ImageView;
/**
 * Demo描述:
 * 1 生成圆角Bitmap图片
 * 2 利用Bitmap.compress()方法将Bitmap保存到指定位置.
 *   该方法可减少原Bitmap的KB值,但不一定会减少原Bitmap宽和高的pixel.
 * 3 利用Google提供的方法计算出合适的options.inSampleSize,从而获取缩略图
 * 4 利用系统自带方法ThumbnailUtils.extractThumbnail()获取缩略图
 * 5 利用Bitmap.createBitmap(...matrix...)获取缩略图
 *   该方法主要是利用了矩阵Matrix的postScale()设置缩放比
 * 
 * 
 * 注意事项:
 * 测试其中一个方法时最好注释掉其余的代码
 * 
 * 参考资料:
 * 1 http://blog.csdn.net/c8822882/article/details/6906768
 * 2 http://www.5yijia.com/?p=173
 * 3 http://blog.csdn.net/t12x3456/article/details/10432935
 * 4 http://blog.csdn.net/edisonlg/article/details/7084977
 * 5 http://blog.csdn.net/superfpe/article/details/8750938
 *   Thank you very much
 */

public class MainActivity extends Activity {
	private ImageView mImageView;
    private Bitmap copyRawBitmap;
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		mImageView = (ImageView) findViewById(R.id.imageView);
		
		
		//------>以下为生成Bitmap的几种方式
		//第一种方式:从资源文件中得到图片
		Bitmap rawBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.haha);
		copyRawBitmap=rawBitmap;
		//第二种方式:从SD卡中得到图片(方法1)
		String SDCarePath=Environment.getExternalStorageDirectory().toString();
		String filePath=SDCarePath+"/"+"haha.jpg";
		Bitmap rawBitmap1 = BitmapFactory.decodeFile(filePath, null);
		//第二种方式:从SD卡中得到图片(方法2)
		InputStream inputStream=getBitmapInputStreamFromSDCard("haha.jpg");
		Bitmap rawBitmap2 = BitmapFactory.decodeStream(inputStream);
		//------>以上为生成Bitmap的几种方式
		
		
		
		
//		//------>以下为将设置图片的圆角
//		Bitmap roundCornerBitmap=this.getRoundCornerBitmap(rawBitmap, 60);
//		mImageView.setImageBitmap(roundCornerBitmap);
//		//------>以上为将设置图片的圆角
		
		
		
		
//		//------>以下为将图片的kB压缩即KB会变小,但宽高(pixel像素)可能变大或者变小
//		 this.compressAndSaveBitmapToSDCard(copyRawBitmap,"haha_new70.jpg",70);
//		 this.compressAndSaveBitmapToSDCard(copyRawBitmap,"haha_new80.jpg",80);
//		 this.compressAndSaveBitmapToSDCard(copyRawBitmap,"haha_new90.jpg",90);
//		//------>以上为将图片的kB压缩即KB会变小,但宽高(pixel像素)可能变大或者变小
		
		
		
		 
		 
		
//		//------>以下为获取SD卡图片的缩略图方法1
//		String SDCarePath1=Environment.getExternalStorageDirectory().toString();
//		String filePath1=SDCarePath1+"/"+"haha.jpg";
//		Bitmap bitmapThumbnail1=this.getBitmapThumbnail(filePath1);
//		mImageView.setImageBitmap(bitmapThumbnail1);
//		//------>以上为获取SD卡图片的缩略图方法1
		
		
		
		
		
//		//------>以下为获取SD卡图片的缩略图方法2
//		//利用系统自带方法ThumbnailUtils.extractThumbnail(Bitmap source,int width,int height)
//		//第二,三个参数表示压缩后的宽和高
//		String SDCarePath2=Environment.getExternalStorageDirectory().toString();
//		String filePath2=SDCarePath2+"/"+"xixi.jpg";
//		Bitmap tempBitmap=BitmapFactory.decodeFile(filePath2);
//		Bitmap bitmapThumbnail2=ThumbnailUtils.extractThumbnail(tempBitmap, 200, 200);
//		mImageView.setImageBitmap(bitmapThumbnail2);
//		//------>以上为获取SD卡图片的缩略图方法2
		
		
		
//		//------>以下为利用Bitmap.createBitmap()获取缩略图
//		// 第一步:得到图片原始的高宽
//		int rawHeight = rawBitmap.getHeight();
//		int rawWidth = rawBitmap.getWidth();
//		// 第二步:设定图片新的高宽
//		int newHeight = 500;
//		int newWidth = 500;
//		// 第三步:计算缩放因子
//		float heightScale = ((float) newHeight) / rawHeight;
//		float widthScale = ((float) newWidth) / rawWidth;
//		// 第四步:利用Matrix设置宽和高的缩放Scale
//		Matrix matrix = new Matrix();
//		matrix.postScale(widthScale, heightScale);
//		// 设置图片的旋转角度
//		//matrix.postRotate(-30);
//		// 设置图片的倾斜
//		//matrix.postSkew(0.1f, 0.1f);
//        // 第五步:获取缩略图
//		Bitmap newBitmap = Bitmap.createBitmap(rawBitmap, 0, 0, rawWidth,rawHeight, matrix, true);
//		mImageView.setImageBitmap(newBitmap);
//		//------>以上为利用Bitmap.createBitmap()获取缩略图
		
	}
	
	
	
   
	
	/**
	 * 压缩且保存图片到SDCard
	 * 
	 * Bitmap.compress(CompressFormat format, int quality, OutputStream stream)
	 * 把位图的压缩信息写入到一个指定的输出流中
	 * 第一个参数format为压缩的格式
	 * 第二个参数quality为图像压缩比的值,0-100.0 意味着小尺寸压缩,100意味着高质量压缩
	 * 第三个参数stream为输出流
	 * 
	 * 注意事项:
	 * 1 Bitmap.compress()该方法不一定会变小图片的宽和高(pixel像素),有时反而会变大
	 *   但一定会减小图片的KB值
	 * 2 Bitmap.compress()该方法不适用于压缩PNG格式,因为它是无损的.
	 *   所以在Android开发中推荐使用PNG格式的图片.jpg格式有什么问题呢?
	 *   jpg格式经过反复的编辑和保存会造成图片失真,请参见资料5
	 */
	private void compressAndSaveBitmapToSDCard(Bitmap rawBitmap,String fileName,int quality){
		String saveFilePaht=this.getSDCardPath()+File.separator+fileName;
		File saveFile=new File(saveFilePaht);
		if (!saveFile.exists()) {
			try {
				saveFile.createNewFile();
				FileOutputStream fileOutputStream=new FileOutputStream(saveFile);
				if (fileOutputStream!=null) {
					rawBitmap.compress(Bitmap.CompressFormat.JPEG, quality, fileOutputStream);
				}
				fileOutputStream.flush();
				fileOutputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
				
			}
		}
	}
	
	
	
	// 获取图片的缩略图
	// 测试分析:
	// 原图大小为宽和高的像素值为:625x690,KB大小值为90.2kB.
	// 该图片在res中备份,作为测试图片
	// 调用方法computeSampleSize(options, 100, 100*200);
	// 表示希望得到的图片宽和高两者的最小值为100pixel,图片的总大小为100*200pixel.
	// 该方法返回的insampleSize=8,最终生成的图片宽和高分别为79和87
	// 在此做一个小验证:
	// 79*8=632 87*8=696 即为632x696,该值接近于原本的625x690
	private Bitmap getBitmapThumbnail(String filePath) {
		BitmapFactory.Options options = new BitmapFactory.Options();
		// 将options.inJustDecodeBounds设置为true
		// 那么利用BitmapFactory.decodeXXX(...options...)将不返回实际的bitmap对象
		// 不给其分配内存空间但是可以得到图片的一些解码边界信息即图片大小等
		options.inJustDecodeBounds = true;
		// 此时rawBitmap为null
		Bitmap rawBitmap = BitmapFactory.decodeFile(filePath, options);
		if (rawBitmap == null) {
			System.out.println("---> 验证了上面的解释");
		}

		// 计算insampleSize
		// inSampleSize表示缩略图大小为原始图片大小的几分之一,若该值为3
		// 则取出的缩略图的宽和高的pixel均为原始图片的1/3,图片大小就为原始大小的1/9
		int insampleSize = computeSampleSize(options, 100, 100 * 200);
		options.inSampleSize = insampleSize;
		// 为BitmapFactory.decodeXXX(...options...)获取到实际的bitmap对象读到图片
		// 必须把options.inJustDecodeBounds设回false
		options.inJustDecodeBounds = false;
		Bitmap thumbnailBitmap = BitmapFactory.decodeFile(filePath, options);
		System.out.println("---> insampleSize="+insampleSize+",width="+
		thumbnailBitmap.getWidth()+",height="+thumbnailBitmap.getHeight());
		return thumbnailBitmap;
	}
	
	
	//Android提供的一种动态计算的方法,得到恰当的inSampleSize
	//第一个参数:原本Bitmap的options
	//第二个参数:希望生成的缩略图的宽高中的pixel较小的值
	//第三个参数:希望生成的缩量图的总像素pixel
	public static int computeSampleSize(Options options,int minSideLength, int maxNumOfPixels) {
		int initialSize = computeInitialSampleSize(options, minSideLength,maxNumOfPixels);
		int roundedSize;
		if (initialSize <= 8) {
			roundedSize = 1;
			while (roundedSize < initialSize) {
				roundedSize <<= 1;
			}
		} else {
			roundedSize = (initialSize + 7) / 8 * 8;
		}

		return roundedSize;
	}
	
	
	
	private static int computeInitialSampleSize(Options options,int minSideLength, int maxNumOfPixels) {
		double w = options.outWidth;
		double h = options.outHeight;
		int lowerBound = (maxNumOfPixels == -1) ? 1 : 
			             (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));
		int upperBound = (minSideLength == -1) ? 128 : 
			             (int) Math.min(Math.floor(w / minSideLength), Math.floor(h / minSideLength));
		if (upperBound < lowerBound) {
			// return the larger one when there is no overlapping zone.
			return lowerBound;
		}
		if ((maxNumOfPixels == -1) && (minSideLength == -1)) {
			return 1;
		} else if (minSideLength == -1) {
			return lowerBound;
		} else {
			return upperBound;
		}
	}
	
	
	
	
	 /**
     * @param bitmap 需要修改的图片
     * @param pixels 圆角的弧度
     * @return 圆角图片
     * 
     * 步骤如下:
     * 1 新建一个Canvas,注意其构造方法为
     *   Canvas canvas = new Canvas(roundCornerBitmap);
     *   即构造方法传入的参数是一个Bitmap
     * 2 在画布上画一个圆角矩形
     * 3 设置Paint的模式Mode.SRC_IN
     * 4 在画布上画原图
     *   最终的结果就是圆角图片即为roundCornerBitmap
     * 
     * 注意事项:
     * 在new一个Canvas需要一个Bitmap作为参数,然后需要画什么东西就利用
     * Canvas的drawXXX()方法即可.在这个画的过程中实际上是画到了这个
     * Bitmap上,即在该Bitmap上涂鸦.所以画的东西和结果都在这个Bitmap上.
     * 
     */
    public  Bitmap getRoundCornerBitmap(Bitmap bitmap, float pixels) {
    	int width=bitmap.getWidth();
    	int height=bitmap.getHeight();
        Bitmap roundCornerBitmap = Bitmap.createBitmap(width,height, Config.ARGB_8888);
        //第一步:利用Bitmap生成Canvas
        Canvas canvas = new Canvas(roundCornerBitmap);
        int color = 0xff424242;
        Paint paint = new Paint();
        paint.setColor(color);
        //防止锯齿
        paint.setAntiAlias(true);
        Rect rect = new Rect(0, 0, width, height);
        RectF rectF = new RectF(rect);
        //相当于清屏
        canvas.drawARGB(0, 0, 0, 0);      
        //第二步:画圆角矩形
        canvas.drawRoundRect(rectF, pixels, pixels, paint);
        //第三步:为画笔Paint设置模式
        paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
        //第四步:画原图
        canvas.drawBitmap(bitmap, rect, rect, paint);
        return roundCornerBitmap;
    }
    
    
    //获取SDCard路径
  	private String getSDCardPath() {
  		String SDCardPath = null;
  		boolean IsSDcardExist = Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
  		if (IsSDcardExist) {
  			SDCardPath = Environment.getExternalStorageDirectory().toString();			
  		}
  		return SDCardPath;
  	}
  	
	// 读取SD卡下的图片
	private InputStream getBitmapInputStreamFromSDCard(String fileName) {
		if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
			String SDCarePath = Environment.getExternalStorageDirectory().toString();
			String filePath = SDCarePath + File.separator + fileName;
			File file = new File(filePath);
			try {
				FileInputStream fileInputStream = new FileInputStream(file);
				return fileInputStream;
			} catch (Exception e) {
				e.printStackTrace();
			}

		}
		return null;
	}

  		

	
}

相关文章
|
Java API Maven
pom文件的<scope>标签详细含义是什么
【4月更文挑战第13天】pom文件的<scope>标签详细含义是什么
1775 3
|
机器学习/深度学习 并行计算 编译器
了解NVIDAI显卡驱动(包括:CUDA、CUDA Driver、CUDA Toolkit、CUDNN、NCVV)
开发过程中需要用到GPU时,通常在安装配置GPU的环境过程中遇到问题;CUDA Toolkit和CUDNN版本的对应关系;CUDA和电脑显卡驱动的版本的对应关系;CUDA Toolkit、CUDNN、NCVV是什么呢?
17979 1
了解NVIDAI显卡驱动(包括:CUDA、CUDA Driver、CUDA Toolkit、CUDNN、NCVV)
|
7月前
|
人工智能 前端开发 搜索推荐
AI 英语口语 APP 的费用
AI英语口语APP开发费用分三块:研发人力(60%-70%)、AI模型调用(Token计费)、第三方授权。预算分三级:MVP版15–30万(基础对话纠错);进阶版40–100万(数字人+发音打分);企业版150万+(自研模型+VR沉浸)。2026年可借轻量化模型、端侧VAD、跨平台框架降本。#AI教育 #AI英语
|
人工智能 运维 监控
聚焦“AI+运维”深度融合,龙蜥系统运维联盟 MeetUp 圆满结束
现场 40 多位开发者进行了深入的技术交流,探索 AI 与运维深度融合的未来路径。
|
机器学习/深度学习 存储 算法
深度学习500问——Chapter03:深度学习基础(2)
深度学习500问——Chapter03:深度学习基础(2)
643 0
|
Java Android开发
Android图片的手动放大缩小
本文介绍了通过缩放因子实现图片放大缩小的功能,效果如动图所示。关键步骤包括:1) 在布局文件中设置 `android:scaleType=&quot;matrix&quot;`;2) 实例化控件并用 `ScaleGestureDetector` 处理缩放手势;3) 使用 `Matrix` 对图片进行缩放处理。为避免内存崩溃,可在全局配置添加 `android:largeHeap=&quot;true&quot;`。代码中定义了 `beforeScale` 和 `nowScale` 变量控制缩放范围,确保流畅体验。
486 8
|
机器学习/深度学习 人工智能 自然语言处理
人体图智能导诊系统的功能与应用分析
人体图智能导诊系统结合AI与可视化人体图谱,帮助用户初步判断症状对应科室或疾病,提升分诊效率、优化就医体验。系统通过交互式人体图标注症状,智能分析后推荐就诊科室、提示疾病风险,并具备急诊预警功能,适用于医院平台、自助终端、互联网医疗等多种场景。
876 0
|
存储 开发工具 git
[Git] 深入理解 Git 的客户端与服务器角色
Git 的核心设计理念是分布式,每个仓库既可以是客户端也可以是服务器。通过 GitHub 远程仓库和本地仓库的协作,Git 实现了高效的版本管理和代码协作。GitHub 作为远程裸仓库,存储项目的完整版本历史并支持多客户端协作;本地仓库则通过 `.git` 文件夹独立管理版本历史,可在离线状态下进行提交、回滚等操作,并通过 `git pull` 和 `git push` 与远程仓库同步。这种分布式特性使得 Git 在代码协作中具备强大的灵活性和可靠性。
[Git] 深入理解 Git 的客户端与服务器角色
|
安全 Java 程序员
ArrayList vs Vector:一场线程安全与性能优化的世纪之争!
在 Java 面试中,ArrayList 和 Vector 是高频考点,但很多人容易混淆。本文通过10分钟深入解析它们的区别,帮助你快速掌握性能、线程安全性、扩容机制等核心知识,让你轻松应对面试题目,提升自信!
513 18
|
JavaScript
vue2【详解】mixins —— 抽离公共逻辑
vue2【详解】mixins —— 抽离公共逻辑
390 0

热门文章

最新文章