Tempo Di Valse

[Electron] <img> 태그에 로컬 이미지 로드하기 본문

개발/Electron

[Electron] <img> 태그에 로컬 이미지 로드하기

TempoDiValse 2022. 4. 27. 16:10

웹 페이지에서 이미지를 보여주는 것을 만든다고 하면 <img> 를 통하여 이미지를 보여준다. 그래서,

<img src="${URL}">

형식처럼 URL 을 넘겨주면 알아서 URL 의 이미지를 불러오곤 한다. 여기서 URL 은 일반 웹상에서 돌아댕기는 http 나 https Scheme 이 붙은 URL 일 수도 있고, data URI 값일 수도 있고 다양한 값으로 가져올 수 있다.

 

이 방식으로 Electron 환경에서 로컬에 있는 이미지를 부른다면, 로컬 이미지의 경로를 가지고 있기 때문에 URL 넣는 것 처럼 넣어주면 된다고 생각했을 것이다. 

 

그러나 작동하지 않는다.

 

Electron 은 보안상의 이유인 지는 몰라도 Electron 환경에 올라가진 웹 페이지 상에서는 로컬에 있는 데이터를 접근하는 것을 방지하고 있는 것 같았다. 웹 페이지에서 로컬 데이터를 접근할 때에 URL 은 file 이라는 Scheme 을 붙여준다. 그래서,

 

<img src="file://C:/Document/image1.png" />

 

이런 형식으로 해당 파일이 로컬 파일임을 알려주고 접근하도록 할 수 있는데, Electron 에서는 file 이라는 Scheme 을 허용하지 않는다. 대신에 다른 방식으로 하라고 우회를 해주고 있다.

 

그 방법은 바로 Custom Scheme 을 제작하여 사용하는 방식이다. Custom Scheme 이라고하면 컴퓨터에서 사용하는 일반적인 Scheme 이 아닌 내가 만드는 어플리케이션에서만 사용할 Scheme 을 만드는 것이다. 그래서, Scheme 적용 프로세스를 간략하게 나열 해보자면,

1. 어플리케이션에서만 사용 할 Scheme 정의
2. 이미지 경로를 Scheme 정의에 맞게 수정
3. 수정된 경로를 <img src="" /> 에 적용

그럼 이 순서대로 작업을 해보도록 하자.

 

1. Scheme 정의

 

Scheme 을 정의하기 위해서는 Electron 에 있는 protocol 이라는 API 를 이용한다. Electron 의 main 을 담당하고 있는 JS 파일에서 electron 을 import 하는 부분을 찾아서 수정을 한다.

// import { app, BrowserWindow } from 'electron' 에서, 
// 아래와 같이 protocol 을 추가한다.

import { app, BrowserWindow, protocol } from 'electron';

다음 app.whenReady() 부분을 찾아서 그 안에 protocol API 를 이용하여 Scheme 을 정의하도록 한다.

import { app, BrowserWindow, protocol } from 'electron'

// ... Codes

app.whenReady().then(() => {
    // ... Codes
    
    protocol.registerFileProtocol(${SCHEME}, (request, callback) => {
    	// input code
    })
})

protocol 의 registerFileProtocol 이라는 메소드를 통해서 Scheme 을 정의할 수 있다. ${SCHEME} 에 사용하고자 하는 Scheme 을 입력하고 등록하게 되면 Electron 상에서 파일에 접근하고 싶을 때 "${Scheme}://${PATH}" 의 형식으로 접근이 되는 것이다.

 

두번째 파라미터에서는 request 와 callback 을 받을 수 있는 Function 객체를 넣어주는데, <img> 태그에서 ${Scheme} 가 사용된 URL 을 호출하게되면 request 로 호출한 것의 정보가 불러와지고, 그 정보를 가공하여 callback 을 통해 다시 <img> 태그로 정보를 전송해주는 프로세스를 코딩할 수 있다. 그래서 이 안을 채워보면 다음처럼 할 수가 있다.

 

// Scheme 은 local 로 정의 하였으며, 태그에서의 사용은 "local://" 으로 사용한다.

protocol.registerFileProtocol('local', (request, callback) => {
    // 한글이나 기타 유니코드 글자를 사용하는 경우 문자열이 분리되는 현상이 있어 normalize 처리한다.
    const url = request.url.normalize() 
    
    // Scheme 을 삭제해서 불러올 path 만 가져오도록 한다.
    const p = url.replace("local://", "")
    
    // 가공이 없는 상태에서 Path 의 내용을 불러오는 경우에는 바로 Scheme 을 삭제한 값을 callback 에 태워 보내준다
    callback({ path: p })
})

request 를 통해서 URL 정보를 받아올 수 있었다. 받은 URL 에서 Scheme 영역만 지우게되면 나머지 데이터만 가지고 파일에 접근을 할 수 있다. 일단 예시로 작성해놓은 코드는 img 태그에서 사용하는 src 타겟이 Path 내용인 경우이다. 바로,

<img src="local://C:/Document/image.png" />

이런 형식이다. 그래서 local:// 만 지우면 C 드라이브의 Document 에 image.png 파일에 접근하게 되는거다.

 

그러나 이 방법에는 약간의 고민이 발생할 수 있다. 바로 약간의 보안성? 은닉? TMI 같은 정보? 에 대한 문제가 발생되는데, 생각해보면 굳이 내 컴퓨터에 Path 를 전부 가지고 있을 필요가 있을까 싶다. 위의 예 처럼 사용할 때, 내가 로컬 파일에 대해서 이곳저곳 거의 모든 곳을 접근하여 가져올 필요가 있을 때에는 경로 에 대한 모든 값을 가져오는게 맞을 것이다. 그러나 프로그램에서 사용하는 경로가 Document 폴더 내부로 한정되어있을 때에는 C:\Document 를 전부 다 써줄 필요가 있을까? 어차피 똑같은 경로 내에서 가져오는데 정보를 적어놓을 필요가 있을까? 생각할 수 있다.

 

2. Scheme 로직 수정

 

그런 경우라면 이렇게 사용할 수도 있을 것이다.

// Scheme 은 local 로 정의 하였으며, 태그에서의 사용은 "local://" 으로 사용한다.

protocol.registerFileProtocol('local', (request, callback) => {
    // 한글이나 기타 유니코드 글자를 사용하는 경우 문자열이 분리되는 현상이 있어 normalize 처리한다.
    const url = request.url.normalize()
    
    // Scheme 을 삭제해서 불러올 path 만 가져오도록 한다.
    const p = url.replace("local://", "")
    
    // 컴퓨터의 Documents 경로를 가져온다.
    const dir = app.getPath("documents")
    
    // 경로를 가공하여 보여준다.
    callback({ path: path.resolve(dir, p) })
})

 

가변적인 값만 가지고 있으면 고정 값은 Scheme 을 정의 한 곳에서 로직으로 커버할 수 있기 때문에 굳이 모든 경로를 쓰지 않게 할 수도 있다. 그러면 <img> 태그에서도,

<img src="local://image.png" />

이런식으로 쓰기만해도 작동이 되는 것이다.

반응형
Comments