戴斌 發表於 2020-8-26 17:43:00

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 &amp;&amp; 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>&nbsp;</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) &gt;<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>&nbsp;</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 &gt; 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&gt;imageHeight &amp;&amp; imageWidth&gt;<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&gt;imageWidth &amp;&amp; imageHeight&gt;<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 &lt;= 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>&nbsp;将图片角度设置回去</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>&nbsp;</p>
<p>&nbsp;</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]
查看完整版本: Android开发 Bitmap图像处理详解