How to download images without displaying them using Vue.js?
12,261
Solution 1
I created a solution based on blob
. First, I created a blob
using the image url
.
After the image blob is loaded I called the saveAs
method extracted from FileSaver to have the blob quietly.
let vm = new Vue({
el: '#vue-instance',
data: {
link: 'https://i.imgur.com/lF1GKDt.jpg',
},
created() {
this.remoteURL();
},
methods: {
downloadImg() {
let url = this.remoteURL();
fetch(url)
.then((response) => response.blob())
.then((blob) => {
saveAs(blob, 'image_name.jpg');
});
console.log('downloading', url);
},
remoteURL() {
//return this.BASE_URL + link //link is the image's path fetched from database
return this.link;
},
}
});
var _global = typeof window === 'object' && window.window === window ?
window : typeof self === 'object' && self.self === self ?
self : typeof global === 'object' && global.global === global ?
global :
this
function bom(blob, opts) {
if (typeof opts === 'undefined') opts = {
autoBom: false
}
else if (typeof opts !== 'object') {
console.warn('Deprecated: Expected third argument to be a object')
opts = {
autoBom: !opts
}
}
// prepend BOM for UTF-8 XML and text/* types (including HTML)
// note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
if (opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
return new Blob([String.fromCharCode(0xFEFF), blob], {
type: blob.type
})
}
return blob
}
function download(url, name, opts) {
var xhr = new XMLHttpRequest()
xhr.open('GET', url)
xhr.responseType = 'blob'
xhr.onload = function() {
saveAs(xhr.response, name, opts)
}
xhr.onerror = function() {
console.error('could not download file')
}
xhr.send()
}
function corsEnabled(url) {
var xhr = new XMLHttpRequest()
// use sync to avoid popup blocker
xhr.open('HEAD', url, false)
xhr.send()
return xhr.status >= 200 && xhr.status <= 299
}
// `a.click()` doesn't work for all browsers (#465)
function click(node) {
try {
node.dispatchEvent(new MouseEvent('click'))
} catch (e) {
var evt = document.createEvent('MouseEvents')
evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80,
20, false, false, false, false, 0, null)
node.dispatchEvent(evt)
}
}
var saveAs = _global.saveAs || (
// probably in some web worker
(typeof window !== 'object' || window !== _global) ?
function saveAs() { /* noop */ }
// Use download attribute first if possible (#193 Lumia mobile)
:
'download' in HTMLAnchorElement.prototype ?
function saveAs(blob, name, opts) {
var URL = _global.URL || _global.webkitURL
var a = document.createElement('a')
name = name || blob.name || 'download'
a.download = name
a.rel = 'noopener' // tabnabbing
// TODO: detect chrome extensions & packaged apps
// a.target = '_blank'
if (typeof blob === 'string') {
// Support regular links
a.href = blob
if (a.origin !== location.origin) {
corsEnabled(a.href) ?
download(blob, name, opts) :
click(a, a.target = '_blank')
} else {
click(a)
}
} else {
// Support blobs
a.href = URL.createObjectURL(blob)
setTimeout(function() {
URL.revokeObjectURL(a.href)
}, 4E4) // 40s
setTimeout(function() {
click(a)
}, 0)
}
}
// Use msSaveOrOpenBlob as a second approach
:
'msSaveOrOpenBlob' in navigator ?
function saveAs(blob, name, opts) {
name = name || blob.name || 'download'
if (typeof blob === 'string') {
if (corsEnabled(blob)) {
download(blob, name, opts)
} else {
var a = document.createElement('a')
a.href = blob
a.target = '_blank'
setTimeout(function() {
click(a)
})
}
} else {
navigator.msSaveOrOpenBlob(bom(blob, opts), name)
}
}
// Fallback to using FileReader and a popup
:
function saveAs(blob, name, opts, popup) {
// Open a popup immediately do go around popup blocker
// Mostly only available on user interaction and the fileReader is async so...
popup = popup || open('', '_blank')
if (popup) {
popup.document.title =
popup.document.body.innerText = 'downloading...'
}
if (typeof blob === 'string') return download(blob, name, opts)
var force = blob.type === 'application/octet-stream'
var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari
var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent)
if ((isChromeIOS || (force && isSafari)) && typeof FileReader === 'object') {
// Safari doesn't allow downloading of blob URLs
var reader = new FileReader()
reader.onloadend = function() {
var url = reader.result
url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;')
if (popup) popup.location.href = url
else location = url
popup = null // reverse-tabnabbing #460
}
reader.readAsDataURL(blob)
} else {
var URL = _global.URL || _global.webkitURL
var url = URL.createObjectURL(blob)
if (popup) popup.location = url
else location.href = url
popup = null // reverse-tabnabbing #460
setTimeout(function() {
URL.revokeObjectURL(url)
}, 4E4) // 40s
}
}
)
_global.saveAs = saveAs.saveAs = saveAs
if (typeof module !== 'undefined') {
module.exports = saveAs;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="vue-instance">
<span @click="downloadImg()">Download Image</span>
</div>
Update:
I removed the jQuery and FileSaver and adapted a vanilla version.
Solution 2
I used Axios
import axios from "axios";
async downloadImage(url) {
var base64 = await axios
.get(url, {
responseType: "arraybuffer"
})
.then(response =>
Buffer.from(response.data, "binary").toString("base64")
);
var img = new Image();
img.src = "data:image/jpeg;base64, " + base64;
return img;
},
var img = await this.downloadImage("https://upload.wikimedia.org/wikipedia/commons/d/d9/Test.png");
console.log(img.width);
Related videos on Youtube
Author by
qliq
Updated on September 28, 2022Comments
-
qliq over 1 year
In my Vue.js app, I'd like force browser to download image without displaying it when a button is clicked.
Following this answer, I came up with this solution:
<span @click="downloadImg(remoteURL)"> Download Image </span>
And the method:
downloadImg(url) { console.log('downloading', url); document.execCommand('SaveAs',true, url); },
remoteURL
is in fact a small function which generates url like this:remoteURL(link) { return this.BASE_URL+ link //link is the image's path fetched from database },
But when I click
Download Image
nothing happens.This question is not relevant because I don't want to just
Download image with JavaScript
. What I want is to download image quietly, that is without displaying the image.How can I fix it?
-
Yom T. over 5 yearsThis post might help. It's for jQuery, but the idea is you could use an anchor element as a workaround.
-
AndrewShmig over 5 yearswhat about headers sent from server when requesting image -
inline
/attachment
?
-
-
qliq over 5 yearsThanks but I'd like to do it in vanilla vue.js, without jQuery or external packages.
-
ebbishop over 5 years@qliq - Unless you want to go the completely vanilla js route (gomakethings.com/ajax-and-apis-with-vanilla-javascript) you must use some kind of library to make http requests to get the image for downloading. Because vue.js is a library written in javascript, most things that work in vanilla javascript (or any other js library) will work in a vue app. All you have to do (most of the time) is wrap them in a vue method and call as desired. If you want to use a library recommended specifically for vue, check out axios: vuejs.org/v2/cookbook/using-axios-to-consume-apis.html
-
Stephen Ostermiller over 2 yearsA code-only answer is not high quality. While this code may be useful, you can improve it by saying why it works, how it works, when it should be used, and what its limitations are. Please edit your answer to include explanation and link to relevant documentation.