Download image from a third-party server button - javascript

In any browser, if you saw an image, you can right-click on it and click "save as" to download it.
I'm trying to make a button to download an image
The download button should download the image above, the barcode.
I am using react, not sure if this has something to do with the answers.
I read that you can use the <a/> tag with the download attribute, however, I'm on Firefox, and it's redirecting me to a page where the barcode image is hosted, and it's not opening the download window instead:
The code is pretty simple, it look as follows:
<a href='https://barcode.tec-it.com/barcode.ashx?data=${product.barcode}&code=&multiplebarcodes=true&backcolor=%23ffffff&quietzone=10&quietunit=Px&size=Small' download>click me</a>
From the MDN docs:
download only works for same-origin URLs, or the blob: and data:
schemes.
I want to implement this, how can I do it?
I'm not the owner of the server where the image is hosted.
Can we do that in 2023?
The other questions are mixing between local images and images hosted on other servers.
So I thought I could create this thread for people interested only in images on third party servers. - so we are all front-end here, no back-end related stuff.

I think your question refers to this old question.
You need something on the server to send a Content-Disposition header to set the file as an attachment so the browser will not try to handle the file internally.
Please see:
href image link download on click

It only works on the same website, not an external link. Try an image of the same website. Ex: <a href="images/detailed-product.png" download>click</a>

You'll need to proxy the request to avoid CORS issues. As the article states it's better to deploy your own proxy, but you can test with a free one, eg: https://codetabs.com/cors-proxy/cors-proxy.html
StackBlitz updated example:
const downloadButton = document.querySelector('button');
downloadButton.onclick = () => {
console.log('download button clicked');
downloadImage(
'https://api.codetabs.com/v1/proxy?quest=https://barcode.tec-it.com/barcode.ashx?data=${product.barcode}&code=&multiplebarcodes=true&backcolor=%23ffffff&quietzone=10&quietunit=Px&size=Small'
);
};
async function downloadImage(imageSrc) {
try {
const image = await fetch(imageSrc);
const imageBlob = await image.blob();
const imageURL = URL.createObjectURL(imageBlob);
const link = document.createElement('a');
link.href = imageURL;
link.download = 'image.jpg';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
} catch (error) {
console.log(error);
}
}
<button>Download image</button>

To do that, you can utilize the createObjectURL static method from URL to create download link for the image. Then, we create temporary <a> in a variable to open that link programmatically.
async function downloadImage(imageSrc) {
const image = await fetch(imageSrc)
const imageBlob = await image.blob()
const imageURL = URL.createObjectURL(imageBlob)
const link = document.createElement('a')
link.href = imageURL
link.download = 'myimage.jpg'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}

Related

Download html2canvas image to specific file path

export default class Thumbnail {
getThumbnail(canvas) {
html2canvas(canvas)
.then((canvas) => {
this.saveAs(canvas, 'thumbnail.png');
}).catch(function(err) {
console.log(err);
})
}
saveAs(canvas, filename) {
let link = document.createElement('a');
if (typeof link.download === 'string') {
link.href = canvas.toDataURL("image/png").replace("image/png", "image/octet-stream");
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
} else {
window.open(canvas);
}
}
}
I have created a module Thumbnail taking canvas tag as its parameter to take a screen capture of the designated area when called from the html script tag (so whenever I refresh the local page, it calls the module)
As far as I know, the html2canvas saves the image to the download folder as its default. If I would like to save an image to a specific file path what should I do?
For example, if I would like to save the image into a folder with a file path of ./Desktop/Project/Assets/Thumbnail, is there any way to add such command inside the code?
No web browser will permit this.
You as the page author have zero control over where the file is saved. This is as much for security and privacy as it is about user preferences.
This applies to all downloads, not just files created by the html2canvas package.
If you're building a tool that only you will use (and it sounds like you are), you may be able to accomplish the same result by writing a non-web shell script that monitors your Downloads directory and moves these files to the special location when they appear.
For that to work, you'd want to give all the screenshots names that follow a pattern you can easily recognize with your shell script.

Couldn't download several files Programmatically through <a> tag

My node server sends links to the client to download by creating tag and triggering it. But that way I am able to download only one file.
My handleDownload function:
//imageUrls is a array containing links
function handleDownload(){
for(let i=0;i<imageUrls.length;i++){
downloadAnImage(imageUrls[i])
}
}
My downloadAnImage function:
function downloadAnImage(imageLink){
let link=document.createElement('a');
link.href = process.env.REACT_APP_PROXY+"/download/"+imageLink
link.download = imageLink;
link.click();
}
By the way, only the last link of the array gets downloaded.
Thanks in advance!
const arrayOfLinks = ['https://link1.com', 'https://link2.com', 'https://link3.com', 'https://link4.com']
function handleDownload(array) {
array.forEach((link) => {
window.open(link, '_blank')
// you can also use _parent as the second argument to the window.open
// function if you want to get that downloaded in the parent frame
// Even if you use _blank it will open in a new page, and will close once the user allows it to download
})
}
handleDownload(arrayOfLinks)
PS: This will work if the pop-ups are not blocked in the browser settings.

JavaScript can't download images programmatically (getting 403)

In my website I've a button that whenever user clicks on it downloads him a random image, here is the code to download an image:
const downloadImg = (src) => {
const imgName = src.replace(/^.*[\\\/]/, '');
var a = document.createElement('a');
a.href = src;
a.download = imgName;
a.click();
};
This works completely fine from images that are from open websites, like google.com or Wikipedia commons
However, for images from websites like Pixabay, Pexels, Freepik instead of downloading the Image it opens the image URL in the same tab and gives me 403 forbidden error in the console
I completely understand why this error happens, but what I don't understand is how to fix it? If I right-clicked on the image then hit save image as no error will appear and I will be able to download the image normally, how can I do this with javascript programmatically?
It works using the approach from accepted answer here: Chrome 65 blocks cross-origin <a download>. Client-side workaround to force download? , with a minor change. Instead of using mode "cors" use "no-cors". Apparently there is a cors error with some domains when downloading directly from url.
Updated: It does not work if the server does not allow cros-origin requests. Making the request with "no-cors" will succeed, but the response body will not be available. So this is NOT a solution.
You can use javascript fetch to download the random selected image from url address.
Code:
JS:
<script>
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'));}</script>
HTML:<button onclick="downloadimage('https://pixabay.com/get/g2cc1f3e1fe58926edc20db6cf67be6dd1614d93b06e934118288e4c57d5228c60c50de32506ac83ffdabc6fe20a6a01b3c7504b82965e6043e9038185180f3ae_1920.jpg', 'download.jpg')" >download</button>
example:
https://viena.lovestoblog.com/bakDownload/bak.php

Download multiple files via Axios and .zip them

I am trying to expose a .zip in VueJS containing multiple files that are stored in a remote server.
I have tried at least with just one .csv file: the download works, but opening the archive fails because the .zip is recognised as invalid.
What I have tried to do is, this following this previous issue:
try {
const response = await axios.get(download_url, {
responseType:'blob'
});
const url = window.URL.createObjectURL(new Blob([response.data));
const link = document.createElement("a");
link.href = url;
link.setAttribute("download", "filename.zip");
document.body.appendChild(link);
link.click();
} catch (error) {
console.log(error);
}
That allows me to download the .zip, but again, it is invalid and I cannot open it.
Then, I would like to be able to do it with multiple "download_urls", i.e. with multiple files in the same .zip, but for now I would be happy to succeed at least with one file!
Thank you in advance with your help.
Let the link () be directly what you are getting from axios (axios.get(url))
To download multiple file in one zip you could let the server pack them and provide public link to download (we can elaborate on this if you need to)
Again use that public link from the server to download the zip
Use download_url and put it in a

HTML anchor tag download attribute not working in Firefox for jpg and png files

In my web application I have supported user to upload any type of document (.png, .jpg, .docx, .xls, ... ) I'm trying to implement download functionality for these documents.
In Google Chrome if you click on Download link Save dialog is shown for all above documents.
In Mozilla Firefox for docx and xls works fine, Save dialog is shown but for .png and .jpg download tag is not working as expected i.e., download dialog or Save dialog does not appear, it directly open that image.
My code:
Download
I have tried almost all solutions mentioned on stackoverflow and suggested by Google. But most of them says that 'check firefox version' and other changes like:
try adding the element to the DOM before triggering the click
Remove filename from download tag it is of boolean type and etc.
I have also tried w3schools lesson on anchor tag and download attribute but nothing seems to be working.
My Mozilla Firefox version is: 38.0.5
P.S.: in chrome as well as in firefox .docs, .xls, .pdf documents work fine, problem is for .png and .jpg in firefox.
Firefox will handle png and jpeg using default handling, which is to inline them in the document. When clicking a link, even if download attribute is defined, seem to make Firefox think it has a new image ignoring the download aspect of it. This may be a temporary bug.
Here is a way, admittedly not super-elegant, to get around this problem forcing the image to be interpreted as an octet-stream.
It does not work inline on Stackoverflow so you have to test it on jsFiddle.
The code does the following:
Scans the document for a-tags.
Those which has data-link set will have a common click-handler attached.
When clicked the link is extracted from the data-link attribute (href is se to #), loaded as an ArrayBuffer via XHR (CORS requirements applies, not a problem in this case), and is converted to an Object-URL with the Blob set to mime-type octet/stream
The Object URL is set as window.location to redirect to this binary data which will make the browser ask user to download the file instead.
var links = document.querySelectorAll("a"), i = 0, lnk;
while(lnk = links[i++]) {
if (lnk.dataset.link.length) lnk.onclick = toBlob;
}
function toBlob(e) {
e.preventDefault();
var lnk = this, xhr = new XMLHttpRequest();
xhr.open("GET", lnk.dataset.link);
xhr.responseType = "blob";
xhr.overrideMimeType("octet/stream");
xhr.onload = function() {
if (xhr.status === 200) {
window.location = (URL || webkitURL).createObjectURL(xhr.response);
}
};
xhr.send();
}
Example tag:
Click to download
The drawback is that you'll loose the extension in the filename.
This is also possible to do using a Data-URL, but a data-url has a 166% overhead compared to using ArrayBuffer and a blob.
I had a similar problem with firefox not handling the download attribute, even for same-domain files.
My target files are actually hosted on AWS, so they are cross-domain. I got around this with a same-domain endpoint that downloads the remote file and pipes it to the client.
const express = require('express')
const {createWriteStream} = require('fs')
const downloadVideo = (url) => { return new Promise((resolve, reject) => {
const filePath = `/tmp/neat.mp4`
const ws = createWriteStream(filePath)
request(url, {}, (error, response, body) => {
if(error) { return reject(error) }
resolve(filePath)
}).pipe(ws)
})}
app.get('/api/download', async (req, res) => {
const videoPath = await downloadVideo(req.query.url)
res.sendFile(videoPath)
})
On the client, I send the file path to the download endpoint to get a blob back, which is then converted to an object url. From there, it's standard download attribute stuff.
async download(remoteFilePath){
const a = document.createElement('a')
const dlURL = `/api/download?url=${encodeURIComponent(remoteFilePath)}`
const blob = await fetch(dlURL).then(res => res.blob())
a.href = URL.createObjectURL(blob)
a.setAttribute('download', 'cool.mp4')
document.body.appendChild(a)
a.click()
a.remove()
}
As you are using HTML5 attribute, each browser handling differently. So use https://github.com/dcneiner/Downloadify for client side forceful download instead of viewing in browser.

Categories