图像的缩放(图像缩小和图像放大 旋转 倾斜)
图像缩放
一、图像缩放的方式在c和java中我都讲过、现在讲一下在android中如何利用api方便快速的缩放图片。主要有一下集中方式:
(1)、加载图片到内存,利用matrix设置缩放、倾斜、旋转属性来创建图片。
public Bitmap SmallImage(Bitmap bitmap,int newHeight , int newWidth){ int h = bitmap.getHeight(); int w = bitmap.getWidth(); float heightScale = ((float) newHeight) / h;// 计算缩放因子 float widthScale = ((float) newWidth) / w; Matrix matrix = new Matrix(); matrix.postScale(widthScale,heightScale); // 设置图片的旋转角度 // // matrix.postRotate(-30); // // 设置图片的倾斜 // // matrix.postSkew(0.1f, 0.1f); Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true); return newBitmap; }
这种方法可以任意改变图像的大小,但是会加载原图片资源到内存中,通过matrix的属性对图像像素矩阵做了相应的变化后创建图片,一般在需要对图像进行其他的处理如倾斜、旋转等操作时用到,时间复杂度和内存消耗都比较大。
(2)不加载图像到内存直接获取图像的宽高对图像进行压缩。且只能用来缩小,不能放大。
当options.inJustDecodeBounds=true时,不加载图片到内存里,但加载了图片的信息。
当options.inJustDecodeBounds=false时,就会加载图片到内存,且若又option作为参数,则按照参数的缩放要求生成新的图片。
但是值得注意的是平时我们加载的不是位图,如jpg、png等。它们都是经过压缩的图,当它们加载成位图的时候就会明显比它们是jpg的时候大,即得到的宽高都会比原来的大很多。
public Bitmap SmallImage2(int newHeight , int newWidth) { BitmapFactory.Options options=new BitmapFactory.Options(); options.inJustDecodeBounds=true;//(设为true 图片不加入内存效率高) BitmapFactory.decodeResource(getResources(),R.drawable.zyh , options); // BitmapFactory.decodeFile(imagePath, options); int outWidth = options.outWidth; int outHeight = options.outHeight; System.out.println("jpg图"+outHeight+","+outWidth); //经实验证明,缩小的倍数只能是整数倍。 options.inSampleSize=(outHeight/newHeight+outWidth/newWidth)/2; options.inJustDecodeBounds=false; Bitmap newBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.zyh , options); Bitmap newBitmap2 = BitmapFactory.decodeResource(getResources(),R.drawable.zyh); System.out.println("目标位图:"+newBitmap.getHeight()+","+newBitmap.getWidth()); System.out.println("原图位图:::"+newBitmap2.getHeight()+","+newBitmap2.getWidth()); return newBitmap; }
打印的结果:
jpg图:900,1440
目标位图:591,945
原图位图:::2363,3780
我调用该函数的语句为:Bitmap bitmap = SmallImage2(200,320); 从结果来看我们最后生成的高、宽为:591、945,而我们要求生成的图为200、320相差太大了。
原因:用decode从资源drawable中加载图像时候,会根据不同的文件夹加载不同分辨率图像,会自动对图像进行缩放。
这种方式效率很高,但是不能整数倍缩小。
(3)android 2.2新加的一个工具类:ThumbnailUtils。
public static Bitmap extractThumbnail(Bitmap source, int width, int height, int options)
第一个是源图像,第二、三个是缩放后输出图像的宽高,第四个参数是缩放方式,当然我们可以调用下面函数来实现缩放:
public static Bitmap extractThumbnail(Bitmap source, int width, int height)
其实这个函数调用的也是上面一个函数,只是第四个参数的缩放方式采取的默认值:OPTIONS_NONE。
网上一些文章说是对前面2种方法的加工,其实在你传入图片的时候就已经加载图片到内存了应该没有第二种方式什么事,看源码发现是对第一种方式的封装,并且源图片使用完了后调用source.recycle()释放源图像的内存,效率应该是介于第一种与第二种高。
但是采用下面的代码测试,我发现采用采用第一种和第三种方式放大图片时,当多次(2-3)点击click按钮时采用第1种方式没事,采用第三者方式反而outofmemory内存溢出了,若有大神知道麻烦告知一下,小弟谢过:
public class MainActivity extends AppCompatActivity { ImageView imageView; Bitmap bt; String imagePath = "data/data/com.example.lammy.imagetest/files/xr.jpg"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imageView = (ImageView) findViewById(R.id.image); } //从图库中获取 public void click(View view) { bt = BitmapFactory.decodeResource(getResources() , R.drawable.xr); Bitmap bitmap = SmallImage(bt,7500,4000); // Bitmap bitmap = SmallImage2(200,320); // Bitmap bitmap = SmallImage3(bt,7500,4000); imageView.setImageBitmap(bitmap); } //图缩小 public Bitmap SmallImage(Bitmap bitmap,int newHeight , int newWidth){ int h = bitmap.getHeight(); int w = bitmap.getWidth(); float heightScale = ((float) newHeight) / h;// 计算缩放因子 float widthScale = ((float) newWidth) / w; Matrix matrix = new Matrix(); matrix.postScale(widthScale,heightScale); // 设置图片的旋转角度 // // matrix.postRotate(-30); // // 设置图片的倾斜 // // matrix.postSkew(0.1f, 0.1f); Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true); System.out.println("目标位图:"+newBitmap.getHeight()+","+newBitmap.getWidth()); return newBitmap; } public Bitmap SmallImage2(int newHeight , int newWidth) { BitmapFactory.Options options=new BitmapFactory.Options(); options.inJustDecodeBounds=true;//(设为true 图片不加入内存效率高) BitmapFactory.decodeResource(getResources(),R.drawable.zyh , options); // BitmapFactory.decodeFile(imagePath, options); int outWidth = options.outWidth; int outHeight = options.outHeight; System.out.println("jpg图"+outHeight+","+outWidth); //经实验证明,缩小的倍数只能是整数倍。 options.inSampleSize=(outHeight/newHeight+outWidth/newWidth)/2; options.inJustDecodeBounds=false; Bitmap newBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.zyh , options); Bitmap newBitmap2 = BitmapFactory.decodeResource(getResources(),R.drawable.zyh); System.out.println("目标位图:"+newBitmap.getHeight()+","+newBitmap.getWidth()); System.out.println("原图位图:::"+newBitmap2.getHeight()+","+newBitmap2.getWidth()); return newBitmap; } public Bitmap SmallImage3(Bitmap bitmapt ,int newHeight , int newWidth) { Bitmap newBitmap = ThumbnailUtils.extractThumbnail(bitmapt,newWidth,newHeight); System.out.println("目标位图:"+newBitmap.getHeight()+","+newBitmap.getWidth()); return newBitmap; } }
图像旋转
一、用matrixde 的方式进行,最后一个参数filter是否保持原来图像的比例,通常matrix中包含缩放的时候用true,若只是平移、旋转则可不需要用到(即为false)。为false的时候效率要比为true的时候高很多,这里得注意取舍。
createBitmap(Bitmap source, int x, int y, int width, int height,
Matrix m, boolean filter)
* * @param origin 原图 * @param angle 旋转角度,可正可负 * @return 旋转后的图片 */ public static Bitmap rotateBitmap(Bitmap origin, float angle) { if (origin == null) { return null; } Matrix matrix = new Matrix(); matrix.setRotate(angle); Bitmap newBM = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false); if (newBM.equals(origin)) { return newBM; } return newBM; }