이미지 다운로드 크기 줄이기

다운로드 트래픽은 대부분 이미지로 구성됩니다. 그 결과 다운로드 가능한 이미지를 작게 만들수록 앱에서 사용자에게 제공할 수 있는 네트워크 환경이 더 좋아집니다. 이 페이지에서는 이미지 파일을 더 작고 네트워크 친화적으로 만드는 방법에 관해 안내합니다.

이미지 형식 정보

Android 앱은 일반적으로 AVIF, PNG, JPG, WebP 파일 형식 중 하나 이상의 이미지를 사용합니다. 이러한 형식별로 이미지 크기를 줄이기 위해 취할 수 있는 단계가 있습니다.

AVIF

Android 12(API 수준 31) 이상에서는 AV1 이미지 파일 형식(AVIF)을 사용하는 이미지를 지원합니다. AVIF는 AV1을 사용하여 인코딩된 이미지 및 이미지 시퀀스의 컨테이너 형식입니다. 동영상 압축에서 프레임 내 인코딩 콘텐츠를 활용합니다. 이렇게 하면 JPEG와 같은 기존 이미지 형식과 비교할 때 동일한 파일 크기의 이미지 품질이 크게 향상됩니다. 이 형식의 장점에 관한 자세한 내용은 제이크 아치볼드의 블로그 게시물을 참고하세요.

PNG

PNG 파일을 작게 만드는 비결은 이미지를 구성하는 픽셀의 각 행에 사용되는 고유한 색상 수를 줄이는 것입니다. 더 적은 색상을 사용하면 파이프라인의 다른 모든 단계에서 압축 가능성이 향상됩니다.

고유한 색상 수를 줄이면 상당한 차이가 생깁니다. 왜냐하면 PNG 압축 효과는 부분적으로는 수평으로 인접한 픽셀 색상이 얼마나 다양한지에 달려 있기 때문입니다. 따라서 PNG 이미지의 각 행에서 고유한 색상 수를 줄이면 파일 크기를 줄일 수 있습니다.

이 전략을 추구할지 판단할 때, 고유한 색상 수를 효과적으로 줄이면 이미지에 손실(lossy) 인코딩 단계를 적용하게 된다는 점을 명심해야 합니다. 그러나 인코딩 도구는 겉보기에는 작은 오류가 사람의 눈에 얼마나 심각하게 보일지 판단하는 데 적합하지 않을 수 있습니다. 따라서 효율적인 압축과 허용되는 이미지 품질 사이에 적절한 균형을 이루기 위해 이 작업을 수동으로 실행해야 합니다.

특히 유용한 두 가지 접근 방식을 취할 수 있습니다. 색인이 생성된 형식을 사용하는 것과 벡터 양자화를 적용하는 것입니다.

색인이 생성된 형식 사용

색상 줄이기를 시도할 때는 이미지를 PNG로 내보낼 때 색인이 생성된 형식을 사용할 수 있도록 색상을 최적화하는 것부터 시작해야 합니다. 색인이 생성된 색상 모드는 사용할 최상의 256색을 선택하고 픽셀 값을 모두 색상 팔레트의 색인으로 교체하여 작동합니다. 그 결과 색상이 잠재적인 1,600만 개에서 단 256개로, 픽셀당 3바이트(투명도 없음) 또는 4바이트(투명도 있음)에서 픽셀당 1바이트로 줄어듭니다. 이러한 변경은 파일 크기 줄이기의 중요한 첫 단계입니다.

그림 1은 원본 이미지와 색인이 생성된 이미지를 예로 보여줍니다.

그림 1. 색인이 생성된 형식으로 변환하기 이전과 이후 이미지

그림 2는 그림 1 이미지의 색상 팔레트를 보여줍니다.

그림 2. 그림 1 이미지의 색상 팔레트

이미지를 팔레트화된 이미지로 표현하면 파일 크기를 크게 개선하는 데 도움이 되므로 대부분의 이미지를 변환할 수 있는지 알아보는 것이 좋습니다.

물론 모든 이미지를 단 256가지 색상으로 정확히 표현할 수는 없습니다. 예를 들어 일부 이미지는 올바르게 표현하려면 257, 310, 512 또는 912가지 색상이 필요할 수 있습니다. 이러한 경우에는 벡터 양자화도 도움이 될 수 있습니다.

벡터 양자화

색인이 생성된 이미지를 만드는 프로세스는 벡터 양자화(VQ)로 더 잘 설명할 수 있습니다. VQ는 다차원 숫자의 반올림 프로세스 역할을 합니다. 이 프로세스에서 이미지의 색상은 모두 유사도에 기반해 그룹화됩니다. 주어진 그룹에서 그룹의 모든 색상은 단일 중심점 값으로 교체되어 셀(Voronoi 용어를 사용하는 경우 '사이트')의 색상 오류를 최소화합니다. 그림 3에서 녹색 점은 입력 색상을 표현하고 빨간색 점은 입력 색상을 대체하는 중심점입니다. 각 셀은 파란색 선으로 경계가 그어져 있습니다.

그림 3. 이미지 색상에 벡터 양자화 적용

VQ를 이미지에 적용하면 고유한 색상 수가 줄어들어 각 색상 그룹이 시각적 품질 면에서 '상당히 근접한' 단일 색상으로 대체됩니다.

이 기법을 사용하면 이미지의 최대 고유 색상 수를 정의할 수도 있습니다. 예를 들어 그림 4는 1,670만 색상(픽셀당 24비트)으로 표현된 앵무새 머리와 고유한 색상 16(3bpp)가지만 사용할 수 있는 버전을 보여줍니다.

그림 4. 벡터 정량화 적용 이전과 이후 이미지

품질 손실을 바로 알 수 있습니다. 그라디언트 색상이 대부분 교체되어 이미지에 밴딩 효과를 줍니다. 이 이미지에는 16개를 초과하는 고유한 색상이 필요합니다.

파이프라인에서 VQ 단계를 설정하면 이미지에서 사용하는 고유한 색상의 실제 수를 더 잘 파악하고 그 수를 크게 줄일 수 있습니다. 이 기법을 구현하는 데 바로 사용할 수 있는 여러 도구가 있습니다.

JPG

JPG 이미지를 사용하는 경우 조금만 변경해도 파일 크기를 많이 줄일 수 있는 방법들이 있습니다. 예를 들면 다음과 같습니다.

  • 다양한 인코딩 메서드를 이용해 품질에 영향을 주지 않으면서 더 작은 파일 크기를 생성합니다.
  • 더 나은 압축을 만들기 위해 품질을 약간 조정합니다.

이러한 전략을 추구하면 파일 크기를 종종 최대 25% 줄일 수 있습니다.

도구를 선택할 때 사진 내보내기 도구는 GPS 정보와 같은 불필요한 메타데이터를 이미지에 삽입할 수 있다는 것을 기억하세요. 최소한 기존 도구를 활용하여 파일에서 이 정보를 삭제합니다.

WebP

WebP는 Android 4.2.1(API 수준 17)에서 지원되는 최신 이미지 형식입니다. 이 형식은 웹상의 이미지에 뛰어난 무손실 및 손실(lossy) 압축을 제공합니다. WebP를 사용하여 개발자는 더 작고 풍부한 이미지를 만들 수 있습니다. WebP 무손실 이미지 파일은 평균적으로 PNG보다 26% 더 작습니다. 또한 이러한 이미지 파일은 22% 더 많은 바이트 비용만으로 투명도(알파 채널이라고도 함)를 지원합니다.

WebP 손실(lossy) 이미지는 동등한 SSIM 품질 색인에서 비슷한 JPG 이미지보다 25~34% 더 작습니다. 손실(lossy) RGB 압축이 허용되는 경우 손실(lossy) WebP는 투명도도 지원하여 일반적으로 PNG보다 3배 작은 파일 크기를 생성합니다.

WebP에 관한 자세한 내용은 WebP 사이트를 참고하세요.

Android 스튜디오를 사용하여 기존 BMP, JPG, PNG 또는 정적 GIF 이미지를 WebP 형식으로 변환할 수 있습니다. 자세한 내용은 Android 스튜디오를 사용하여 WebP 이미지 만들기를 참고하세요.

형식 선택

다양한 이미지 유형에 적합한 다양한 이미지 형식이 있습니다. JPG와 PNG는 압축 프로세스가 매우 달라서 그 결과도 상당히 다릅니다.

PNG와 JPG 사이의 판단은 결국 이미지 자체의 복잡성에 달린 경우가 많습니다. 그림 5는 개발자가 적용하는 압축 방식에 따라 매우 다르게 표현되는 두 이미지를 보여줍니다. 왼쪽 이미지는 작은 세부사항이 많으므로 JPG를 사용하면 더 효율적으로 압축됩니다. 오른쪽 이미지는 같은 색상이 연속되므로 PNG를 사용하면 더 효율적으로 압축됩니다.

그림 5. JPG에 적합한 사례와 PNG에 적합한 사례

WebP 형식은 손실(lossy) 모드와 무손실 모드를 모두 지원할 수 있으므로 PNG와 JPG 두 가지를 모두 이상적으로 대체합니다. 한 가지 기억해야 할 점은 Android 4.2.1(API 수준 17) 이상을 실행하는 기기에서 네이티브 지원만 있다는 것입니다. 다행히 대부분의 기기는 이러한 요구사항을 충족합니다.

그림 6은 사용할 압축 체계를 결정하는 데 도움이 되는 간단한 시각화를 제공합니다.

그림 6. 압축 방식 판단

최적의 품질 값 판단

압축과 이미지 품질 사이에 적절한 균형을 이루는 데 사용할 수 있는 여러 기법이 있습니다. 한 가지 기법은 스칼라 값을 사용하므로 JPG와 WebP에서만 작동합니다. 다른 기법은 Butteraugli 라이브러리를 활용하고 모든 이미지 형식에 사용할 수 있습니다.

스칼라 값(JPG 및 WebP에만 적용)

JPG와 WebP의 장점은 스칼라 값을 사용하여 파일 크기와 품질의 균형을 이룰 수 있다는 사실입니다. 비결은 이미지에 맞는 올바른 품질 값을 찾아내는 것입니다. 품질 수준이 너무 낮으면 작은 파일을 만들지만 이미지 품질은 떨어집니다. 품질 수준이 너무 높으면 파일 크기가 커지며 사용자에게 뚜렷한 이점도 제공하지 않습니다.

가장 간단한 솔루션은 최댓값이 아닌 값을 선택하여 그 값을 사용하는 것입니다. 그러나 품질 값은 모든 이미지에 다르게 영향을 미칩니다. 예를 들어 75%의 품질은 대부분의 이미지에서 좋아 보일 수 있지만 어떤 경우에는 좋아 보이지 않을 수 있습니다. 대표 이미지 샘플에 선택한 최댓값을 테스트해야 합니다. 또한 압축된 버전이 아닌 원본 이미지에 모든 테스트를 실행해야 합니다.

하루에 JPG를 수백만 개 업로드하고 다시 전송하는 대용량 미디어 애플리케이션의 경우 각 애셋의 수동 미세 조정은 비실용적입니다. 이미지 카테고리에 따라 여러 다양한 품질 수준을 지정하여 이 문제를 해결할 수 있습니다. 예를 들어 작은 이미지가 더 많은 압축 아티팩트를 숨기므로 썸네일의 품질 설정으로 35%를 설정할 수 있습니다.

Butteraugli

Butteraugli 프로젝트는 이미지의 Psychovisual 오류 임계값(뷰어가 이미지 품질 저하를 알아채기 시작하는 지점)을 테스트하는 라이브러리입니다. 즉, 이 프로젝트는 압축된 이미지의 왜곡된 정도를 정량화하려고 시도합니다.

Butteraugli를 사용하면 시각적 품질 목표를 정의한 다음 PNG, JPG, WebP 손실(lossy) 압축 및 WebP 무손실 압축을 실행할 수 있습니다. 그런 다음 파일 크기와 Butteraugli 수준의 균형이 가장 좋은 이미지를 선택할 수 있습니다. 그림 7은 사용자가 문제를 인식할 수 있을 만큼 시각적 왜곡이 심해지기 전에 Butteraugli를 사용하여 최소 JPG 품질 수준을 찾는 방법의 예를 보여줍니다. 결과는 파일 크기의 약 65% 감소입니다.

그림 7. Butteraugli 기술 적용 이전과 이후 이미지

Butteraugli를 사용하면 출력 또는 입력에 기반해 진행할 수 있습니다. 즉, 사용자가 결과 이미지에서 눈에 띄는 왜곡을 인식하기 전에 가장 낮은 품질 설정을 찾거나 이미지 왜곡 수준을 반복적으로 설정하여 연결된 품질 수준을 알 수 있습니다.

크기 제공

서버에 단일 해상도의 이미지만 유지하는 것은 솔깃한 일입니다. 기기에서 이미지에 액세스하면 서버는 하나의 해상도로 이미지를 제공하고 이미지 축소는 기기에 맡깁니다.

이 솔루션은 개발자에게 편리하지만 사용자에게는 고통스러울 수 있습니다. 이 솔루션으로 사용자가 필요한 것보다 훨씬 많은 데이터를 다운로드해야 하기 때문입니다. 대신 다양한 크기의 이미지를 저장하여 특정 사용 사례에 가장 적합한 크기를 제공해야 합니다. 예를 들어 썸네일의 경우 원본 크기 버전을 제공 및 축소하는 대신 실제 썸네일 이미지를 제공하면 훨씬 적은 네트워크 대역폭이 소비됩니다.

이 접근 방식은 다운로드 속도에 도움이 되고 데이터 전송량에 제한이 있는 데이터 요금제를 이용하는 사용자에게 비용 부담이 적습니다. 또한 이미지가 기기 및 기본 메모리에서 차지하는 공간도 줄어듭니다. 4K와 같이 큰 이미지의 경우 이 접근법을 사용하면 이미지를 로드하기 전에 기기에서 크기를 조절하지 않아도 됩니다.

이 접근법을 구현하려면 올바른 캐싱으로 다양한 해상도의 이미지를 제공하는 백엔드 이미지 서비스가 있어야 합니다. 작업에 도움을 줄 수 있는 기존 서비스가 있습니다. 예를 들어 App Engine에는 이미지 크기 조절 기능이 이미 설치되어 있습니다.