Android开发 Bitmap图像处理详解
<h1><span style="color: rgba(0, 128, 128, 1)">前言</span></h1><p><span style="color: rgba(0, 0, 0, 1)"> Bitmap开发涉及到方方面面,比如裁剪图片,压缩图片,镜像图片,旋转图片,各种转存图片等等,是必需掌握Android开发技巧,Android开发提供了2个类来实现这些需求,Bitmap类与BitmapFactory类。此博客会持续更新各种实际需求。</span></p>
<h1><span style="color: rgba(0, 128, 128, 1)">将Res位图资源转成Bitmap</span></h1>
<p><span style="color: rgba(0, 0, 0, 1)">请注意,使用这个方法会出现Bitmap为null的问题。这个问题可能是因为资源id异常引起的。特别是你使用了分module形式构建的app</span></p>
<div class="cnblogs_code">
<pre>Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);</pre>
</div>
<h1><span style="color: rgba(0, 128, 128, 1)">将指定文件转成Bitmap</span></h1>
<div class="cnblogs_code">
<pre>Bitmap bitmap = BitmapFactory.decodeFile(getContext().getExternalCacheDir() + File.separator + "demo1.png");</pre>
</div>
<h1><span style="color: rgba(0, 128, 128, 1)">将Drawable矢量图资源转成Bitmap</span></h1>
<div class="cnblogs_code">
<pre> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> Bitmap getBitmapFromDrawable(Context context, @DrawableRes <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> drawableId) {
Drawable drawable </span>=<span style="color: rgba(0, 0, 0, 1)"> ContextCompat.getDrawable(context, drawableId);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (drawable <span style="color: rgba(0, 0, 255, 1)">instanceof</span><span style="color: rgba(0, 0, 0, 1)"> BitmapDrawable) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> ((BitmapDrawable) drawable).getBitmap();
} </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (drawable <span style="color: rgba(0, 0, 255, 1)">instanceof</span> VectorDrawable || drawable <span style="color: rgba(0, 0, 255, 1)">instanceof</span><span style="color: rgba(0, 0, 0, 1)"> VectorDrawableCompat) {
Bitmap bitmap </span>=<span style="color: rgba(0, 0, 0, 1)"> Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Canvas(bitmap);
drawable.setBounds(</span>0, 0<span style="color: rgba(0, 0, 0, 1)">, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> bitmap;
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> IllegalArgumentException("unsupported drawable type"<span style="color: rgba(0, 0, 0, 1)">);
}
}</span></pre>
</div>
<h1><span style="color: rgba(0, 128, 128, 1)">将Uri转成Bitmap</span></h1>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)"> @Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> onActivityResult(<span style="color: rgba(0, 0, 255, 1)">int</span> requestCode, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> resultCode, @Nullable Intent data) {
</span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.onActivityResult(requestCode, resultCode, data);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">相册选择图片</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (requestCode == GALLERY_RESULT_CODE && resultCode ==<span style="color: rgba(0, 0, 0, 1)"> RESULT_OK) {
</span><span style="color: rgba(0, 0, 255, 1)">final</span> Uri uri =<span style="color: rgba(0, 0, 0, 1)"> data.getData();
</span> <span style="color: rgba(0, 0, 255, 1)">try</span> (InputStream inputStream =<span style="color: rgba(0, 0, 0, 1)"> getActivity().getApplicationContext().getContentResolver().openInputStream(uri)) {
Bitmap bitmap </span>= BitmapFactory.decodeStream(inputStream);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">得到bitmap</span>
} <span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (FileNotFoundException e) {
e.printStackTrace();
} </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) {
e.printStackTrace();
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
}
}</span></pre>
</div>
<h1><span style="color: rgba(0, 128, 128, 1)">将Bitmap输出成文件</span> </h1>
<div class="cnblogs_code">
<pre> Bitmap bitmap = BitmapFactory.decodeFile(getContext().getExternalCacheDir() + File.separator + "demo1.png"<span style="color: rgba(0, 0, 0, 1)">);
File file </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> File(getContext().getExternalCacheDir(), "demo.jpg"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">try</span> (FileOutputStream fileOutputStream = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileOutputStream(file)) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">参数1:输出的图片格式 参数2:输出图片的压缩质量(范围值为0-100) 参数3:输出流</span>
bitmap.compress(Bitmap.CompressFormat.JPEG, 90<span style="color: rgba(0, 0, 0, 1)">, fileOutputStream);
} </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (FileNotFoundException e) {
e.printStackTrace();
} </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) {
e.printStackTrace();
}</span></pre>
</div>
<h1><span style="color: rgba(0, 128, 128, 1)">镜像垂直翻转</span></h1>
<div class="cnblogs_code">
<pre> Bitmap bitmap =<span style="color: rgba(0, 0, 0, 1)"> BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
Matrix matrix </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Matrix();
matrix.postScale(</span>1, -1); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">镜像垂直翻转</span>
Bitmap changBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">);<br></span></pre>
</div>
<h1><span style="color: rgba(0, 128, 128, 1)">镜像水平翻转</span></h1>
<div class="cnblogs_code">
<pre> Bitmap bitmap =<span style="color: rgba(0, 0, 0, 1)"> BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
Matrix matrix </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Matrix();
matrix.postScale(</span>-1, 1); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">镜像水平翻转</span>
Bitmap changBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">);
mBinding.weatherIcon.setImageBitmap(changBitmap);</span></pre>
</div>
<h1><span style="color: rgba(0, 128, 128, 1)">旋转图片</span></h1>
<div class="cnblogs_code">
<pre> Bitmap bitmap =<span style="color: rgba(0, 0, 0, 1)"> BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
Matrix matrix </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Matrix();
matrix.postRotate(</span>-90);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">旋转-90度</span>
Bitmap changBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">);
mBinding.weatherIcon.setImageBitmap(changBitmap);</span></pre>
</div>
<h1><span style="color: rgba(0, 128, 128, 1)">压缩图片质量,降低图片存储大小</span></h1>
<p>原理其实很简单就是利用compress方法,一点一点的降低图片质量,最后压缩到需要的目标存储大小</p>
<div class="cnblogs_code">
<pre> <span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
* 压缩图片
* </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> bitmap bitmap图片 压缩
* </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> targetKB 目标压缩大小
* </span><span style="color: rgba(128, 128, 128, 1)">@return</span>
<span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">private</span> Bitmap compressImage(Bitmap bitmap, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> targetKB){
Bitmap outBitmap </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
ByteArrayInputStream bais </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
ByteArrayOutputStream baos </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
baos </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ByteArrayOutputStream();
</span><span style="color: rgba(0, 0, 255, 1)">int</span> quality = 80<span style="color: rgba(0, 0, 0, 1)">;
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);
</span><span style="color: rgba(0, 0, 255, 1)">while</span> ((baos.toByteArray().length/1024) ><span style="color: rgba(0, 0, 0, 1)"> targetKB){
quality </span>= quality-10<span style="color: rgba(0, 0, 0, 1)">;
baos.reset();
bitmap.compress(Bitmap.CompressFormat.JPEG,quality,baos);
}
bais </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ByteArrayInputStream(baos.toByteArray());
outBitmap </span>=<span style="color: rgba(0, 0, 0, 1)"> BitmapFactory.decodeStream(bais);
bais.close();
baos.close();
} </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e) {
e.printStackTrace();
onError(e);
} </span><span style="color: rgba(0, 0, 255, 1)">finally</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
bais.close();
baos.close();
} </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) {
e.printStackTrace();
}
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> outBitmap;
}</span></pre>
</div>
<h1><span style="color: rgba(0, 128, 128, 1)">压缩图片尺寸</span></h1>
<p><span style="color: rgba(0, 0, 0, 1)">原理是利用BitmapFactory.decodeStream方法,传入options,以降幂的方式等比例的压缩到目标尺寸,关键是options.inSampleSize = be;这个属性的配置</span></p>
<p> </p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
* 尺寸压缩
* </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> bitmap
</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">private</span> Bitmap sizeCompres(Bitmap bitmap,<span style="color: rgba(0, 0, 255, 1)">float</span> targetWidth,<span style="color: rgba(0, 0, 255, 1)">float</span><span style="color: rgba(0, 0, 0, 1)"> targetHeight){
Bitmap handleBitmap </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
ByteArrayOutputStream baos </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG,</span>100<span style="color: rgba(0, 0, 0, 1)">,baos);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 判断如果图片大于1M,进行压缩避免在生成图片(BitmapFactory.decodeStream)时溢出</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (baos.toByteArray().length / 1024 > 1024<span style="color: rgba(0, 0, 0, 1)">) {
baos.reset();</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 重置baos即清空baos</span>
bitmap.compress(Bitmap.CompressFormat.JPEG, 50, baos);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 这里压缩50%,把压缩后的数据存放到baos中</span>
<span style="color: rgba(0, 0, 0, 1)"> }
ByteArrayInputStream bais </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ByteArrayInputStream(baos.toByteArray());
BitmapFactory.Options options </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BitmapFactory.Options();
options.inJustDecodeBounds </span>= <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
BitmapFactory.decodeStream(bais,</span><span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">,options);
options.inJustDecodeBounds </span>= <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">int</span> imageWidth =<span style="color: rgba(0, 0, 0, 1)"> options.outWidth;
</span><span style="color: rgba(0, 0, 255, 1)">int</span> imageHeight =<span style="color: rgba(0, 0, 0, 1)"> options.outHeight;
</span><span style="color: rgba(0, 0, 255, 1)">int</span> be = 1<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (imageWidth>imageHeight && imageWidth><span style="color: rgba(0, 0, 0, 1)">targetWidth){
be </span>= Math.round(imageWidth/<span style="color: rgba(0, 0, 0, 1)">targetWidth);
}</span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (imageHeight>imageWidth && imageHeight><span style="color: rgba(0, 0, 0, 1)">targetHeight){
be </span>= Math.round(imageHeight/<span style="color: rgba(0, 0, 0, 1)">targetHeight);
}
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (be <= 1<span style="color: rgba(0, 0, 0, 1)">){
be </span>=1;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">如果小于1等于1就不需要压缩直接返回</span>
<span style="color: rgba(0, 0, 0, 1)"> }
options.inSampleSize </span>=<span style="color: rgba(0, 0, 0, 1)"> be;
bais </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> ByteArrayInputStream(baos.toByteArray());<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">bais运行到这里可能已经清空了,所以需要再次添加</span>
handleBitmap = BitmapFactory.decodeStream(bais,<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">,options);
bais.close();
baos.close();
} </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e) {
e.printStackTrace();
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> handleBitmap;
}</span></pre>
</div>
<h1><span style="color: rgba(0, 0, 0, 1)">获取图片的角度属性与将图片角度属性设置回去</span></h1>
<p>获取图片的角度属性很重要,这里说明下,因为我们在压缩或者读取图片成Bitmap后在保存到文件里会丢失图片的角度,这样下次在查看这张图片的时候极有可能是倒的图片</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
ExifInterface exifInterface </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> ExifInterface(inpPath);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取图片角度</span>
mDegrees = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">int</span> angle = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">switch</span><span style="color: rgba(0, 0, 0, 1)"> (angle){
</span><span style="color: rgba(0, 0, 255, 1)">case</span><span style="color: rgba(0, 0, 0, 1)"> ExifInterface.ORIENTATION_ROTATE_270:
mDegrees </span>= 270<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">break</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">case</span><span style="color: rgba(0, 0, 0, 1)"> ExifInterface.ORIENTATION_ROTATE_180:
mDegrees </span>= 180<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">break</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">case</span><span style="color: rgba(0, 0, 0, 1)"> ExifInterface.ORIENTATION_ROTATE_90:
mDegrees </span>= 90<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">break</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">default</span><span style="color: rgba(0, 0, 0, 1)">:
mDegrees </span>= 0<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">break</span><span style="color: rgba(0, 0, 0, 1)">;
}
} </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) {
e.printStackTrace();
}</span></pre>
</div>
<p> 将图片角度设置回去</p>
<div class="cnblogs_code">
<pre> Matrix matrix = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Matrix();
matrix.setRotate(mDegrees, bitmap.getWidth(), bitmap.getHeight());
Bitmap finishBitmap </span>= Bitmap.createBitmap(finishBitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix,<span style="color: rgba(0, 0, 255, 1)">true</span>);</pre>
</div>
<p> </p>
<p> </p>
<p>End</p>
</div>
<div id="MySignature" role="contentinfo">
<div style="text-align: center">
<p style="color:orange;font-size:16px;" >本文来自博客园,作者:观心静 ,转载请注明原文链接:https://www.cnblogs.com/guanxinjing/p/13566480.html </p>
<div style="color:orange;font-size:16px;">本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。 </div>
</div><br><br>
来源:https://www.cnblogs.com/guanxinjing/p/13566480.html
頁:
[1]