从URL加载图像到文件输入框

8
能否使用 JavaScript 将图片 URL 放入 <input type="file"> 以备提交?或者实现相似的效果?实际上,我想要在用户注册表单中“预加载”图片,使其能够与表单一起提交,就好像使用输入字段从磁盘加载一样。我的图片位于 http://example.com/xxx/image.jpg
具体情况是,我从 API 中获取到的用户数据,我希望用它填充用户注册表单,其中一个字段是用户的头像,API 会提供 URL。 这不是关于如何通过输入字段预览从磁盘选择的图像的问题!

考虑采用不同的方法。您可以将URL放在画布中,然后将该图像的原始内容传递给服务器进行保存。请访问以下链接获取更多信息。http://permadi.com/2010/10/html5-saving-canvas-image-data-using-php-and-ajax/ - cjatstackoverflow
另一种简单的方法是将图像URL发送到服务器并在服务器端获取和处理图像。我只是好奇是否有本地或浏览器API方法,我找不到。 - lavirius
5个回答

2

这不是可行的。作为替代方案,您可以使用一个 input[type="url"],然后在提交时使用JavaScript创建要上传的文件:

async function getFileFromUrl(url, name, defaultType = 'image/png') {
  const response = await fetch(url)
  const data = await response.blob()
  return new File([data], name, {
    type: data.type || defaultType,
  })
}

或者,您可以将其转换为base64,而不是使用此函数:

async function getBase64FromUrl(url) {
  let reader = new FileReader();
  const response = await fetch(url)
  const data = await response.blob()

    return await new Promise((resolve, reject) => {
    reader.onload = () => resolve(reader.result);
    reader.onerror = reject;
    reader.readAsDataURL(data);
  })
}

并上传base64字符串。


2
使用FileReader API的示例。这将在图像HTML对象中加载在文件对象中加载的图像。
<!DOCTYPE html>

<html>
    <head>
        <title>TODO supply a title</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>

        <div>
            <input id="btnFile" type="file" accept="image/*" />
        </div>

        <div>
            <img id="img" style="max-width: 100px" />
        </div>


        <script>



            var btnFile = document.getElementById("btnFile");

            //Register event on file selected or changed.
            addEvents(btnFile, "change", function (event) {
                if (event.target.files.length !== 0) {
                    var file = event.target.files[0];
                    //Check if the file is IMAGE.
                    if (file.type.match("image.*")) {

                        var fl = new FileReader();

                        //Add event to read the content file.
                        addEvents(fl, "load", function (evt) {
                            //alert(evt.target.result);
                            try {


                                //CONVERT ARRAY BUFFER TO BASE64 STRING.
                                var dataURL = evt.target.result;

                                document.getElementById("img").src = dataURL;


                            } catch (e) {
                                alert(e);
                            }

                        });

                        //Read the file as arraybuffer.

                        fl.readAsDataURL(file);

                    } else {

                        alert("Please select a IMAGE FILE");
                    }
                }

            });

            function addEvents(obj, evtName, func) {
                if (obj.addEventListener !== undefined && obj.addEventListener !== null) {
                    obj.addEventListener(evtName, func, false);
                } else if (obj.attachEvent !== undefined && obj.attachEvent !== null) {
                    obj.attachEvent(evtName, func);
                } else {
                    if (this.getAttribute("on" + evtName) !== undefined) {
                        obj["on" + evtName] = func;
                    } else {
                        obj[evtName] = func;
                    }
                }

            }

            function removeEvents(obj, evtName, func) {
                if (obj.removeEventListener !== undefined && obj.removeEventListener !== null) {
                    obj.removeEventListener(evtName, func, false);
                } else if (obj.detachEvent !== undefined && obj.detachEvent !== null) {
                    obj.detachEvent(evtName, func);
                } else {
                    if (this.getAttribute("on" + evtName) !== undefined) {
                        obj["on" + evtName] = null;
                    } else {
                        obj[evtName] = null;
                    }
                }

            }

        </script>
    </body>
</html>

你的代码似乎使用了一个<input type="file">元素来预览从磁盘中选择的图像,这是另一回事... - lavirius
1
你好,你无法将URL图片加载到文件对象中。但是你可以加载到一个图像对象中。之后,你可以使用canvas上传图像到服务器来获取内容blob、二进制字符串或base64。 - toto

1

1
我知道。我正在寻找可能从UI角度模仿此行为的替代解决方案。 - lavirius

1

现在可以使用原生JS实现这一点。

我们可以在内容脚本中获取文件,无需后台脚本的麻烦,将文件转换为Blob,并使用新的File构造函数在内存中创建一个文件。

之后,我们可以使用标准查询选择器选择输入标签,创建一个数据传输对象,将文件传递给输入标签,并通过调度change事件来触发变化,听起来很简单对吧。

以下是代码片段:

// This function does the following
// 1. fetches the PDF resume from the url provided
// 2. creates a file object with the resume data
// 3. triggers the change event on the file input element
// 4. the file input element gets the file object
// 5. the file object is uploaded to the website
async function handleResumeInput(remoteResumeURL) {
  const designFile = await createFile(remoteResumeURL);
  const input = document.querySelector('input[type="file"]');
  const dt = new DataTransfer();
  dt.items.add(designFile);
  input.files = dt.files;
  const event = new Event("change", {
    bubbles: !0,
  });
  input.dispatchEvent(event);
}
async function createFile(url) {
  let response = await fetch(url);
  let data = await response.blob();
  let metadata = {
    type: "image/png",
  };
  return new File([data], "app-logo.png", metadata);
}

这篇文章详细解释了它 https://medium.com/@dev_agam/automate-file-upload-with-chrome-extension-7ee6989d58e9

0
正如Jahl所说,由于安全原因,这是不可能的,但您可以使用隐藏的输入值并填充它作为替代方案。显示图像并提供提交不同图像的选项--如果没有提交其他图像,则默认使用加载的头像。

2
你能用实际的代码来举例说明你的答案吗?这正是 Stack Overflow 的宗旨 :) - lavirius

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接