强制浏览器在点击时下载图像文件

Posted

技术标签:

【中文标题】强制浏览器在点击时下载图像文件【英文标题】:Force browser to download image files on click 【发布时间】:2013-07-05 20:22:24 【问题描述】:

我需要浏览器下载图像文件,就像单击 Excel 工作表时一样。

有没有办法只使用客户端编程来做到这一点?

<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title></title>
        <script type="text/javascript" src="Scripts/jquery-1.10.2.js">
        $(document).ready(function () 
            $("*").click(function () 
                $("p").hide();
            );
        );
        </script>
    </head>

    <script type="text/javascript">
        document.onclick = function (e) 
            e = e || window.event;
            var element = e.target || e.srcElement;
            if (element.innerHTML == "Image") 
                //someFunction(element.href);
                var name = element.nameProp;
                var address = element.href;
                saveImageAs1(element.nameProp, element.href);
                return false; // Prevent default action and stop event propagation
            
            else
                return true;
        ;

        function saveImageAs1(name, adress) 
            if (confirm('you wanna save this image?')) 
                window.win = open(adress);
                //response.redirect("~/testpage.html");
                setTimeout('win.document.execCommand("SaveAs")', 100);
                setTimeout('win.close()', 500);
            
        
    </script>

    <body>
        <form id="form1" runat="server">
            <div>
                <p>
                    <a href="http://localhost:55298/SaveImage/demo/Sample2.xlsx" target="_blank">Excel</a><br />
                    <a href="http://localhost:55298/SaveImage/demo/abc.jpg" id="abc">Image</a>
                </p>
            </div>
        </form>
    </body>
</html>

在下载Excel表格的情况下应该如何工作(浏览器做什么)?

【问题讨论】:

download 属性。 确保文件下载的最佳方法是在服务器端设置内容配置,大多数客户端解决方案并不那么可靠。 可能重复:***.com/questions/2408146/…? 有一个类似的问题已经为您解答:***.com/a/6799284/1948211 Karl-Andre Gagnon : 请正确地通过它。[我没有标记 HTML 5,因为我不想使用它] 并且没有接触服务器 【参考方案1】:

使用 HTML5,您可以将“下载”属性添加到您的链接中。

&lt;a href="/path/to/image.png" download&gt;

兼容的浏览器将提示下载具有相同文件名的图像(在本例中为 image.png)。

如果您为此属性指定一个值,那么它将成为新的文件名:

&lt;a href="/path/to/image.png" download="AwesomeImage.png"&gt;

更新:自 2018 年春季起,对于跨域 hrefs 不再可能。因此,如果您想在 imgur.com 以外的域上创建 &lt;a href="https://i.imgur.com/IskAzqA.jpg" download&gt;,它将无法按预期工作。 Chrome deprecations and removals announcement

【讨论】:

Richard Parnaby-King:使用 HTML 5 属性可以完成,但我需要在不使用 HTML5 或任何服务器端工具的情况下完成它(如果可以的话)感谢帮助 :) 目前尚未在所有浏览器中完全支持,但如果您不关心 IE 或 Safari,这是一个很好的解决方案。 caniuse.com/#feat=download 感谢 HTML5 解决方案。如何仍然允许“另存为”让我在保存之前输入文件名? @ArjunChiddarwar 不,这会带来安全漏洞(想象一下有人将恶意文件直接保存到您的 Windows 文件夹中)。下载路径基于浏览器设置 - 例如默认情况下 Chrome 会下载到您的下载文件夹。 感谢您对跨域内容的提醒。你知道其他浏览器是否会做同样的事情吗?呃..我讨厌跨域。【参考方案2】:

通过将链接附加到文档,我也设法使其在 Chrome 和 Firefox 中正常工作。

var link = document.createElement('a');
link.href = 'images.jpg';
link.download = 'Download.jpg';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);

【讨论】:

对于到处都是 Javascript 的网络应用来说,这实际上是一个非常好的解决方案。不过,仅适用于 Google Chrome(在我的测试设置中)。 很好的解决方案,谢谢!请注意,如果您省略 document.body.appendChild(link),它将无法在 Firefox 中运行。在link.click() 之后删除带有document.body.removeChild(link); 的创建元素也很好 最佳解决方案。为了避免 DOM 中出现垃圾,请使用 setTimeout( function () link.parentNode.removeChild( link ); ,10 ); 感谢应该是选择的答案,因为问题询问如何在 JAVASCRIPT 中执行此操作。 NB1:由于 CORS,这在本地无法工作。 NB2:在 macOS Brave 中,这会立即保存图像。在 ios Safari 中,这会产生一个对话框,询问您是要查看还是保存图像。如果保存,它会进入一个只能在 iOS Safari 中访问的神秘位置(我希望它会保存到我的图像应用程序中,详细信息在 macreports.com/…)。在 iOS Brave 上,它只是打开图像。【参考方案3】:

Leeroy 和 Richard Parnaby-King:

更新:从 2018 年春季开始,跨域不再可能 链接。因此,如果您想在 imgur.com 以外的域上创建它 不会按预期工作。 Chrome deprecations and removals announcement

function forceDownload(url, fileName)
    var xhr = new XMLHttpRequest();
    xhr.open("GET", url, true);
    xhr.responseType = "blob";
    xhr.onload = function()
        var urlCreator = window.URL || window.webkitURL;
        var imageUrl = urlCreator.createObjectURL(this.response);
        var tag = document.createElement('a');
        tag.href = imageUrl;
        tag.download = fileName;
        document.body.appendChild(tag);
        tag.click();
        document.body.removeChild(tag);
    
    xhr.send();

【讨论】:

图像下载但无法打开,因为它说“图像损坏”【参考方案4】:

使用 Promise 和 async/await 的更现代的方法:

toDataURL(url) 
    return fetch(url).then((response) => 
            return response.blob();
        ).then(blob => 
            return URL.createObjectURL(blob);
        );

然后

async download() 
        const a = document.createElement("a");
        a.href = await toDataURL("https://cdn1.iconfinder.com/data/icons/ninja-things-1/1772/ninja-simple-512.png");
        a.download = "myImage.png";
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);

在此处查找文档:https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

【讨论】:

如果请求的图像被 CORS 策略阻止,这将不起作用。【参考方案5】:

2018 年春季更新

<a href="/path/to/image.jpg" download="FileName.jpg">

虽然这仍然受支持,但截至 2018 年 2 月,chrome 禁用了跨域下载的此功能,这意味着这仅在文件位于同一域名上时才有效。

在 Chrome 的新更新禁用跨域下载之后,我想出了一个下载跨域图像的解决方法。您可以将其修改为适合您需要的函数。如果需要,您可以通过更多研究获得图像 mime 类型(jpeg、png、gif 等)。也可能有一种方法可以对视频执行类似的操作。希望这对某人有帮助!

Leeroy 和 Richard Parnaby-King:

更新:从 2018 年春季开始,跨域不再可能 参考文献。因此,如果您想在其他域上创建 比 imgur.com 它不会按预期工作。 Chrome deprecations and removals announcement

var image = new Image();
image.crossOrigin = "anonymous";
image.src = "https://is3-ssl.mzstatic.com/image/thumb/Music62/v4/4b/f6/a2/4bf6a267-5a59-be4f-6947-d803849c6a7d/source/200x200bb.jpg";
// get file name - you might need to modify this if your image url doesn't contain a file extension otherwise you can set the file name manually
var fileName = image.src.split(/(\\|\/)/g).pop();
image.onload = function () 
    var canvas = document.createElement('canvas');
    canvas.width = this.naturalWidth; // or 'width' if you want a special/scaled size
    canvas.height = this.naturalHeight; // or 'height' if you want a special/scaled size
    canvas.getContext('2d').drawImage(this, 0, 0);
    var blob;
    // ... get as Data URI
    if (image.src.indexOf(".jpg") > -1) 
    blob = canvas.toDataURL("image/jpeg");
     else if (image.src.indexOf(".png") > -1) 
    blob = canvas.toDataURL("image/png");
     else if (image.src.indexOf(".gif") > -1) 
    blob = canvas.toDataURL("image/gif");
     else 
    blob = canvas.toDataURL("image/png");
    
    $("body").html("<b>Click image to download.</b><br><a download='" + fileName + "' href='" + blob + "'><img src='" + blob + "'/></a>");
;
&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"&gt;&lt;/script&gt;

【讨论】:

看起来这段代码将图像解码为浏览器内存中的像素缓冲区,然后将其重新编码为 jpeg/png/gif,然后将其封装到数据 uri 中,然后希望将其存储在本地。如果是这样,则意味着图像文件中的所有元数据都丢失了。此外,重新编码 JPEG 会损失一些质量,并且质量/字节数比会更差。不过,很高兴知道。感谢分享。 它会下载图像,但对于我来自 firebase 存储的图像,它表示它被 CORS 策略阻止,但不适用于您的图像链接。【参考方案6】:
var pom = document.createElement('a');
pom.setAttribute('href', 'data:application/octet-stream,' + encodeURIComponent(text));
pom.setAttribute('download', filename);
pom.style.display = 'none';
document.body.appendChild(pom);
pom.click();
document.body.removeChild(pom);     

【讨论】:

safari 浏览器不支持下载属性【参考方案7】:

这是您问题的一般解决方案。但是有一个非常重要的部分是文件扩展名应该与您的编码匹配。当然,downlowadImage 函数的 content 参数应该是图片的 base64 编码字符串。

const clearUrl = url => url.replace(/^data:image\/\w+;base64,/, '');

const downloadImage = (name, content, type) => 
  var link = document.createElement('a');
  link.style = 'position: fixed; left -10000px;';
  link.href = `data:application/octet-stream;base64,$encodeURIComponent(content)`;
  link.download = /\.\w+/.test(name) ? name : `$name.$type`;

  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);


['png', 'jpg', 'gif'].forEach(type => 
  var download = document.querySelector(`#$type`);
  download.addEventListener('click', function() 
    var img = document.querySelector('#img');

    downloadImage('myImage', clearUrl(img.src), type);
  );
);
a gif image: <image id="img" src="data:image/gif;base64,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" />


<button id="png">Download PNG</button>
<button id="jpg">Download JPG</button>
<button id="gif">Download GIF</button>

【讨论】:

请在您的回答中添加一个简短的解释,以使其与提问者相关 link.href = 'data:application/octet-stream,' + encodeURIComponent(address) 这会损坏文件,因此无法打开,可以建议为什么会这样 是的,这个答案当之无愧!对我来说缺少的部分是“cleanUrl”,它会生成格式错误的数据并破坏文件。 另外请记住,如果您将包含点的字符串作为第一个参数的值传递给 downloadImage 常量中包含的函数,则下载的图像在 Windows 等操作系统上将被损坏,因为文件扩展名不会附加到文件名,因此系统将无法识别如何打开该文件。因此,最好将 download 字段的值设置为不带三元运算符的 link 变量中包含的对象:link.download = `$name.$type`;【参考方案8】:

创建一个函数来获取图像 url 和文件名并使用按钮调用该函数。

function downloadImage(url, name)
      fetch(url)
        .then(resp => resp.blob())
        .then(blob => 
            const url = window.URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.style.display = 'none';
            a.href = url;
            // the filename you want
            a.download = name;
            document.body.appendChild(a);
            a.click();
            window.URL.revokeObjectURL(url);
        )
        .catch(() => alert('An error sorry'));
&lt;button onclick="downloadImage('https://upload.wikimedia.org/wikipedia/commons/thumb/0/02/Stack_Overflow_logo.svg/1280px-Stack_Overflow_logo.svg.png', 'Logo***.png')" &gt;DOWNLOAD&lt;/button&gt;

Codepen.io Force image download with JavaScript

vladi.codes

【讨论】:

【参考方案9】:

您可以使用锚标签直接下载此文件,无需太多代码。复制sn​​-p并粘贴到您的文本编辑器中并尝试...!

<html>
<head>
</head>
<body>
   <div>
     <img src="https://upload.wikimedia.org/wikipedia/commons/1/1f/SMirC-thumbsup.svg"  >
      <a href="#" download="https://upload.wikimedia.org/wikipedia/commons/1/1f/SMirC-thumbsup.svg"> Download Image </a>
   </div>
</body>
</html>

【讨论】:

请添加更多详细信息,例如可以使用此代码的位置。 太棒了! href="#" 是这里的关键。 你拯救了我的一天!很简单 !那里有很多糟糕的文档甚至没有显示这个...... 我累了,对我没用。我不明白应该怎么做,因为 download 属性用于提供 the title of the element 而不是路径 这会为我下载一些 html 内容【参考方案10】:

在 2020 年,我使用Blob 制作图像的本地副本,浏览器将下载该图像作为文件。你可以在这个site 上测试它。

(function(global) 
  const next = () => document.querySelector('.search-pagination__button-text').click();
  const uuid = () => Math.random().toString(36).substring(7);
  const toBlob = (src) => new Promise((res) => 
    const img = document.createElement('img');
    const c = document.createElement("canvas");
    const ctx = c.getContext("2d");
    img.onload = (target) => 
      c.width = target.naturalWidth;
      c.height = target.naturalHeight;
      ctx.drawImage(target, 0, 0);
      c.toBlob((b) => res(b), "image/jpeg", 0.75);
    ;
    img.crossOrigin = "";
    img.src = src;
  );
  const save = (blob, name = 'image.png') => 
    const a = document.createElement("a");
    a.href = URL.createObjectURL(blob);
    a.target = '_blank';
    a.download = name;
    a.click();
  ;
  global.download = () => document.querySelectorAll('.search-content__gallery-results figure > img[src]').forEach(async (src) => save(await toBlob(src), `$uuid().png`));
  global.next = () => next();
)(window);

【讨论】:

看起来这段代码将图像解码为浏览器内存中的像素缓冲区(画布),然后将其重新编码为 jpeg/png/gif,然后将其封装到 data-uri 中,然后希望将其存储本地。如果是这样,则意味着图像文件中的所有元数据都丢失了。此外,重新编码 JPEG 会损失一些质量,并且质量/字节数比会更差。不过,很高兴知道。感谢分享。 代码太繁琐。不必要的编码\解码和 CPU 使用率。上面还有更优雅的解决方案。另外 - 如果不是图片而是视频怎么办?...//【参考方案11】:

试试这个:

<a class="button" href="http://www.glamquotes.com/wp-content/uploads/2011/11/smile.jpg" download="smile.jpg">Download image</a>

【讨论】:

【参考方案12】:
<html>
<head>
<script type="text/javascript">
function prepHref(linkElement) 
    var myDiv = document.getElementById('Div_contain_image');
    var myImage = myDiv.children[0];
    linkElement.href = myImage.src;

</script>
</head>
<body>
<div id="Div_contain_image"><img src="YourImage.jpg" alt='MyImage'></div>
<a href="#" onclick="prepHref(this)" download>Click here to download image</a>
</body>
</html>

【讨论】:

【参考方案13】:

我发现了

&lt;a href="link/to/My_Image_File.jpeg" download&gt;Download Image File&lt;/a&gt;

对我不起作用。我不知道为什么。

我发现您可以在链接末尾包含?download=true 参数来强制下载。我想我注意到 Google Drive 正在使用这种技术。

在您的链接中,在您的 href 末尾包含 ?download=true

您也可以同时使用这种技术来设置文件名。

在您的链接中,在您的 href 末尾包含 ?download=true&amp;filename=My_Image_File.jpeg

【讨论】:

?download=true 被传递给 Google Drive,告诉他们的服务器发送正确的标头来下载图像。除非以这种方式专门设置,否则它不能在任何其他环境中工作。【参考方案14】:

如何使用 .click() 函数和标签?

(压缩版)

<a id="downloadtag" href="examplefolder/testfile.txt" hidden download></a>

<button onclick="document.getElementById('downloadtag').click()">Download</button>

现在可以用js来触发了。与其他示例一样,它也无法打开图像和文本文件!

(js-function 版本)

function download()
document.getElementById('downloadtag').click();
<!-- HTML -->
<button onclick="download()">Download</button>
<a id="downloadtag" href="coolimages/awsome.png" hidden download></a>

【讨论】:

【参考方案15】:

你不需要写js来做到这一点,只需使用:

<a href="path_to/image.jpg" >Download image</a>

而且浏览器本身会自动下载图片。

如果由于某种原因它不起作用,请添加下载属性。 使用此属性,您可以为可下载文件设置名称:

<a href="path_to/image.jpg" download="myImage">Download image</a>

【讨论】:

图片链接只会在同一窗口中打开图片,除非您的浏览器配置不同。并非所有浏览器都支持 download 属性。

以上是关于强制浏览器在点击时下载图像文件的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 django 和 aws s3 在点击时强制下载图像

使用 jquery 强制浏览器在单击链接时下载图像

有没有办法强制浏览器刷新/下载图像?

Vue js图像强制下载无法使用锚标记

如何强制用户嵌入图像或注册

浏览器/HTML 强制从 src="data:image/jpeg;base64..." 下载图像