[Android] Palette로 이미지에서 평균색 알아내기 (Java)

th.k·2021년 1월 10일
1

Android

목록 보기
3/8

java - How can I get the average colour of an image - Stack Overflow
구글 검색 결과 최상단에 뜨는 이미지에서 어떻게 평균색을 알아낼 수 있냐는 스택오버플로우 질문...

이미지에서 평균색을 알아내서 평균 색의 밝기에 따라 UI의 색상을 변경하는 걸 구현할 일이 있었다.
그래서 구글에 검색하니까 바로 최상단에 바로 내가 원하는 스택 오버플로우 질문이 있길래 바로 읽었는데, 가장 높은 투표를 받은 답변의 코드가 뭔가... 뭔가가 찜찜했다...
댓글에서도 for문의 루프를 지적하고 있길래 좀 쓰기가 싫어서 답변을 쭉 보다가 Palette라는걸 써보라고 하는 답변을 보고 찾아보게 되었다.

Palette

(공식)Palette
이미지에서 특정 색상을 추출 할 수 있는 기능을 가진 라이브러리이다.

(공식)Palette API로 색상 선택
써볼려고 문서를 찾아봤는데 음.. 일단 공식 문서에서 Support Library로 Palette를 추가하는 방법이 나와있고, 내가 원하는 "평균색 얻기"에 대한 내용은 가이드에 써있지 않길래 정리를 해야겠다고 생각했다.

사용하기

gradle(App)에 추가

공식 문서를 영문으로 봐도 AndroidX 라이브러리로 gradle에 추가하는 안내는 없는 것 같아서 때려맞춰서 적어봤는데 잘됐다.
왜 안내가 없는지는... 모르겠다...

dependencies {
    implementation 'androidx.palette:palette:1.0.0'   
}

일반적인 사용

먼저, Bitmap으로부터 Palette.Builder를 만들어내야 한다.

Palette.from(bitmap);

그리고 Palette.Builder에서 Palette를 만들어내야 하는데, 동기식과 비동기식을 선택할 수 있다.
보통 비동기식을 추천하는 것 같다.

// 동기식
Palette myPalette = Palette.from(bitmap).generate();

// 비동기식
Palette.from(bitmap).generate(new Palette.PaletteAsyncListener() {
    @Override
    public void onGenerated(@Nullable Palette palette) {
    
         // palette가 만들어졌을 때 하고싶은 것...
      
    }
});

Palette.PaletteAsyncListener를 사용하면 자동으로 onGenerated(@Nullable Palette palette)가 추가된다.

@Override
public void onGenerated(@Nullable Palette palette) {
    
    // 원하는 Swatch 얻기
    Palette.Swatch dominantSwatch = palette.getDominantSwatch();
    
    // rgb값 얻기
    int dominantRgb = dominantSwatch.getRgb();
      
}

파라미터로 넘어오는 palette를 사용해서 원하는 색상을 추출할 수 있는데, 밝은거 어두운거 어쩌구 저쩌구는 위에있는 공식 가이드 문서에서 안내하고있으니까 적지 않는다.

구체적인 색상값을 가져오기 전에 Swatch라는걸 가져와야한다.
그리고 나는 평균색을 가져오고 싶으니까 dominant한 색의 정보를 가지고 있는 Swatch를 가져온다.
그리고 얻어온 Swatch에서 여러 구체적인 값을 얻을 수 있다.

근데 사실 dominant한 색이라는게 정확히 평균색은 아닌 것 같다? 사전에 단어를 검색해봤을 때 "우세한" 이라는 뜻인걸 봐서 평균색은 아닌 것 같다..
그래도 내가 원하는대로 작동을 하고 있어서 상관 없이 쓰고 있다.

Glide랑 사용

아무래도 사진을 Glide로 받는 경우가 많을 듯...
Glide의 타겟으로 BitmapImageViewTarget을 사용하면 된다.

Glide.with(context)
     .asBitmap()
     .load("someUrl")
     .into(new BitmapImageViewTarget(imageView) {
         @Override
         public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
            super.onResourceReady(resource, transition);
             
            // 파라미터로 넘어오는 Bitmap resource를 사용해서 Palette 생성
            Palette.from(resource).generate(new Palette.PaletteAsyncListener() {
                @Override
                public void onGenerated(@Nullable Palette palette) {
    
                    // palette가 만들어졌을 때 하고싶은 것...
      
                }
            });
         }
     });

이미지 bitmap이 다 다운되었을 때 호출되는 onResourceReady안에 Palette를 만드는 코드를 써주면 된다.

근데 BitmapImageViewTargetImageView 객체를 넘기도록 되어있는데, 다운받아진 이미지가 ImageView 객체에 들어가지는 않았다...
그래서 준비된 resourceImageView 객체에 따로 세팅해줬다.

+이미지 밝기 판별

(공식)ColorUtils
이미지 밝기 판별하는 코드도 찾아봤었는데, 가장 많은 추천을 받은 답변에 쓰인 방법이 내 프로젝트의 최소 API 레벨하고 맞지 않았다...
그래서 더 보니까 ColorUtils를 사용하면 한줄로 처리할 수 있었다.

private boolean isImageDark(int rbg) {
    // 반환된 밝기 값이 0.5보다 작으면 어두운거라고 한다...
    return ColorUtils.calculateLuminance(rgb) < 0.5;
}

이런건 직접 for문을 돌려가면서 구현하고싶지 않다는 나의 절박함...
역시 누가 만들어놨을 줄 알았어

profile
고생끝에롹이온다

0개의 댓글