A atob
função decodificará uma string codificada em Base64 em uma nova string com um caractere para cada byte dos dados binários.
const byteCharacters = atob(b64Data);
O ponto de código de cada caractere (charCode) será o valor do byte. Podemos criar uma matriz de valores de bytes, aplicando isso usando o .charCodeAt
método para cada caractere na string.
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
Você pode converter essa matriz de valores de bytes em uma matriz de bytes digitada real passando-a para o Uint8Array
construtor.
const byteArray = new Uint8Array(byteNumbers);
Por sua vez, isso pode ser convertido em um BLOB envolvendo-o em uma matriz e passando-o para o Blob
construtor.
const blob = new Blob([byteArray], {type: contentType});
O código acima funciona. No entanto, o desempenho pode ser melhorado um pouco ao processar as byteCharacters
fatias menores, em vez de todas de uma vez. No meu teste aproximado, 512 bytes parecem ser um bom tamanho de fatia. Isso nos dá a seguinte função.
const b64toBlob = (b64Data, contentType='', sliceSize=512) => {
const byteCharacters = atob(b64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
const blob = new Blob(byteArrays, {type: contentType});
return blob;
}
const blob = b64toBlob(b64Data, contentType);
const blobUrl = URL.createObjectURL(blob);
window.location = blobUrl;
Exemplo completo:
const b64toBlob = (b64Data, contentType='', sliceSize=512) => {
const byteCharacters = atob(b64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
const blob = new Blob(byteArrays, {type: contentType});
return blob;
}
const contentType = 'image/png';
const b64Data = 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==';
const blob = b64toBlob(b64Data, contentType);
const blobUrl = URL.createObjectURL(blob);
const img = document.createElement('img');
img.src = blobUrl;
document.body.appendChild(img);
Aqui está um método mais minimalista, sem dependências ou bibliotecas.
Requer a nova API de busca. ( Posso usá-lo? )
Com esse método, você também pode obter facilmente um ReadableStream, ArrayBuffer, texto e JSON.
Como uma função:
Fiz um teste de desempenho simples para a versão de sincronização do Jeremy ES6.
A versão de sincronização bloqueará a interface do usuário por um tempo. manter o devtool aberto pode diminuir o desempenho da busca
Mostrar snippet de código
fonte
createObjectURL
em vez dereadAsDataURL
é muito melhor, por exemplo. E se você fazer upload de arquivos usando Ajax, escolhaFormData
, em vez deJSON
, ou usarcanvas.toBlob
, em vez detoDataURL
await (await fetch(imageDataURL)).blob()
await fetch(url).then(r=>r.blob())
é classificadorAccess is denied.
erro. Eu acho quefetch
expõe blob sob url de blob - da mesma maneiraURL.createObjectUrl
que - que não funcionará no ie11. referência . Talvez haja alguma solução alternativa para usar a busca com o IE11? Parece muito melhor do que outras soluções de sincronização :)Implementação otimizada (mas menos legível):
fonte
Para todo o suporte ao navegador, especialmente no Android, talvez você possa adicionar o seguinte:
fonte
Para dados de imagem, acho mais simples de usar
canvas.toBlob
(assíncrono)fonte
image/jpg
da string base64 e depois passá-lo como um segundo parâmetro para atoBlob
função, para que o resultado seja o mesmo tipo. Fora isso, acho que isso é perfeito - economiza 30% do tráfego e do espaço em disco no servidor (comparado ao base64) e funciona bem mesmo com PNG transparente.Veja este exemplo: https://jsfiddle.net/pqhdce2L/
fonte
Percebi que o Internet Explorer 11 fica incrivelmente lento ao fatiar os dados, como sugeriu Jeremy. Isso ocorre no Chrome, mas o Internet Explorer parece ter um problema ao passar os dados fatiados para o Blob-Constructor. Na minha máquina, a transmissão de 5 MB de dados causa uma falha no Internet Explorer e o consumo de memória está aumentando. O Chrome cria o blob rapidamente.
Execute este código para uma comparação:
Então, decidi incluir os dois métodos descritos por Jeremy em uma função. Créditos vão para ele por isso.
fonte
Se você pode adicionar uma dependência ao seu projeto, existe o ótimo
blob-util
pacote npm que fornece umabase64StringToBlob
função útil . Uma vez adicionado ao seu,package.json
você pode usá-lo assim:fonte
Para todos os amantes de copiar e colar como eu, aqui está uma função de download preparada que funciona no Chrome, Firefox e Edge:
fonte
createObjectURL
não aceita um segundo argumento ...Estou postando uma maneira mais declarativa de sincronizar a conversão do Base64. Embora o assíncrono
fetch().blob()
seja muito elegante e eu goste muito desta solução, ele não funciona no Internet Explorer 11 (e provavelmente o Edge - eu não testei este), mesmo com o polyfill - dê uma olhada no meu comentário para Endless ' postar para mais detalhes.Bônus
Se você quiser imprimi-lo, pode fazer algo como:
Bônus x 2 - Abrir um arquivo BLOB em uma nova guia do Internet Explorer 11
Se você for capaz de executar algum pré-processamento da string Base64 no servidor, poderá expô-la em algum URL e usar o link em
printJS
:)fonte
A seguir está o meu código TypeScript, que pode ser facilmente convertido em JavaScript e você pode usar
fonte
Typescript code
código tem apenas um tipo ÚNICO e esse tipo éany
. Como por que se preocupar?O método com busca é a melhor solução, mas se alguém precisar usar um método sem buscar, aqui está, pois os mencionados anteriormente não funcionaram para mim:
fonte