Fetch image from API - javascript

Q1) In my reactjs application, I am trying to fetch an API from my backend Nodejs server. The API responds with an image file on request.
I can access and see image file on http://192.168.22.124:3000/source/592018124023PM-pexels-photo.jpg
But in my reactjs client side I get this error on console log.
Uncaught (in promise) SyntaxError: Unexpected token � in JSON at position 0
Reactjs:
let fetchURL = 'http://192.168.22.124:3000/source/';
let image = name.map((picName) => {
return picName
})
fetch(fetchURL + image)
.then(response => response.json())
.then(images => console.log(fetchURL + images));
Nodejs:
app.get('/source/:fileid', (req, res) => {
const { fileid } = req.params;
res.sendFile(__dirname + /data/ + fileid);
});
Is there any better way to do than what I am doing above?
Q2) Also, how can I assign a value to an empty variable (which lives outside the fetch function)
jpg = fetchURL + images;
So I can access it somewhere.

The response from the server is a binary file, not JSON formatted text. You need to read the response stream as a Blob.
const imageUrl = "https://.../image.jpg";
fetch(imageUrl)
// vvvv
.then(response => response.blob())
.then(imageBlob => {
// Then create a local URL for that image and print it
const imageObjectURL = URL.createObjectURL(imageBlob);
console.log(imageObjectURL);
});

Equivalent to solution by #maxpaj, but using async and await.
async function load_pic() {
const url = '<REPLACE-WITH-URL>'
const options = {
method: "GET"
}
let response = await fetch(url, options)
if (response.status === 200) {
const imageBlob = await response.blob()
const imageObjectURL = URL.createObjectURL(imageBlob);
const image = document.createElement('img')
image.src = imageObjectURL
const container = document.getElementById("your-container")
container.append(image)
}
else {
console.log("HTTP-Error: " + response.status)
}
}

This question is 4 years old and I think in 2022 there are many ways to solve this. This is ES6 version using async calls.
First, I don't know if you are trying to download the image or insert the image into a img tag. So I will assume we want to download the image.
The process is simple: a) fetch the image as a blob; b) convert blob to Base64 using URL.createObjectURL(blob); and c) trigger the download using a ghost a tag.
const $btn = document.getElementById('downloadImage')
const url = 'https://s3-ap-southeast-1.amazonaws.com/tksproduction/bmtimages/pY3BnhPQYpTxasKfx.jpeg'
const fetchImage = async url => {
const response = await fetch(url)
const blob = await response.blob()
return blob
}
const downloadImage = async url => {
const imageBlob = await fetchImage(url)
const imageBase64 = URL.createObjectURL(imageBlob)
console.log({imageBase64})
const a = document.createElement('a')
a.style.setProperty('display', 'none')
document.body.appendChild(a)
a.download = url.replace(/^.*[\\\/]/, '')
a.href = imageBase64
a.click()
a.remove()
}
$btn.onclick = event => downloadImage(url)
<button id="downloadImage">Download Image</button>
Note:
StackOverflow uses a sandboxed iframe's so we can test the download but you can use my codepen

Related

Downloading Image locally from GitHub Raw link using fs.writeFileSync() JS

Currently trying to download image from GitHub locally. Everything seems to work, the fetch goes through with a 200 OK response, however, I don't understand how to store image itself:
const rawGitLink = "https://raw.githubusercontent.com/cardano-foundation/CIPs/master/CIP-0001/CIP_Flow.png"
const folder = "/Folder"
const imageName = "/Test"
const imageResponse = await axios.get(rawGitLink)
fs.writeFileSync(___dirname + folder + imageName, imageResponse, (err) => {
//Error handling
}
)
Four problems had to be fixed:
Image name must include png format for this case
The response must be in the correct format as a buffer for an image
You must write the response data and not the object itself
__dirname only needs two underscores
const rawGitLink = "https://raw.githubusercontent.com/cardano-foundation/CIPs/master/CIP-0001/CIP_Flow.png"
const folder = "/Folder"
const imageName = "/Test.png"
const imageResponse = await axios.get(rawGitLink, { responseType: 'arraybuffer' });
fs.writeFileSync(__dirname + folder + imageName, imageResponse.data)
Axios returns a special object: https://github.com/axios/axios#response-schema
let {data} = await axios.get(...)
await fs.writeFile(filename, data) // you can use fs.promises instead of sync
As #Leau said you should include the extension on the filename
Another sugestion is to use the path module to create the filename:
filename = path.join(__dirname, "/Folder", "Test.png")

How to get file name from download link in firebase storage(Javascript, React)?

I've being trying to get files name from Firebase storage.
Right now I got a download link and trying to get name from it.
const showPhoto = () => {
var eventDOM = event.target;
var src = eventDOM.getAttribute('src');
setpickImage(src);
console.log(src);
// src = "https://firebasestorage.googleapis.com/v0/b....."
}
I need file name to delete file from storage.
If you want to map a download URL back to a file name, use the refFromURL method.
Also see the documentation on creating a reference from a download URL, which contains this example:
var httpsReference = storage.refFromURL('https://firebasestorage.googleapis.com/b/bucket/o/images%20stars.jpg');
From that Reference you can then get other properties like the file's name.
let fileName = httpsReference.name;
To get the file name and url or download link of the videos or files from the firebase storage you can use these two functions in javascript and react
// function to fetch videos / files from firebase storage
const fetchVideos = async() => {
const storageRef = firebase.storage().ref("your storage folder name");
const videos = [];
await storageRef
.listAll()
.then(async function(result) {
result.items.forEach(async function(videoRef) {
// getting the name of the file
const videoName = videoRef.name;
// getting the url of the file -> calling another function for this
const videoUrl = await getVideoUrl(videoRef);
// creating the object with name and url
const videoObj = {
videoName,
videoUrl,
};
console.log("video obj", videoObj);
videos.push(videoObj);
});
})
.catch(function(error) {
// Handle any errors
return [];
});
}
// function to get download url
const getVideoUrl = (imageRef) => {
const videoLink = imageRef
.getDownloadURL()
.then(function(videoUrl) {
console.log("videoUrl", videoUrl);
return videoUrl;
})
.catch(function(error) {
// Handle any errors
return "";
});
return videoLink;
};

How to generate a blob url from a actual url

How do I convert video source url like
http://localhost:3000/videos/abc.mp4 to blob url
let dataUrl = "http://localhost:3000/videos/abc.mp4"
this.videoBlobUrl = URL.createObjectURL(dataUrl);
All you are looking for is fetch's blob function
fetch("URL")
.then(response => response.blob())
.then(blobData => /* you got the blob data */)
.catch(reason => /* handling errors */)
You can also use URL.createObjectURL(blobData); to create temporary URL as said by
For Example
fetch("https://i.picsum.photos/id/682/200/300.jpg")
.then(r => r.blob())
.then(blobData => console.log(URL.createObjectURL(blobData)))
.catch(console.error)
what is a blob url?
in my opinion, it's not even a real standard on the internets.
i always use my own way of generating a 'blob url'.
for that, i'd use (in javascript) :
var
dataURL = 'http://localhost:3000/videos/abc.mp4',
generateRandomID = function() {
var
r = '',
returnLength = 10,
cipher='abc0123';
for (var i=0; i<returnLength; i++) {
r += cipher.substr(Math.random() * cipher.length, 1)
};
return r;
},
generateBlobURL = function (url) {
var
urlStripped = url.replace('http://localhost:3000/videos',''),
r = urlStripped + generateRandomID();
return r;
},
dataURL_blob = generateBlobURL (dataURL);
and do not forget to use the F12 button to test this code, and to see where the errors in it might be :)

create data url from fetched image

TL;DR
I'm trying to fetch and image, convert it to base64, and put the data url into an img's src attribute, but it's not working:
async function ajax(id) {
const tag = document.getElementById(id);
const path = tag.getAttribute("data-src");
const response = await fetch(path);
const blob = await response.blob();
const base64 = window.btoa(blob);
const content = `data:image/jpeg;base64,${base64}`;
tag.setAttribute("src", content);
}
The details, as well as some other methods, which do work follow.
I have been experimenting with different ways to lazy load:
$ mkdir lazy
$ cd lazy
$ wget https://upload.wikimedia.org/wikipedia/commons/7/7a/Lone_Ranger_and_Silver_1956.jpg # any other example image
now create a file called index.html with this in it:
<script>
// this works
function setAttribute(id) {
const tag = document.getElementById(id);
const path = tag.getAttribute("data-src");
tag.setAttribute("src", path);
}
// this doesn't work for some reason
async function ajax(id) {
const tag = document.getElementById(id);
const path = tag.getAttribute("data-src");
const response = await fetch(path);
const blob = await response.blob();
const base64 = window.btoa(blob);
const content = `data:image/jpeg;base64,${base64}`;
tag.setAttribute("src", content);
}
// this works too
async function works(id) {
const tag = document.getElementById(id);
const path = tag.getAttribute("data-src");
const response = await fetch(path);
const blob = await response.blob();
const content = URL.createObjectURL(blob);
tag.setAttribute("src", content);
}
</script>
set attribute<br />
data url<br />
object url<br />
<img id="example" data-src="Lone_Ranger_and_Silver_1956.jpg"></img><br />
and start a server in that folder:
$ python -m SimpleHTTPServer # or whichever local webserver
and then when I look at it in chrome I get this:
The first and third links both work:
However, the middle link does not:
Here is what the three links do to the tag respectively:
works:
<img id="example" data-src="Lone_Ranger_and_Silver_1956.jpg" src="Lone_Ranger_and_Silver_1956.jpg">
does not work:
<img id="example" data-src="Lone_Ranger_and_Silver_1956.jpg" src="data:image/jpeg;base64,W29iamVjdCBCbG9iXQ==">
works:
<img id="example" data-src="Lone_Ranger_and_Silver_1956.jpg" src="blob:http://localhost:8000/736a9e18-c30d-4e39-ac2e-b5246105c178">
That data url in the non working example also looks too short. So what am I doing wrong?
Thanks for the suggestion #dolpsdw. window.btoa doesn't do what I thought it would. If anybody is trying to do the same thing, instructions for reading a blob into a data url are here: https://stackoverflow.com/a/18650249/5203563
I have created this wrapper that fits right into my program as follows:
(it even adds in the data:image/jpeg;base64, part for you and works out the mime type from the blob)
function readBlob(b) {
return new Promise(function(resolve, reject) {
const reader = new FileReader();
reader.onloadend = function() {
resolve(reader.result);
};
// TODO: hook up reject to reader.onerror somehow and try it
reader.readAsDataURL(b);
});
}
async function ajax(id) {
const tag = document.getElementById(id);
const path = tag.getAttribute("data-src");
const response = await fetch(path);
const blob = await response.blob();
// const base64 = window.btoa(blob);
// const content = `data:image/jpeg;base64,${base64}`;
const content = await readBlob(blob);
tag.setAttribute("src", content);
}
this gives me the much longer data url that I expected:
When you have the inmemory blob
Just generate a url for that blob
var url = urlCreator.createObjectURL(blob)
Then create a new IMG with JavaScript and invoke decode method
const img = new Image();
img.src = url;
img.decode()
.then(() => {
document.body.appendChild(img);
})
.catch((encodingError) => {
// Do something with the error.
})
Maybe you want also to revoke URL after load with
URL.revokeObjectURL(objectURL)
About why the window.btoa does not work, its because is for string to base64 only.
Read about blob to base64 conversión here.
But is a more elegant solution createObjectURL.

NodeJS + ldapsj-client: problem saving thumbnailPhoto

Using the ldapsj-client module, I'm trying to save the thumbnailPhoto into a file
const auth = async () => {
const client = new LdapClient({ url: 'myaddomain' })
await client.bind('someemail#domain.com.br', 'passwaord')
const opts = {
filter: `(sAMAccountName=credential)`,
scope: "sub"
}
const s = await client.search(myBaseDN, opts)
console.log('thumbnailPhoto', s[0].thumbnailPhoto)
}
The console.log() outputs something like '����JFIF��C...'
I cannot figure out how to save this binary into a file. When I try several approaches, as explained here, does not work. It seems the data from AD is not in the same "format".
I tried to convert it into a Buffer and then, to base64
const buffer = Buffer.from(s[0].thumbnailPhoto, 'binary')
var src = "data:image/png;base64," + Buffer.from(s[0].thumbnailPhoto).toString('base64')
But the output is not a valid base64.

Categories

Resources