Edit: This first answer was only ever meant to address the original question asked around working with an image element. Scroll down for a better alternative to fetching image data.
If you are trying to safely capture the raw data to use at a later point, you can draw the image onto a canvas
element in order to generate a base-64 encoded data-URL. Though this solution will be subject to same-origin restrictions.
const getImageData = imageElement => {
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
canvas.width = imageElement.width
canvas.height = imageElement.height
ctx.drawImage(imageElement, 0, 0)
return canvas.toDataURL()
}
const img = new Image
img.addEventListener('load', () =>
// assign to some CSS rule
console.log(getImageData(img))
)
img.src = '/foo/bar'
Reading between the lines however your comment, "wouldn't that make the browser download the image twice?" sounds like a misunderstanding - browsers already cache resources and you can reuse asset URLs in any context in your page (i.e. HTML / CSS / JS) and unless explicitly circumvented, rely on them only being downloaded once.
Alternatively, it would be cleaner to load the image as a Blob.
Note: I'm using a CORS proxy here purely to facilitate a runnable example. You probably wouldn't want to pass your own assets through an arbitrary third-party in a production environment.
const getImage = async url => {
const proxy = 'https://cors-anywhere.herokuapp.com/'
const response = await fetch(`${proxy}${url}`)
const blob = await response.blob()
return URL.createObjectURL(blob)
}
const imageUrl =
'https://cdn.sstatic.net/Sites/stackoverflow/' +
'company/img/logos/so/so-logo.png?v=9c558ec15d8a'
const example = document.querySelector('.example')
getImage(imageUrl).then(objectUrl =>
example.style.backgroundImage = `url(${objectUrl})`
)
.example {
min-height: 140px;
background-size: contain;
background-repeat: no-repeat;
}
<div class="example"></div>