비트맵(bitmap) 전체 분석 1부


이 섹션 소개:

이전 섹션에서는 Android의 13가지 유형의 Drawable 유형을 직접 적용해 보셨나요? 프로젝트는 어떻습니까? 이 섹션에서는 이 섹션의 내용을 시작하기 전에 Bitmap의 몇 가지 용도에 대해 설명합니다. 먼저 여러 명사의 개념을 구별해 보겠습니다.

  • Drawable: PNG 및 JPG와 같은 일반적인 형식의 이미지를 로드하는 데 사용되는 일반 그래픽 객체입니다. 앞서 배운 13가지 Drawable 유형의 시각적 개체이기도 합니다! 그림을 걸어두는 장소로 이해할 수 있어요 - 액자!
  • Bitmap: 이젤이라고 생각하면 먼저 그림을 그 위에 올려놓은 다음 이미지 파일 정보 획득, 회전 및 잘라내기, 확대/축소 등의 일부 처리를 수행합니다!
  • Canvas: 이름에서 알 수 있듯이 canvas, 그림을 그릴 수 있고 Paint(브러시)를 사용할 수도 있고, 다양한 모양을 그리거나 단어를 쓰려면 Path를 사용하여 여러 점을 그린 다음 다양한 모양으로 연결할 수도 있습니다!
  • Matrix: 그래픽 특수 효과 처리, 컬러 매트릭스(ColorMatrix) 및 이미지 처리용 매트릭스에 사용됩니다. 팬, 확대/축소, 회전, 기울이기 등!

위 내용은 모두 Android의 기본 그래픽 클래스입니다. 인터페이스는 android.graphics에서 제공됩니다! 자, 더 이상 고민하지 말고 이 섹션을 시작하겠습니다! 추신: 공식 문서: Bitmap


1. Bitmap, BitmapFactory, BitmapFacotry.Options 이해하기

제목에서 알 수 있듯이 세 가지의 관계에 대해 직접 이야기할 수도 있었지만 그냥 츤데레하고 싶습니다. , 코드에 따라 다릅니다! 1.gifBitmap 클래스의 소스 코드를 열면 Bitmap의 생성 방법에서 다음과 같은 내용을 볼 수 있습니다.

2.png

제가 말하고 싶은 것은 아마도 Bitmap의 생성 방법은 비공개이며 외부에서 인스턴스화할 수 없다는 것입니다. .JNI를 통해 인스턴스화하세요! 물론 Bitmap을 생성할 수 있는 인터페이스가 확실히 제공될 것이며 이 인터페이스 클래스는 BitmapFactory입니다! 자, BitmapFactory 클래스를 엽니다. 왼쪽의 구조를 클릭하면 BitmapFactory가 제공하는 것을 볼 수 있습니다. 이러한 메소드가 제공되는데 대부분 decodeXxx로 다양한 형태의 Bitmap을 생성할 수 있습니다!

3.png

그런 다음 각 메소드에 옵션 유형 매개변수가 있다는 것을 발견했습니다. 이를 클릭하여 살펴보세요. 그래서 우리는 이것이 정적 내부 클래스인 BitmapFacotry.Options라는 것을 발견했습니다! 그리고 그는 디코딩 중에 옵션을 설정하는 데 사용됩니다!

4.png

여기에서는 OOM(메모리 오버플로)을 방지하기 위해 inJustDecodeBounds를 true로 설정하는 등 일부 매개변수의 값을 설정합니다. 뭐, OOM은 몰라 괜찮아 나중에 설명해줄게! 마지막으로 비트맵으로 돌아왔습니다! 음, 비트맵에서는 방법이 너무 많아서 하나씩 설명하진 않겠습니다. 더 많이 쓰이는 몇 가지만 골라서 설명드리겠습니다! 중국어 문서: Android 중국어 API(136) - Bitmap


2.Bitmap 일반 메소드

common 메소드

  • public boolean compress(Bitmap.CompressFormat 형식, int 품질, OutputStream 스트림) 비트맵을 지정된 OutputStream으로 압축하는 것은 비트맵을 파일에 저장하는 것으로 이해될 수 있습니다! format: 형식, PNG, JPG 등 quality: 압축 품질, 0-100, 0은 가장 낮은 품질 압축을 나타내고 100은 최대 품질을 나타냅니다(PNG는 무손실이며 품질 설정은 무시됩니다) stream : 출력 스트림 반환 값은 지정된 스트림에 대한 압축이 성공했는지 여부를 나타냅니다!
  • void recycle(): 비트맵이 차지하는 메모리 공간을 재활용하고 비트맵을 Dead
  • boolean으로 표시합니다. isRecycled(): 비트맵 메모리가 해제되었는지 확인
  • int getWidth(): 가져오기 비트 이미지의 너비
  • int getHeight(): 비트맵의 높이를 가져옵니다
  • boolean isMutable(): 이미지를 수정할 수 있는지 여부
  • int getScaledWidth(캔버스 캔버스): 가져오기 지정된 밀도 변환 후 이미지의 너비
  • int getScaledHeight(캔버스 캔버스): 지정된 밀도 변환 후 이미지의 높이를 가져옵니다.

Static method:

  • Bitmap createBitmap(Bitmap src) : src를 원본 이미지로 사용하여 불변의 새 이미지 생성 Image
  • Bitmap createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter): src를 원본 이미지로 사용하여 새 이미지를 만들고 높이를 지정하고 새 이미지의 너비와 변경 여부.
  • Bitmap createBitmap(int width, int height, Config config): 지정된 형식과 크기의 비트맵을 생성합니다.
  • Bitmap createBitmap(Bitmap source, int x, int y, int width, int height)는 소스를 원본 이미지로 가져와 새 이미지를 만들고 시작 좌표와 새 이미지의 높이 및 너비를 지정합니다.
  • 공용 정적 비트맵 createBitmap(비트맵 소스, int x, int y, int 너비, int 높이, 행렬 m, 부울 필터)

BitmapFactory.Option설정 가능한 매개변수:

  • boolean inJustDecodeBounds——true로 설정하면 이미지를 가져오지 않고 메모리를 할당하지 않지만 이미지의 높이와 너비 정보를 반환합니다.
  • int inSampleSize——이미지 크기 조정의 배수. 4로 설정하면 너비와 높이가 모두 원본 크기의 1/4이고 이미지는 원본 크기의 1/16입니다.
  • int outWidth——이미지의 너비 값을 가져옵니다.
  • int outHeight——이미지의 높이 값을 가져옵니다.
  • int inDensity——비트맵에 사용되는 픽셀 압축 비율
  • int inTargetDensity—— 대상 비트맵에 사용할 픽셀 압축 비율(생성할 비트맵)
  • boolean inScaled - true로 설정된 경우 inDensity에서 inTargetDensity까지 이미지 압축.

그렇습니다. 문서를 직접 확인해야 합니다~


3. 비트맵 비트맵 가져오기

아래 그림과 같이 BitmapDrawable 또는 BitmapFactory를 통해 리소스에서 비트맵을 가져오는 방법이 두 가지 있습니다. : 먼저 이

BitmapDrawable 메소드를 가져와야 합니다.

스트림을 통해 BitmapDrawable을 구축하는 것과 같이 BitmapDrawable 객체를 생성하는 생성자를 만들 수 있습니다.

BitmapDrawable bmpMeizi = new BitmapDrawable(getAssets().open("pic_meizi.jpg"));
Bitmap mBitmap = bmpMeizi.getBitmap();
img_bg.setImageBitmap(mBitmap);

BitmapFactory 메소드:

는 모두 정적 메소드입니다. , 리소스 ID, 경로, 파일, 데이터 스트림 등을 통해 직접 호출하여 비트맵을 얻을 수 있습니다!

//通过资源ID
private Bitmap getBitmapFromResource(Resources res, int resId) {
      return BitmapFactory.decodeResource(res, resId);
}

//文件
private Bitmap getBitmapFromFile(String pathName) {
      return BitmapFactory.decodeFile(pathName);
}

//字节数组
public Bitmap Bytes2Bimap(byte[] b) {
    if (b.length != 0) {
        return BitmapFactory.decodeByteArray(b, 0, b.length);
    } else {
        return null;
    }
}

//输入流
private Bitmap getBitmapFromStream(InputStream inputStream) {
      return BitmapFactory.decodeStream(inputStream);
}

4. 비트맵 관련 정보 가져오기:

이것은 비트맵 객체를 얻는 한 관련 메서드를 호출하여 해당 매개변수를 가져올 수 있으며, getByteCount는 크기를 가져옵니다. getHeight 및 getWidth ~ 여기서는 쓰지 않겠습니다. 문서를 직접 확인하세요!


5. 그림의 특정 모서리를 당기세요

때로는 그림의 특정 모서리를 당기고 싶을 수도 있습니다. Bitmap의 createBitmap()을 통해 직접 클릭하세요. 매개변수는 처리된 비트맵 객체, 시작 x, y 좌표 및 가로채기된 너비와 높이입니다.

Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(), R.mipmap.pic_meizi);
Bitmap bitmap2 = Bitmap.createBitmap(bitmap1,100,100,200,200);
img_bg = (ImageView) findViewById(R.id.img_bg);
img_bg.setImageBitmap(bitmap2);

렌더링 실행 중:

원본 이미지:

5.png

모퉁이 자르기:

6.png


6. 비트맵 크기 조정

7.png

여기서는 비트맵 크기를 조정하기 위해 Matrix를 사용하지 않고, 이를 구현하기 위해 Bitmap에서 제공하는 createScaledBitmap을 직접 사용합니다. 매개변수는 순서대로입니다. 처리된 비트맵 객체, 크기 조정된 너비 및 높이,


7. 비트맵을 사용하여 스크린샷 찍기

렌더링 실행:

8.gif

구현 코드:

public class MainActivity extends AppCompatActivity {
    static ByteArrayOutputStream byteOut = null;
    private Bitmap bitmap = null;
    private Button btn_cut;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btn_cut = (Button) findViewById(R.id.btn_cut);
        btn_cut.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                captureScreen();
            }
        });
    }

    public void captureScreen() {
        Runnable action = new Runnable() {
            @Override
            public void run() {
                final View contentView = getWindow().getDecorView();
                try{
                    Log.e("HEHE",contentView.getHeight()+":"+contentView.getWidth());
                    bitmap = Bitmap.createBitmap(contentView.getWidth(),
                            contentView.getHeight(), Bitmap.Config.ARGB_4444);
                    contentView.draw(new Canvas(bitmap));
                    ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
                    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteOut);
                    savePic(bitmap, "sdcard/short.png");
                }catch (Exception e){e.printStackTrace();}
                finally {
                    try{
                        if (null != byteOut)
                            byteOut.close();
                        if (null != bitmap && !bitmap.isRecycled()) {
//                            bitmap.recycle();
                            bitmap = null;
                        }
                    }catch (IOException e){e.printStackTrace();}

                }
            }
        };
        try {
            action.run();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void savePic(Bitmap b, String strFileName) {
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(strFileName);
            if (null != fos) {
                boolean success= b.compress(Bitmap.CompressFormat.PNG, 100, fos);
                fos.flush();
                fos.close();
                if(success)
                    Toast.makeText(MainActivity.this, "截屏成功", Toast.LENGTH_SHORT).show();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

코드 분석:

코드는 매우 간단합니다. final View contentView = getWindow().getDecorView(); 이 코드는 현재 XML을 가져오는 것입니다. 루트 노드의 모습! 그런 다음 스크린샷의 크기를 설정하고 contentView.draw(new Canvas(bitmap))를 호출한 다음 OK를 클릭하세요. 비트맵이 스트림으로 변환된 후 SD 카드에 기록됩니다~ 물론 스크린샷에는 수정된 APP의 내용만 캡처된 것도 알 수 있습니다! 전체 화면을 캡쳐하고 싶다면 구글에서 직접~!


이 섹션 요약:

이 섹션에서는 Bitmap, BitmapFactory 및 해당 정적 내부 클래스 Options와 BitmapDrawable에 대해 설명합니다. 실제로 기본적인 사용을 위해서는 Bitmap을 생성하는 방법만 알면 됩니다. 그 확장은 일반적으로 Matrix와 Canvas를 통해 구현됩니다. Bitmap, 우리는 OOM 문제에 더 주의를 기울입니다. 다음 섹션에서는 Bitmap의 OOM 문제를 피하는 방법을 배우겠습니다! 감사합니다~9.gif