관리 메뉴

나만을 위한 블로그

[Android] dataUrl이란? 웹뷰로 dataUrl 전송하는 법 본문

Android

[Android] dataUrl이란? 웹뷰로 dataUrl 전송하는 법

참깨빵위에참깨빵 2023. 3. 25. 23:17
728x90
반응형

웹뷰로 이미지를 전송해야 할 일이 생겼다. 그 방법으로 dataUrl이 나왔는데, 처리는 했지만 dataUrl이 뭔지 모르니 알아본다.

 

https://en.wikipedia.org/wiki/Data_URI_scheme

 

data URI scheme - Wikipedia

From Wikipedia, the free encyclopedia Web page in-line data scheme The data URI scheme is a uniform resource identifier (URI) scheme that provides a way to include data in-line in Web pages as if they were external resources. It is a form of file literal o

en.wikipedia.org

data URI 체계는 외부 리소스인 것처럼 웹 페이지에 인라인 데이터를 포함하는 방법을 제공하는 URI(Uniform Resource Identifier) 체계다. 파일 리터럴 또는 here document의 형식이다. 이 기술을 쓰면 일반적으로 이미지, 스타일 시트 같은 별도 요소를 단일 HTTP 요청으로 가져올 수 있다. 이는 여러 HTTP 요청보다 효율적일 수 있으며 이미지를 패키징하기 위해 여러 브라우저 확장에서 쓰인다. 2022년부터 데이터 URI는 대부분의 주요 브라우저에서 완전 지원되며 인터넷 익스플로러에서 부분 지원된다
data URI의 구문은 98년 8월에 게시된 RFC에 정의돼 있고 URI 체계 구문을 따른다. 데이터 URI는 다음으로 구성된다

data:[<media type>][;base64],<data>

data 뒤에 콜론이 붙고, 이어서 선택적 media type이 붙는다. media type 부분은 속성=값 형식으로 세미콜론으로 구분된 하나 이상의 매개변수를 포함할 수 있다. 일반적인 media type 매개변수는 media type의 문자 집합을 지정하는 charset이고 여기서 값은 문자 집합 이름의 IANA 목록에서 가져온다. 지정되지 않았으면 data URI의 media type은 text/plain;charset=US-ASCII로 간주된다
선택적 base64 확장 base64는 이전 부분과 세미콜론으로 구분된다. 존재하는 경우 URI의 데이터 컨텐츠가 바이너리 텍스트 인코딩을 위한 Base64 체계를 써서 아스키 타입으로 인코딩된 바이너리 데이터임을 나타낸다. base64 확장은 "=value" 구성요소가 없고 모든 media type 매개변수 뒤에 오는 점에서 모든 media type 매개변수와 구별된다. Base64로 인코딩된 데이터는 원본 데이터보다 약 33% 크기 때문에 서버에서 HTTP 압축을 지원하거나 포함된 파일이 1KB 미만인 경우에만 Base64 data URI를 쓰는 게 좋다...(중략)

 

https://developer.mozilla.org/ko/docs/Web/HTTP/Basics_of_HTTP/Data_URLs

 

데이터 URIs - HTTP | MDN

Data URIs, data: 스킴이 접두어로 붙은 URL은 컨텐츠 작성자가 작은 파일을 문서 내에 인라인으로 삽입할 수 있도록 해줍니다.

developer.mozilla.org

"data:" 스킴이 접두어로 붙은 URL. 컨텐츠 작성자가 적은 파일을 문서 안에 인라인으로 작성할 수 있게 해준다. Data URIs는 접두사(data:), 데이터 타입을 가리키는 MIME 타입, 텍스트가 아닌 경우 사용될 부가적인 base64 토큰, 데이터 자체의 총 4가지 부분으로 구성된다

data:[<mediaType>][;base64],<data>

mediaType이란 MIME 타입을 말한다. JPEG 이미지의 경우 'image/jpeg'다. 생략된다면 기본값으로 text/plain;charset-US-ASCII가 사용된다. 데이터가 텍스트인 경우 단순히 텍스트를(포함된 문서 유형에 따라 적합한 엔티티 혹은 이스케이프를 써서) 임베드할 수 있다. 그게 아니면 base64로 인코딩된 바이너리 데이터를 임베드하기 위해 base64를 지정할 수 있다

 

아래는 위 MDN 사이트에서 제공하는 브라우저 호환성 표다. 안드로이드 웹뷰를 제외한 다른 브라우저에선 모두 지원하는 걸 볼 수 있다.

 

 

dataUrl이란 접두사로 "data:"가 붙어 있는 URL로, 데이터를 URI 형식의 문자열로 표현하는 방법이다. 인터넷 어딘가에 있는 리소스를 참조하는 게 아니라 자신이 데이터를 갖고 있기 때문에 웹 브라우저 등의 클라이언트에서 데이터를 즉시 사용할 수 있다.
이 dataUrl은 아래 경우에 사용할 수 있다.

 

  • 작은 이미지 등의 파일을 웹 페이지에 포함할 때 : 외부 리소스에 대한 추가 요청을 줄일 수 있어 성능이 향상될 수 있음
  • 인터넷 접속이 제한된 환경에서 데이터를 사용할 때
  • 개인 정보, 암호화된 데이터를 클라이언트에서 처리할 때 : 서버에 데이터를 보내지 않고 클라이언트 측에서만 쓸 수 있게 데이터를 처리함

 

그럼 이것을 안드로이드에서 사용한다면 어떻게 사용할 수 있는가? 서두에서 말한 것처럼 웹뷰로 어떤 이미지의 dataUrl을 보내야 한다면 아래의 시나리오를 갖는 로직을 만들 수 있다.

 

  1. 이미지의 dataUrl을 구한다
  2. evaluateJavascript()를 통해 웹뷰 함수를 실행한다

 

이미지를 다루면서 Bitmap을 사용하고 있고, 코루틴을 사용하려면 아래와 같이 처리할 수 있다.

 

import android.graphics.BitmapFactory
import android.os.Bundle
import android.util.Base64
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.ByteArrayOutputStream
import java.io.File

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val imagePath = "파일 경로 입력"
        CoroutineScope(Dispatchers.Main).launch {
            val dataUrl = getFileImageDataUrl(imagePath)
            // dataUrl을 사용하는 로직 추가
        }
    }

    private suspend fun getFileImageDataUrl(imagePath: String): String = withContext(Dispatchers.IO) {
        val bitmap = BitmapFactory.decodeFile(imagePath)

        // Bitmap을 Base64 인코딩
        val baos = ByteArrayOutputStream()
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos)
        val imageBytes = baos.toByteArray()

        // Base64로 인코딩된 데이터를 Data URL 타입으로 변환
        "data:image/jpeg;base64,${Base64.encodeToString(imageBytes, Base64.DEFAULT)}"
    }
}

 

이미 File 객체에 이미지를 담아 두고 있다면 File 객체의 absolutePath를 써서 파일이 위치한 절대 경로를 얻어와서 이미지 파일을 읽고 처리할 수 있다. 안드로이드면 "storage/emulated/0/DCIM/Camera/IMG_2022...121.jpg" 형식의 경로일 수 있다. 이것을 위 코드의 onCreate() 안의 imagePath 변수에 넣어서 사용할 수 있다. 이것을 웹뷰 함수에 문자열 그대로 넣어서 보낼 수도 있겠지만 JSON으로 처리해 보내면 좀 더 빨리 보낼 수 있다.

추가로 imageBytes에 baos.toByteArray()를 호출한 다음 bitmap.recycle()을 써서 비트맵을 메모리에서 해제해 앱의 메모리 부족 사태를 미연에 방지할 수 있다.

 

이렇게 하면 이미지의 data Url이 만들어지는데 로그로 출력하면 너무 길어서 나오지 않을 수 있다. 이미지의 정보를 갖고 있어서 길 수밖에 없는데, 내 경우 가장 긴 data Url 문자열의 길이는 약 10만 정도였다. 이제 이걸 통해 이미지의 dataUrl을 웹뷰로 보내든 다른 처리를 하든 자유롭게 활용하자.

반응형
Comments