我想出了纯 JavaScript 方式来强制下载图片,但有以下限制:
- 使用 HTML5,因此在 IE9 之前的 IE 浏览器中根本无法使用。
- 由于 URL 长度限制,在 IE(甚至 9 个)中仅限于非常小的图像。
- 无法在代码中确定图像名称(保存到机器时),在 Chrome 中,它只是“下载”而没有扩展名,而在 Firefox 中,它看起来像带有“.part”扩展名的乱码字符串 -无论哪种方式,用户都必须重命名文件以使其可用。
- 只能下载同域的图片 - 同源策略。
上述限制(尤其是第三个限制)或多或少使这个无用,但“核心”想法正在起作用,希望在未来的某个时候可以确定文件名那么它将变得更加有用。
代码如下:
function DownloadImage(imageURL) {
var oImage = document.getElementById(imageURL);
var canvas = document.createElement("canvas");
document.body.appendChild(canvas);
if (typeof canvas.getContext == "undefined" || !canvas.getContext) {
alert("browser does not support this action, sorry");
return false;
}
try {
var context = canvas.getContext("2d");
var width = oImage.width;
var height = oImage.height;
canvas.width = width;
canvas.height = height;
canvas.style.width = width + "px";
canvas.style.height = height + "px";
context.drawImage(oImage, 0, 0, width, height);
var rawImageData = canvas.toDataURL("image/png;base64");
rawImageData = rawImageData.replace("image/png", "image/octet-stream");
document.location.href = rawImageData;
document.body.removeChild(canvas);
}
catch (err) {
document.body.removeChild(canvas);
alert("Sorry, can't download");
}
return true;
}
如您所见,诀窍是将图像绘制到canvas 对象中,获取图像的原始二进制数据,然后通过使用image/octet-stream mime 类型并更改浏览器位置来强制下载。
用法示例如下。
HTML:
<image id="myimage" src="Penguins.jpg" />
<button type="btnDownload" rel="myimage">Download</button>
JavaScript:
window.onload = function() {
var arrButtons = document.getElementsByTagName("button");
for (var i = 0; i < arrButtons.length; i++) {
var oButton = arrButtons[i];
var sRelatedImage = oButton.getAttribute("rel");
if (sRelatedImage && sRelatedImage.length > 0) {
oButton.onclick = function() {
HandleRelatedImage(this, sRelatedImage);
}
}
}
};
function HandleRelatedImage(oButton, sRelatedImage) {
var oImage = document.getElementById(sRelatedImage);
if (!oImage) {
alert("related image '" + sRelatedImage + "' does not exist");
return false;
}
return DownloadImage(sRelatedImage);
}
这允许通过将按钮的 rel 属性分配给图像 ID 来将下载按钮“附加”到每个现有图像 - 代码将完成剩下的工作并附加实际的点击事件。
由于相同的来源政策无法在 jsFiddle 发布实时示例 - 他们使用“沙盒”域来执行脚本。