How to save an image to localStorage and display it on the next page?
Asked Answered
D

8

202

So, basically, I need to upload a single image, save it to localStorage, then display it on the next page.

Currently, I have my HTML file upload:

<input type='file' id="uploadBannerImage" onchange="readURL(this);" />

Which uses this function to display the image on the page

function readURL(input) 
{
    document.getElementById("bannerImg").style.display = "block";

    if (input.files && input.files[0]) {
        var reader = new FileReader();

        reader.onload = function (e) {
            document.getElementById('bannerImg').src =  e.target.result;
        }

        reader.readAsDataURL(input.files[0]);
    }
}

The image is displayed instantly on the page for the user to see. They are then asked to fill out the rest of the form. This part is working perfectly.

Once the form is complete, they then press a 'Save' button. Once this button is pressed, I save all form inputs as localStorage strings. I need a way to also save the image as a localStorage item.

The save button will also direct them to a new page. This new page will display the users data in a table, with the image being at the top.

So plain and simple, I need to save the image in localStorage once the 'Save' button is pressed, and then loan the image on the next page from localStorage.

I found some solutions such as this fiddle and this article at moz://a HACKS.

Although I am still extremely confused on how this works, and I only really need a simple solution. Basically, I just need to find the image via getElementByID once the 'Save' button is pressed, and then process and save the image.

Demilune answered 4/10, 2013 at 13:59 Comment(3)
What is wrong with storing reader.result in localstorage like this example: jsfiddle.net/x11joex11/9g8NN?Stacy
For people looking to store large amounts of data on localStorage this library is quite nice: pieroxy/lz-string: LZ-based compression algorithm for JavaScriptSiegler
"I only really need a simple solution." Doesn't everybody?Jughead
D
265

To whoever also needs this problem solved:

Firstly, I grab my image with getElementByID, and save the image as a Base64. Then I save the Base64 string as my localStorage value.

bannerImage = document.getElementById('bannerImg');
imgData = getBase64Image(bannerImage);
localStorage.setItem("imgData", imgData);

Here is the function that converts the image to a Base64 string:

function getBase64Image(img) {
    var canvas = document.createElement("canvas");
    canvas.width = img.width;
    canvas.height = img.height;

    var ctx = canvas.getContext("2d");
    ctx.drawImage(img, 0, 0);

    var dataURL = canvas.toDataURL("image/png");

    return dataURL.replace(/^data:image\/(png|jpg);base64,/, "");
}

Then, on my next page I created an image with a blank src like so:

<img src="" id="tableBanner" />

And straight when the page loads, I use these next three lines to get the Base64 string from localStorage, and apply it to the image with the blank src I created:

var dataImage = localStorage.getItem('imgData');
bannerImg = document.getElementById('tableBanner');
bannerImg.src = "data:image/png;base64," + dataImage;

Tested it in quite a few different browsers and versions, and it seems to work quite well.

Demilune answered 4/10, 2013 at 14:22 Comment(8)
Gif is not support, because gif is not supported by canvas.Particularly
You don't need the getBase64Image function. Data urls are already base 64 so when you call reader.readAsDataURL the e.target.result sent to the reader.onload handler will be all you need.Octosyllabic
Bear in mind that there is a limit of about 5MB for local/session storage. And converting a binary image to a base 64 encoded string will make it about 30% larger. So this would not work for high resolution images.Sunn
Why do you strip the initial part of the data url? To reduce size?Martyrize
@Martyrize - been a while, but I think that was why. Completely optional though.Demilune
Note that you need to have image fully loaded first (otherwise ending up in having empty images), so in some cases you'd need to wrap handling into: bannerImage.addEventListener("load", function () {});Greek
This worked, but I needed to include the image's width and height in the call to ctx.drawImage, ie, ctx.drawImage(img, 0, 0, img.width, img.height).Harbird
Not that this solution does not work for images fetched from other domains which do not submit the CORS header, as this operation is unsafe!Octuple
D
12

I wrote a little 2,2kb library of saving image in localStorage JQueryImageCaching Usage:

<img data-src="path/to/image">
<script>
    $('img').imageCaching();
</script>
Depredation answered 3/5, 2015 at 13:16 Comment(2)
2.2 Kilobytes is huge for something like this, plus I'm guessing that doesn't even factor in the size of jQuery itself. I would suggest writing it without jQuery, maybe it will be smallerGaskill
1.74 KB according to gitbubDurarte
M
8

You could serialize the image into a Data URI. There's a tutorial in this blog post. That will produce a string you can store in local storage. Then on the next page, use the data uri as the source of the image.

Malpighi answered 4/10, 2013 at 14:5 Comment(0)
B
7

I used a combination of the accepted answer, James H. Kelly's comment, and the FileReader object.

I first stored the uploaded image as a Base64 string using the FileReader object:

// get user's uploaded image
const imgPath = document.querySelector('input[type=file]').files[0];
const reader = new FileReader();

reader.addEventListener("load", function () {
    // convert image file to base64 string and save to localStorage
    localStorage.setItem("image", reader.result);
}, false);

if (imgPath) {
    reader.readAsDataURL(imgPath);
}

Then, to read the image back in from localStorage, I simply did the following:

let img = document.getElementById('image');
img.src = localStorage.getItem('image');
Blabbermouth answered 24/1, 2021 at 6:51 Comment(0)
T
4
document.getElementById('file').addEventListener('change', (e) => {
  const file = e.target.files[0];
  const reader = new FileReader();
  reader.onloadend = () => {
    // convert file to base64 String
    const base64String = reader.result.replace('data:', '').replace(/^.+,/, '');
    // store file
    localStorage.setItem('wallpaper', base64String);
    // display image
    document.body.style.background = `url(data:image/png;base64,${base64String})`;
  };
  reader.readAsDataURL(file);
});

Example CodePen

Teryn answered 30/8, 2020 at 15:2 Comment(0)
O
2

If your images keep getting cropped, here's some code to get the dimensions of the image file before saving to localstorage.

First, I would create some hidden input boxes to hold the width and height values

<input id="file-h" hidden type="text"/>
<input id="file-w" hidden type="text"/>

Then get the dimensions of your file into the input boxes

var _URL = window.URL || window.webkitURL;
$("#file-input").change(function(e) {
    var file, img;
    if ((file = this.files[0])) {
        img = new Image();
        img.onload = function() {
            $("#file-h").val(this.height);
            $("#file-w").val(this.width);
        };
        img.onerror = function() {
            alert( "not a valid file: " + file.type);
        };
        img.src = _URL.createObjectURL(file);
    }
});

Lastly, change the width and height objects used in the getBase64Image() function by pointing to your input box values

FROM

function getBase64Image(img) {
    var canvas = document.createElement("canvas");
    canvas.width = img.width;
    canvas.height = img.height;

TO

function getBase64Image(img) {
    var canvas = document.createElement("canvas");
    canvas.width = $("#file-w").val();
    canvas.height = $("#file-h").val();

Also, you are going to have to maintain a size of about 300kb for all files. There are posts on stackoverflow that cover file size validation using Javascript.

Oney answered 30/8, 2020 at 20:2 Comment(0)
M
0

"Note that you need to have image fully loaded first (otherwise ending up in having empty images), so in some cases you'd need to wrap handling into: bannerImage.addEventListener("load", function () {}); – yuga Nov 1 '17 at 13:04"

This is extremely IMPORTANT. One of the the options i'm exploring this afternoon is using javascript callback methods rather than addEventListeners since that doesn't seem to bind correctly either. Getting all the elements ready before page load WITHOUT a page refresh is critical.

If anyone can expand upon this please do - as in, did you use a settimeout, a wait, a callback, or an addEventListener method to get the desired result. Which one and why?

Mead answered 17/8, 2018 at 16:32 Comment(1)
always use a callback if you can, and never use a settimeout if you can avoid it. By design, you want the thing to happen after the previous thing, with as little overhead as possible. This is exactly what callbacks are designed forAssailant
S
-4

I have come up with the same issue, instead of storing images, that eventually overflow the local storage, you can just store the path to the image. something like:

let imagen = ev.target.getAttribute('src');
arrayImagenes.push(imagen);
Sapsucker answered 12/3, 2019 at 21:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.