외부이미지 나인패치 적용하기


해상도가 다양한 안드로이드는 배너영역의 이미지를 폰별로 최적화 하기는 힘들다. 그래서 고안된것이 디바이스별로 다양한 배너이미지를 만들어 폰 해상도에 따라 최적화된 이미지를 내려주는 방법(애드몹)도 쓰지만 정확하게 맞추기는 힘들고 관리하기도 힘들다.

이런 문제점을 안드로이드의 나인패치기능을 통해 조금이라도 해결가능하다. 예를들면 다음과 같은 결과를 얻을 수 있다.

원본 광고

나인패치(양옆으로만 늘리기)

나인패치(4개의 영역으로 균등하기 늘리기)

  • 공고이미지는 저랑 아무런 관계가 없으며 예시를 위해 사용된것뿐임.

직접 구현하기

안드로이드의 나인패치 이미지를 내부 리소스뿐만 아니라 외부이미지에 대해서도 적용이 가능하다. 외부이미지인 즉, 앱 내부에 리소스가 아닌 웹URL을 통해 가져온 이미지나 폰 내부에 있는 이미지도 나인패치를 체크해서 NinePatchDrawable로 만들 수 있다.

안드로이드 소소코드에서 Bitmap.java를 보면 decodeFile()메서드에서 나인패치영역을 저장하고 있으며, getNinePatchChunk()메서드를 통해서 나인패치가 적용된 이미지인지를 확인 할 수 있다.

그렇기 때문에 getNinePatchChunk()에 값이 있다면, Bitmap을 NinePathDrawable로 사용하여 나인패치가 적용가능하다. 

다음은 decodeFile()메서드 내부에 나인패치영역을 가져오는 loadNinePatchChunk()메서드이다. png파일을 체크 후 나인패치영역을 bytep[]로 변환해 주도록 구현되어 있다.

private static final byte[] loadNinePatchChunk(String name) {
    InputStream stream = name.getClass().getResourceAsStream(name);
    if (stream == null) {
        return null;
    }
    try {
        IntReader reader = new IntReader(stream, true);
        // check PNG signature
        if (reader.readInt() != 0x89504e47 || reader.readInt() != 0x0D0A1A0A) {
            return null;
        }
        while (true) {
            int size = reader.readInt();
            int type = reader.readInt();
            // check for nine patch chunk type (npTc)
            if (type != 0x6E705463) {
                reader.skip(size + 4/* crc */);
                continue;
            }
            return reader.readByteArray(size);
        }
    } catch (IOException e) {
        return null;
    }
}

NinePatchDrawable의 생성자를 보면 byte[] chunk가 있는데, Bitmap의 loadNinePatchChunk()메서드에서 가져온 chunk를 넘기면 나인패치이미지로 변환된다.

InputStream stream = .. //whatever
Bitmap bitmap = BitmapFactory.decodeStream(stream);
byte[] chunk = bitmap.getNinePatchChunk();
boolean result = NinePatch.isNinePatchChunk(chunk);
NinePatchDrawable patchy = new NinePatchDrawable(bitmap, chunk, new Rect(), null);

위와 같은 코드를 통해 Bitmap이미지에서 NinePatchDrawable로 변형하여 나인패치가 적용된 이미지를 사용 할 수 있게 된다.

*주의할점은 외부 이미지는 컴파일된 파일이어야 한다. 컴파일 방법은 http://forum.xda-developers.com/showthread.php?t=785012 를 참고하자.