Base64 in LocalStorage is definitely not "the most performant way" to store an image, nor will it allow the storage of big files.
If I understand your case correctly (the need to be able to navigate your site even when offline), then the correct solution is to
- register a ServiceWorker,
- make this ServiceWorker store all the required resources, including your images, in the browser's cache through the Cache API,
- make it retrieve the resources from the cache when your page fetches it again (e.g at next reload).
More info available at https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps and particularily for this matter at https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Offline_Service_workers
Now, you may be in a rush and not wanting to build a full PWA setup. In that case, the best solution to store binary data (image files included) in a semi-persistent way is to use the IndexedDB API (IDB). I invite you to read this previous answer of mine showing how to use Mozilla's library localforage which helps a lot dealing with IDB.
And... turns out I didn't understand the case correctly. (I leave the first section anyway because who knows, it may help others).
So what OP actually wants is a standalone page, and for this, there is no need to "store" the image anywhere, it suffices to make it part of the markup directly, and this is actually one of the only cases where a data:
URL is useful.
So you'd keep your code that generates the data:
URL, but only as a tool for building your HTML file. The HTML file would not contain this code but only the produced data:
URL:
async function toBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
}
function getBlob(){
return fetch("https://i.imgur.com/sOmEuRl.jpg")
.then(function (response) {
return response.blob();
})
.catch(function(err){
console.log(err);
return Promise.reject(err);
});
}
(async () => {
const blob = await getBlob()
const base64 = await toBase64(blob);
const src = base64;
const HTMLMarkup = `<!DOCTYPE HTML>
<html>
<body>
<h1>Your HTML page</h1>
<img src="${src}" alt="an image">
<!-- your normal HTML content -->
</body>
</html>`;
const HTMLFile = new Blob([HTMLMarkup], { type: "text/html" });
const HTMLSrc = URL.createObjectURL(HTMLFile);
document.querySelector("iframe").src = HTMLSrc;
document.querySelector("pre").textContent = HTMLMarkup;
})();
<iframe></iframe>
<pre></pre>
But maybe, I'm still not understanding your situation completely and all you need is actually to save that file on your hard-drive, in the same directory as your file (or in a sub-folder of the one where your index.html file is). Even if served through file://
all modern browsers accept to load an <img>
if it meets this "same/sub-folder" condition.
Ps: If it's only for your usage, you may also consider starting a local server on your machine. If you continue doing some web-development you'll very soon find out that you need one.