Como salvar uma imagem no localStorage e exibi-la na próxima página?

154

Então, basicamente, preciso fazer upload de uma única imagem, salvá-la no localStorage e exibi-la na próxima página.

Atualmente, tenho meu upload de arquivo HTML:

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

Que usa esta função para exibir a imagem na página

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]);
    }
}

A imagem é exibida instantaneamente na página para o usuário ver. Eles são solicitados a preencher o restante do formulário. Esta parte está funcionando perfeitamente.

Quando o formulário é preenchido, eles pressionam o botão 'Salvar'. Depois que esse botão é pressionado, eu salvo todas as entradas de formulário como localStorageseqüências de caracteres. Eu preciso de uma maneira de também salvar a imagem como um localStorageitem.

O botão Salvar também os direcionará para uma nova página. Esta nova página exibirá os dados dos usuários em uma tabela, com a imagem no topo.

Tão simples e simples, preciso salvar a imagem localStorageassim que o botão 'Salvar' for pressionado e depois emprestar a imagem na próxima página localStorage.

Encontrei algumas soluções como este violino e este artigo em moz: // a HACKS .

Embora eu ainda esteja extremamente confuso sobre como isso funciona, eu realmente só preciso de uma solução simples. Basicamente, só preciso encontrar a imagem getElementByIDassim que o botão 'Salvar' for pressionado, e depois processar e salvar a imagem.

Fizzix
fonte
2
O que há de errado em armazenar o reader.result no armazenamento local como este exemplo: jsfiddle.net/x11joex11/9g8NN ?
Rastreie
Para as pessoas que olham para armazenar grandes quantidades de dados sobre localStorage esta biblioteca é bastante agradável: pieroxy / LZ-string: algoritmo de compressão à base de LZ para JavaScript
brasofilo
"Eu realmente só preciso de uma solução simples." Todo mundo não?
Rodrigo Rodrigo

Respostas:

213

Para quem também precisa deste problema resolvido:

Em primeiro lugar, pego minha imagem getElementByIDe salvo a imagem como Base64. Em seguida, salvei a string Base64 como meu localStoragevalor.

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

Aqui está a função que converte a imagem em uma sequência Base64:

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,/, "");
}

Então, na minha próxima página, criei uma imagem com um espaço em branco srcassim:

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

E direto quando a página é carregada, eu uso essas próximas três linhas para obter a string Base64 localStoragee a aplico à imagem com o espaço em branco srcque criei:

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

Testou em vários navegadores e versões diferentes, e parece funcionar muito bem.

Fizzix
fonte
1
O gif não é suportado, porque o gif não é suportado pela tela.
Allen
16
Você não precisa da função getBase64Image. Os URLs de dados já estão na base 64, portanto, quando você chama reader.readAsDataURL, o e.target.result enviado ao manipulador reader.onload será tudo o que você precisa.
James H. Kelly
3
Lembre-se de que há um limite de cerca de 5 MB para armazenamento local / sessão. E a conversão de uma imagem binária em uma sequência codificada de base 64 a tornará cerca de 30% maior. Portanto, isso não funcionaria para imagens de alta resolução.
Noel Abrahams
Por que você tira a parte inicial do URL de dados? Reduzir tamanho?
deostroll
3
Observe que você precisa ter a imagem totalmente carregada primeiro (caso contrário, acabará tendo imagens vazias); portanto, em alguns casos, você precisará agrupar o tratamento em: bannerImage.addEventListener ("load", function () {});
YE
9

Eu escrevi uma pequena biblioteca de 2,2kb para salvar imagens no localStorage JQueryImageCaching Usage:

<img data-src="path/to/image">
<script>
    $('img').imageCaching();
</script>
moledet
fonte
2
2.2 Kilobytes é enorme para algo assim, além do mais, acho que isso nem leva em consideração o tamanho do jQuery. Eu sugeriria escrevê-lo sem jQuery, talvez ele vai ser menor
ChrisBrownie55
1,74 KB acordo com gitbub
hakiko
6

Você pode serializar a imagem em um URI de dados. Há um tutorial nesta postagem do blog . Isso produzirá uma string que você pode armazenar no armazenamento local. Em seguida, na próxima página, use o uri de dados como a fonte da imagem.

Ray Wadkins
fonte
0

"Observe que você precisa ter a imagem totalmente carregada primeiro (caso contrário, acabará tendo imagens vazias); portanto, em alguns casos, você precisará agrupar o tratamento em: bannerImage.addEventListener (" load ", function () {}); - yuga 1 de novembro de 17 às 13:04 "

Isso é extremamente importante. Uma das opções que estou explorando esta tarde é usar métodos de retorno de chamada javascript em vez de addEventListeners, pois isso também não parece vincular corretamente. Preparar todos os elementos antes do carregamento da página SEM atualizar a página é fundamental.

Se alguém puder expandir isso, faça - como em, você usou um método settimeout, uma espera, um retorno de chamada ou um método addEventListener para obter o resultado desejado. Qual e porquê?

Andrew Ellison Pembroke
fonte
sempre use um retorno de chamada, se puder, e nunca use um tempo limite, se puder evitá-lo. Por design, você deseja que a coisa aconteça após a anterior, com o mínimo de sobrecarga possível. É exatamente para isso que os retornos de chamada são projetados
Grayson
-2

Eu vim com o mesmo problema, em vez de armazenar imagens, que eventualmente excedem o armazenamento local, você pode simplesmente armazenar o caminho para a imagem. algo como:

let imagen = ev.target.getAttribute('src');
arrayImagenes.push(imagen);
SebasCiB3R
fonte