(JavaScript) 从文件或 FileReader 对象导入外部 <object> svg

(JavaScript) Import external <object> svg from File or FileReader Object

我正在使用 Two.js,我想允许用户导入一个 svg 文件并将其显示在我的场景中。

Two.interpret() 可以获取任何 dom 包含 SVG 数据的标签,所以我创建了这个函数来模拟文件中的标签:

this.m_Two.interpretFromFile = function (two, fname) {
        //Create an object and load an svg from 'fname'
        var object = document.createElement("object");
        //Set the id to the filename without path or extension
        object.id = fname;
        object.id = object.id.replace(/\/g, '/');
        object.id = object.id.substring(object.id.lastIndexOf('/')+1, object.id.lastIndexOf('.'));
        console.log("Importing " + object.id);
        object.data = fname; //HTML takes care of the rest
        object.type = "image/svg+xml";
        object.width = 64; //Import from file maybe?
        object.height = 64;
        object.style = "visibility:hidden;position:absolute;left:0px;top:0px;";
        document.body.appendChild(object); //Add it to the body (invis) that way it loads
        //When it loads, finish up
        object.onload = function () {
            if (!object.contentDocument || object.contentDocument.getElementsByTagName("svg").length < 1) return;
            var svgObj = object.contentDocument.getElementsByTagName('svg')[0];
            var ret = two.interpret(svgObj);
            document.body.removeChild(object); //Remove it. Use path.clone to duplicate stuff..
            return ret; //Return our new svg path
        }
    };

此函数接受一个 Two 实例和一个文件 url,并且 returns 一个 two.path。

当使用控制台时,这一切工作正常,花花公子 twoInstance.interpretFromFile (twoInstance, "images/Test.svg");

但是,我 运行 这些文件在本地进行测试,我当然不指望任何人进入他们的浏览器控制台并使用该功能,已经知道文件的确切路径,也知道在该路径之前键入 "file://"... Yeesh

    document.getElementById("dWorkSpace").ondrop = function(e) {
            e.preventDefault(); //Default event loads the file itself.. KILL IT WITH FIRE.

            if (!e.dataTransfer || !e.dataTransfer.items.length > 0 || !e.dataTransfer.files[0]) return;

            var file = e.dataTransfer.files[0];

            twoInstance.interpretFromFile(twoInstance, "file://" + file.name);
    }

'file.name' 只给出文件,不给出路径(是的,我知道这在浏览器中是安全的。我已经看过所有其他关于它的问题..)

所以现在,我可以使用 FileReader 来读取 svg 文件本身,但是我如何将该数据放入标签中呢?我有时需要这种格式:

            <object data="Test.svg" type="image/svg+xml"></object>

因为 Two.js 似乎不喜欢 'svg' 标签..只是 'object' 标签..

对于这个冗长的问题,我深表歉意。如您所见,我已经陷入了这个兔子洞的深处。我试图只使用相关代码,但老实说,整个事情大得惊人,我不想 post 全部。

您必须从您的 File 对象(它只是指向用户磁盘上文件的直接指针)创建一个 BlobURL,然后将您的 <object>data 设置为此BlobURL。

在这里我将只使用一个 <input> 元素,但它与任何 Blob/File 基本相同,无论它们来自哪里(请注意,尽管 IIRC 你需要调用 getAsFile() dataTransfer 的文件中的方法。

f.onchange = e =>{
  var file = f.files[0];
  if(file.type === 'image/svg+xml'){
    var obj = document.createElement('object');
    obj.data = URL.createObjectURL(file);
    obj.onload = e => URL.revokeObjectURL(obj.data);
    document.body.appendChild(obj);
    }
  };
      
<input type="file" id="f"/>

多么快速的回答.. @guest271314(如果我以后能弄明白,我会link这个)。

这对我有用:

document.getElementById("dWorkSpace").ondrop = function(e) {
    e.preventDefault(); //Default event loads the file itself.. KILL IT WITH FIRE.

    if (!e.dataTransfer || !e.dataTransfer.items.length > 0 || !e.dataTransfer.files[0]) return;

    var file = e.dataTransfer.files[0];

    var reader = new FileReader(); //Make a reader

    reader.onloadend = function (evt) { //When the file is actually loaded
        Application.m_Two.interpretFromFile(Application.m_Two, reader.result);
    }
    reader.readAsDataURL(file);
}

更改位与 FileReader 对象有关,我使用了 readAsDataUrl 之类的 guest271314 在第一条评论中谈到。你能说我是新来的吗? xD

演示:http://jonathancrowder.com/AnimatorProject/Application.html -- 拖一个SVG文件到页面上试试看。

这是我上传 svg 图像并附加到 div 的方法,使用 atob 将 base64 字符串转换为 svg 字符串:var svg = atob(event.target.result.replace(/data:image\/svg\+xml;base64,/, ''));

我在 angular 应用程序中使用它。我为谁分忧

handleFileInput(file: FileList) {
    this.fileToUpload = file.item(0);
    var xlinkNS = "http://www.w3.org/1999/xlink";
    //Show image preview
    let reader = new FileReader();
    reader.onload = (event: any) => {

      var svg = atob(event.target.result.replace(/data:image\/svg\+xml;base64,/, ''));
      console.log(svg);

      var element = document.createElement("div");
      element.id = "svg";
      document.getElementsByClassName('svg-container')[0].innerHTML = '';
      document.getElementsByClassName('svg-container')[0].appendChild(element); 
      var newSvg = document.getElementById('svg');
      newSvg.outerHTML = svg;

    }
    reader.readAsDataURL(this.fileToUpload);
  }

HTML

<div class="svg-container">
        <div id="svg"></div>
    </div>
    <div class="image-upload">
        <label (click)='inputClick(Image)'>
            <img src="image/upload.png" />
        </label>

        <input #Image type="file" (change)="handleFileInput($event.target.files)"/>
        <button type="submit" class="btn-large btn-submit" [disabled]="Image.value=='' || !imageForm.valid"><i class="material-icons">save</i></button>
    </div>

如果要将外部 svg 文件包含为内联 SVG,可以使用 FileReader.readAsText() 函数以文本字符串形式获取 SVG 的内容。

参考:https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsText

const reader = new FileReader();
reader.addEventListener("load", (event) => {
    console.log(event.target.result);
});
reader.readAsText(file);

或者如果你想将它嵌入为Object或Img,你可以使用FileReader.readAsDataURL()获取SVG作为编码数据字符串,参考这篇文章 https://web.dev/read-files/ 及其代码示例: https://glitch.com/~read-image-file

const reader = new FileReader();
reader.addEventListener('load', event => {
    document.getElementById('output').src = event.target.result;
});
reader.readAsDataURL(file);