Electron에서 로컬 이미지 파일 보기

17381 단어 Electron

개요



Electron의 응용 프로그램을 개발하는 동안 내장 이미지를 보려고 할 때 "Not allowed to load local resource"라는 오류가 발생했으므로 그 조치를 기록해 둡니다.

패키지화하면 대책을 치지 않아도 이미지가 표시될 수 있습니다.
검증하면 나중에 추기한다고 생각합니다.

결론부터 말하면, file 프로토콜을 그만두고, <img src="data:image/png;base64,<画像をbase64化した文字列>"/> 를 사용해 해결했습니다.

상대 경로에서의 지정 문제(다른 문제가 발생하기 때문에, 후술하는 대책을 실시)



Electron 앱은 React를 사용하고 create-react-app로 만든 앱으로 Electron화한 것입니다.

index.html 옆에 logo.png를 넣고 태그에서 <img src="../build/logo.png"/>로 표시하려고했습니다.

이미지는 웹 앱으로 표시되지만 Electron에서는 src="file:///build/logo.png"가 되어 절대 경로로 검색하게 됩니다.

이 대책으로서, 이하의 사이트를 참고로, protocol.interceptFileProtocol 라고 하는 API로, "file:///%RELATIVE_PATH%"(RELATIVE_PATH는 매직워드)로 시작되고 있으면, 상대 패스로서 핸들 하도록 구현했습니다.

  • Electron에서 절대 경로의 기준점을 애플리케이션이 있는 디렉토리로 설정
    htps : // 이 m / 츠치 에에 / 있어 ms / 4123784 f1 에 b68 아 1d3925

  • img 태그의 지정은, <img src="%RELATIVE_PATH%../build/logo.png" /> 라고 해, 소스는 이런 느낌입니다.
    protocol.interceptFileProtocol('file', (req, callback) => {
        const requestedUrl = req.url.substr(7);
    
        if (path.startsWith("/%RELATIVE_PATh%") {
          callback(path.normalize(path.join(__dirname, requestedUrl.substring("/%RELATIVE_PATh%".length)));
        } else {
          callback(requestedUrl);
        }
    

    이 대책은 Mac에서는 작동했지만 Windows에서는 "Not allowed to load local resource"라는 오류가 발생하여 작동하지 않았습니다.

    Not allowed to load local resource 대책(해결됨)



    Google에서 몇 가지 조사했지만, Websecurity를 ​​Off로 하는, create-react-app를 eject(비가역의 조작으로, create-react-app의 장점이 없어진다)하거나, webpack의 컨피그를 바꾸는 등이라고 하는 것 그래서 적용해도 효과가 없었습니다.
  • 가장 유효해 보였던 해결책(Websecurity를 ​​Off로 한다)
    htps : // 기주 b. 코 m / 에 ct 론 / 에 ct 론 / 이스에 s / 5107 # 이스에 코멘 t-299971806
  • Webpack의 설정 변경
    htps : // 기주 b. 코 m / 에ct 론 / 에 ct 론 / 이스에 s / 5107

  • 결국은, 아래에 인용한 h tps : // s t c ゔ ぇ rf ぉ w. 코 m / 쿠에 s 치온 s / 50272451 / 에ぇct 론 - js - 펑크 s - f 로 m ぉ 카 l - ぃ ぇ - sys m 에 쓰여져 있듯이, file 프로토콜을 사용하고 있는 한 시큐리티를 Off로 하는 등의 해결책 밖에 없고, 문제는 해결하지 않았습니다.

    Electron by default allows local resources to be accessed by render processes only when their html files are loaded from local sources with the file://protocol for security reasons.

    If you are loading the html from any http://or https://protocol even from a local server like webpack-dev-server, access to local resources is disabled.

    If you loading html pages from a local server only during development and switching to local html files in production, you can disable websecurity during development, taking care to enable it in production.

    최종 솔루션



    ` <img src="data:image/png;base64,<画像をbase64化した文字列>"/> 라는 방식으로 해결했습니다.

    해결 후 폴더 구성은 다음과 같습니다.
      build/ <= publicとsrcのビルド結果が格納される。
      public/index.html
             logo.png
      src/ ...
           libs/ImageLoader.js
           main.js <= ElectronのMainプロセスの起動ファイル
    

    해결을 위한 단계는 다음과 같습니다.
    1. main.js에서, images 폴더 이하의 png/jpg 파일을 base64화해, global의 변수에 채운다.
    2. ImageLoader.js 클래스를 만들고 src에 전달할 문자열을 생성합니다.
    3. jsx에서 img 태그에 step2로 생성 된 문자열을 전달합니다.

    소스는 다음과 같습니다.
  • 이미지 파일을 수사, global 맵에 채우는 곳까지.

  • main.js
    const {app, BrowserWindow, ipcMain} = require('electron')
    const path = require('path')
    const url = require('url')
    const fs = require('fs')
    const info = {
      win: null,
      images: {}
    }
    
    global.info = info
    
    let win
    function createWindow () {
      win = new BrowserWindow({width: 800, height: 600, resizable:true})
      info.win = win
    
      // images以下のフォルダを捜査
      const files = fs.readdirSync(path.join(__dirname, '/../build/images'))
      files.forEach((file)=>{
        const ext = path.extname(file)
        if(ext === '.png' || ext === '.jpg') {
          const binary = fs.readFileSync(path.join(__dirname, '/../build/images/' + file))
          // base64化
          const base64data = new Buffer(binary).toString('base64')
          // マップに詰める
          info.images[file] = {
            type: ext.substring(1),
            name: file,
            data: base64data
          }
        }
      })
      // 通常のElectronのメイン処理
      win.loadURL(url.format({
        pathname: path.join(__dirname, '/../build/index.html'),
        protocol: 'file:',
        slashes: true
      }))
      // 以下省略・・・
    
  • ImageLoader.js(글로벌 맵에서 data:image/png,base64,... 를 생성)

  • ImageLoader.js
    const electron = window.require('electron')
    //globalを取得するには、electron.remoteで取得する
    const remote = electron.remote
    
    class ImageLoader {
      static loadSrc = (imagePath) => {
        const info = remote.getGlobal('info')
        const image = info.images[imagePath]
        for(let key in info.images) {
          console.log(key + " " + info.images[key].type + " " + info.images[key].name)
        }
        if(image === undefined)
          return "image not found"
        // data:image/<png|jpg>;base64,<base64 encoded data>の生成
        return `data:image/${image.type};base64,${image.data}`
      }
    }
    
    export default ImageLoader
    
  • 이미지를 표시하는 곳

  • App.jsx
    import React from 'react'
    import ImageLoader from '../libs/ImageLoader'
    /* アプリケーション画面の定義 */
    const App = () => (
      <div>
        <img src={ImageLoader.loadSrc('logo.png')} height="64px" width="64px"/>
      // 以下省略・・・
    

    사이고에게



    대책의 비망록으로 기재하고 있습니다.
    다른 방법도 있을지도 모르기 때문에, 아시면 알려 주시면 다행입니다.

    좋은 웹페이지 즐겨찾기