Como você pode codificar uma string para Base64 em JavaScript?

810

Eu tenho um script PHP que pode codificar uma imagem PNG para uma seqüência de caracteres Base64.

Eu gostaria de fazer a mesma coisa usando JavaScript. Sei como abrir arquivos, mas não sei como fazer a codificação. Não estou acostumado a trabalhar com dados binários.

nome do usuário
fonte
2
Aqui está a melhor maneira de base64_encode e base64_decode usando javascript. Veja os links abaixo. phpjs.org/functions/base64_encode:358 phpjs.org/functions/base64_decode:357
gautamlakum
aqui é outro jquery plug-in fo base64 codificação / descodificação
zahid9i
Verifique os microjs: microjs.com/#base64
Vinod Srivastav
Referenciado na meta-pergunta Respostas basicamente idênticas - Única diferença: correção de erros .
Peter Mortensen

Respostas:

866

Você pode usar btoa()e atob()converter para e da codificação base64.

Parece haver alguma confusão nos comentários sobre o que essas funções aceitam / retornam, então…

  • btoa()aceita uma "string" em que cada caractere representa um byte de 8 bits - se você passar uma string contendo caracteres que não podem ser representados em 8 bits, provavelmente será interrompida . Isso não é um problema se você estiver tratando a string como uma matriz de bytes, mas se estiver tentando fazer outra coisa, precisará codificá-la primeiro.

  • atob()retorna uma "string" onde cada caractere representa um byte de 8 bits - ou seja, seu valor estará entre 0e 0xff. Isso não significa que seja ASCII - presumivelmente, se você está usando essa função, espera trabalhar com dados binários e não com texto.

Veja também:

Shog9
fonte
47
Observe que isso também funciona para navegadores de kit da web, como o Safari.
Daniel Von Fange
5
mas não funciona no iPhone3G com iOS 4.1. Funciona no simulador do iPhone quando definido como iPhone4 ou iPhone.
Grant M
29
Observe a consideração especial para cadeias de caracteres Unicode: developer.mozilla.org/En/DOM/Window.btoa#Unicode_Strings btoa e atob só funcionam corretamente para cadeias de caracteres baseadas em ASCII. Como americano, você provavelmente não notará diferença ... mas na primeira vez em que usar um caractere acentuado, seu código será quebrado.
Dan Esparza
70
você deve usar btoa(unescape(encodeURIComponent(str))))se str for UFT8
SET
4
Veja minha edição, @Triynko. Estes não devem ser usados ​​para processar texto , ponto final.
precisa saber é
289

A partir daqui :

/**
*
*  Base64 encode / decode
*  http://www.webtoolkit.info/
*
**/
var Base64 = {

// private property
_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

// public method for encoding
encode : function (input) {
    var output = "";
    var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
    var i = 0;

    input = Base64._utf8_encode(input);

    while (i < input.length) {

        chr1 = input.charCodeAt(i++);
        chr2 = input.charCodeAt(i++);
        chr3 = input.charCodeAt(i++);

        enc1 = chr1 >> 2;
        enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
        enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
        enc4 = chr3 & 63;

        if (isNaN(chr2)) {
            enc3 = enc4 = 64;
        } else if (isNaN(chr3)) {
            enc4 = 64;
        }

        output = output +
        this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
        this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);

    }

    return output;
},

// public method for decoding
decode : function (input) {
    var output = "";
    var chr1, chr2, chr3;
    var enc1, enc2, enc3, enc4;
    var i = 0;

    input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

    while (i < input.length) {

        enc1 = this._keyStr.indexOf(input.charAt(i++));
        enc2 = this._keyStr.indexOf(input.charAt(i++));
        enc3 = this._keyStr.indexOf(input.charAt(i++));
        enc4 = this._keyStr.indexOf(input.charAt(i++));

        chr1 = (enc1 << 2) | (enc2 >> 4);
        chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
        chr3 = ((enc3 & 3) << 6) | enc4;

        output = output + String.fromCharCode(chr1);

        if (enc3 != 64) {
            output = output + String.fromCharCode(chr2);
        }
        if (enc4 != 64) {
            output = output + String.fromCharCode(chr3);
        }

    }

    output = Base64._utf8_decode(output);

    return output;

},

// private method for UTF-8 encoding
_utf8_encode : function (string) {
    string = string.replace(/\r\n/g,"\n");
    var utftext = "";

    for (var n = 0; n < string.length; n++) {

        var c = string.charCodeAt(n);

        if (c < 128) {
            utftext += String.fromCharCode(c);
        }
        else if((c > 127) && (c < 2048)) {
            utftext += String.fromCharCode((c >> 6) | 192);
            utftext += String.fromCharCode((c & 63) | 128);
        }
        else {
            utftext += String.fromCharCode((c >> 12) | 224);
            utftext += String.fromCharCode(((c >> 6) & 63) | 128);
            utftext += String.fromCharCode((c & 63) | 128);
        }

    }

    return utftext;
},

// private method for UTF-8 decoding
_utf8_decode : function (utftext) {
    var string = "";
    var i = 0;
    var c = c1 = c2 = 0;

    while ( i < utftext.length ) {

        c = utftext.charCodeAt(i);

        if (c < 128) {
            string += String.fromCharCode(c);
            i++;
        }
        else if((c > 191) && (c < 224)) {
            c2 = utftext.charCodeAt(i+1);
            string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
            i += 2;
        }
        else {
            c2 = utftext.charCodeAt(i+1);
            c3 = utftext.charCodeAt(i+2);
            string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
            i += 3;
        }

    }

    return string;
}

}

Além disso, pesquise "codificação javascript base64" gera muitas outras opções, a acima foi a primeira.

Sunny Milenov
fonte
3
Isso também é útil quando a codificação base64 não é padrão; no meu caso, o caractere "/" não foi usado e o "?" o caractere foi usado, o que significa que mesmo no Chrome atob () não decodificaria as seqüências base64 que estavam chegando.
Chris Moschini
21
Tenha cuidado com este código - ele tenta interpretar sua sequência como uma sequência codificada em UTF-8. Tivemos um caso em que tínhamos uma string binária (ou seja, cada caractere na string deveria ser interpretado como um byte), e esse código corrompeu os dados. Leia a fonte, Luke.
11118 Daniel Yankowsky
11
Tudo o que é necessário para torná-lo seguro para a maioria das codificações / decodificações binárias é remover a string = string.replace(/\r\n/g,"\n");declaração questionável no método de codificação utf8.
Marius
7
@ Marius: Eu estou querendo saber por que eles incluiriam string = string.replace(/\r\n/g,"\n");em primeiro lugar, lol. É como "oh, vamos codificar essa string, mas primeiro, por que não normalizamos aleatoriamente todas as quebras de linha sem nenhuma boa razão?". Isso deve ser absolutamente removido da classe em todas as circunstâncias.
Triynko
2
Eu não sou um guru de javascript, mas esse código parece conter um erro: se chr2 for NaN, seu valor ainda será usado na instrução enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);. No meu navegador, isso funciona ok, NaN>>4é igual a 0, mas não sei se todos os navegadores fazem isso (também NaN/16é igual a NaN).
Jan
117

Internet Explorer 10 ou superior

// Define the string
var string = 'Hello World!';

// Encode the String
var encodedString = btoa(string);
console.log(encodedString); // Outputs: "SGVsbG8gV29ybGQh"

// Decode the String
var decodedString = atob(encodedString);
console.log(decodedString); // Outputs: "Hello World!"

Navegador Cruzado

// Create Base64 Object
var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(e){var t="";var n,r,i,s,o,u,a;var f=0;e=Base64._utf8_encode(e);while(f<e.length){n=e.charCodeAt(f++);r=e.charCodeAt(f++);i=e.charCodeAt(f++);s=n>>2;o=(n&3)<<4|r>>4;u=(r&15)<<2|i>>6;a=i&63;if(isNaN(r)){u=a=64}else if(isNaN(i)){a=64}t=t+this._keyStr.charAt(s)+this._keyStr.charAt(o)+this._keyStr.charAt(u)+this._keyStr.charAt(a)}return t},decode:function(e){var t="";var n,r,i;var s,o,u,a;var f=0;e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");while(f<e.length){s=this._keyStr.indexOf(e.charAt(f++));o=this._keyStr.indexOf(e.charAt(f++));u=this._keyStr.indexOf(e.charAt(f++));a=this._keyStr.indexOf(e.charAt(f++));n=s<<2|o>>4;r=(o&15)<<4|u>>2;i=(u&3)<<6|a;t=t+String.fromCharCode(n);if(u!=64){t=t+String.fromCharCode(r)}if(a!=64){t=t+String.fromCharCode(i)}}t=Base64._utf8_decode(t);return t},_utf8_encode:function(e){e=e.replace(/\r\n/g,"\n");var t="";for(var n=0;n<e.length;n++){var r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r)}else if(r>127&&r<2048){t+=String.fromCharCode(r>>6|192);t+=String.fromCharCode(r&63|128)}else{t+=String.fromCharCode(r>>12|224);t+=String.fromCharCode(r>>6&63|128);t+=String.fromCharCode(r&63|128)}}return t},_utf8_decode:function(e){var t="";var n=0;var r=c1=c2=0;while(n<e.length){r=e.charCodeAt(n);if(r<128){t+=String.fromCharCode(r);n++}else if(r>191&&r<224){c2=e.charCodeAt(n+1);t+=String.fromCharCode((r&31)<<6|c2&63);n+=2}else{c2=e.charCodeAt(n+1);c3=e.charCodeAt(n+2);t+=String.fromCharCode((r&15)<<12|(c2&63)<<6|c3&63);n+=3}}return t}}

// Define the string
var string = 'Hello World!';

// Encode the String
var encodedString = Base64.encode(string);
console.log(encodedString); // Outputs: "SGVsbG8gV29ybGQh"

// Decode the String
var decodedString = Base64.decode(encodedString);
console.log(decodedString); // Outputs: "Hello World!"

jsFiddle


com Node.js

Aqui está como você codifica o texto normal para base64 no Node.js:

//Buffer() requires a number, array or string as the first parameter, and an optional encoding type as the second parameter. 
// Default is utf8, possible encoding types are ascii, utf8, ucs2, base64, binary, and hex
var b = new Buffer('JavaScript');
// If we don't use toString(), JavaScript assumes we want to convert the object to utf8.
// We can make it convert to other formats by passing the encoding type to toString().
var s = b.toString('base64');

E aqui está como você decodifica cadeias codificadas em base64:

var b = new Buffer('SmF2YVNjcmlwdA==', 'base64')
var s = b.toString();

com Dojo.js

Para codificar uma matriz de bytes usando dojox.encoding.base64:

var str = dojox.encoding.base64.encode(myByteArray);

Para decodificar uma sequência codificada em base64:

var bytes = dojox.encoding.base64.decode(str)

bower install angular-base64

<script src="bower_components/angular-base64/angular-base64.js"></script>

angular
    .module('myApp', ['base64'])
    .controller('myController', [

    '$base64', '$scope', 
    function($base64, $scope) {

        $scope.encoded = $base64.encode('a string');
        $scope.decoded = $base64.decode('YSBzdHJpbmc=');
}]);
davidcondrey
fonte
3
Esta resposta é baseada no código original e NÃO inclui atualizações para esse código postadas em outras respostas aqui.
Eugene Ryabtsev
A solução NodeJS proposta foi descontinuada.
Vladimir Nul
94

O código do Sunny é ótimo, exceto no IE7, devido a referências a "this". Corrigido substituindo essas referências por "Base64":

var Base64 = {
// private property
_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

// public method for encoding
encode : function (input) {
    var output = "";
    var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
    var i = 0;

    input = Base64._utf8_encode(input);

    while (i < input.length) {

        chr1 = input.charCodeAt(i++);
        chr2 = input.charCodeAt(i++);
        chr3 = input.charCodeAt(i++);

        enc1 = chr1 >> 2;
        enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
        enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
        enc4 = chr3 & 63;

        if (isNaN(chr2)) {
            enc3 = enc4 = 64;
        } else if (isNaN(chr3)) {
            enc4 = 64;
        }

        output = output +
        Base64._keyStr.charAt(enc1) + Base64._keyStr.charAt(enc2) +
        Base64._keyStr.charAt(enc3) + Base64._keyStr.charAt(enc4);

    }

    return output;
},

// public method for decoding
decode : function (input) {
    var output = "";
    var chr1, chr2, chr3;
    var enc1, enc2, enc3, enc4;
    var i = 0;

    input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

    while (i < input.length) {

        enc1 = Base64._keyStr.indexOf(input.charAt(i++));
        enc2 = Base64._keyStr.indexOf(input.charAt(i++));
        enc3 = Base64._keyStr.indexOf(input.charAt(i++));
        enc4 = Base64._keyStr.indexOf(input.charAt(i++));

        chr1 = (enc1 << 2) | (enc2 >> 4);
        chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
        chr3 = ((enc3 & 3) << 6) | enc4;

        output = output + String.fromCharCode(chr1);

        if (enc3 != 64) {
            output = output + String.fromCharCode(chr2);
        }
        if (enc4 != 64) {
            output = output + String.fromCharCode(chr3);
        }

    }

    output = Base64._utf8_decode(output);

    return output;

},

// private method for UTF-8 encoding
_utf8_encode : function (string) {
    string = string.replace(/\r\n/g,"\n");
    var utftext = "";

    for (var n = 0; n < string.length; n++) {

        var c = string.charCodeAt(n);

        if (c < 128) {
            utftext += String.fromCharCode(c);
        }
        else if((c > 127) && (c < 2048)) {
            utftext += String.fromCharCode((c >> 6) | 192);
            utftext += String.fromCharCode((c & 63) | 128);
        }
        else {
            utftext += String.fromCharCode((c >> 12) | 224);
            utftext += String.fromCharCode(((c >> 6) & 63) | 128);
            utftext += String.fromCharCode((c & 63) | 128);
        }

    }

    return utftext;
},

// private method for UTF-8 decoding
_utf8_decode : function (utftext) {
    var string = "";
    var i = 0;
    var c = c1 = c2 = 0;

    while ( i < utftext.length ) {

        c = utftext.charCodeAt(i);

        if (c < 128) {
            string += String.fromCharCode(c);
            i++;
        }
        else if((c > 191) && (c < 224)) {
            c2 = utftext.charCodeAt(i+1);
            string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
            i += 2;
        }
        else {
            c2 = utftext.charCodeAt(i+1);
            c3 = utftext.charCodeAt(i+2);
            string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
            i += 3;
        }

    }
    return string;
}
}
user850789
fonte
4
ooh meu mal, eu estava pegando a entrada do URL do navegador; onde | é convertido em% 7C; daí a codificação também errada.
Kanagavelu Sugumar
Eu sei que isso é realmente antigo, mas eu já vi essa função usada em mais de um lugar, a string da chave tem 65 caracteres, e não 64. A string não é uma especificação padrão, não tenho certeza se isso importa, mas estava me perguntando se isso acontecer?
Jonathan Wagner
"use strict"; é o que quebra o 'this' e outros elementos de tipo como 'with' e, pelo que eu li, 'eval' sofre uma contusão. Todas as idéias equivocadas sobre abuso. Pessoalmente, não vejo por que o JavaScript precisa seguir o caminho que está seguindo; ele nunca foi concebido para ser um programa estreitamente vinculado e tornado mais complexo do que já é. Se você quer ser vinculado, faça um compilador para javascript.
Mark Giblin 10/10
Eu tento usar essa função e recebo o erro: Causado por: org.mozilla.javascript.EcmaError: TypeError: Não é possível encontrar a função substituir no objeto teste teste teste Estou tentando codificar .txt com "teste teste teste". Alguém sabe por que esse erro?
PRVS 04/11/2015
@ JonathanWagner - existem 64 caracteres usados ​​para a codificação normal. O caráter 65 é usado como preenchimento los a cadeia de entrada não tem um número de caracteres divisível por 3.
Kickstart
90

Você pode usar btoa(para a base 64) e atob(da base 64).

Para o IE 9 e abaixo, tente o plugin jquery-base64 :

$.base64.encode("this is a test");
$.base64.decode("dGhpcyBpcyBhIHRlc3Q=");
Vitalii Fedorenko
fonte
133
Por que tudo necessidade de ser um plugin jQuery: c esta é a funcionalidade apenas núcleo JavaScript isso não tem nada a ver com o DOM ou jQuery
EaterOfCode
38
Essa não é uma funcionalidade essencial ou não haveria tantas respostas diferentes com alta votação (incluindo faça você mesmo tl; código dr). Portanto, na verdade, este é realmente um bom caso de uso para o jQuery (um liner, que deve funcionar até no WebView do Android) - ainda mais se já for uma dependência.
Risadinha 26/08
1
Eu gosto de instalar trechos de código como este no jQuery principalmente porque eles existirão em um espaço de nome controlado. Se você não estiver usando AMD ou CommonJS ou um padrão de design semelhante, é fácil para o seu espaço de nomes global ficar realmente confuso com várias funções aleatórias.
Sffc
9
@Risadinha - exceto que sua funcionalidade não depende nem estende nada ao jQuery ... literalmente, as únicas referências ao jQuery em seu código estão anexando-o ao objeto jQuery ... então, qual é o sentido de anexá-lo ao jQuery e, portanto, exigindo jQuery para usar? Basta criar um liner próprio base64.encode(...)e base64.decode(...)... anexá-lo ao jQuery quando tiver zero a funcionalidade específica do jQuery não faz absolutamente nenhum sentido ...
Jimbo Jonny
1
O jQuery não foi solicitado. Não é uma resposta válida para uma pergunta JS simples e antiga.
MetaColin>
34

Dos comentários (de SET e Stefan Steiger) abaixo da resposta aceita, aqui está um rápido resumo de como codificar / decodificar uma string de / para base64 sem a necessidade de uma biblioteca.

str = "The quick brown fox jumps over the lazy dog";
b64 = btoa(unescape(encodeURIComponent(str)));
str = decodeURIComponent(escape(window.atob(b64)));

Demo

(usa a biblioteca jQuery, mas não para codificação / decodificação)

crashwap
fonte
Para confirmar, isso suporta caracteres UTF-8?
Crashalot
1
@Crashalot Sei que isso é dois anos tarde demais, mas sim. Também estou percebendo, ao digitar isso, que você forneceu uma edição que possivelmente fez o UTF8 funcionar.
tycrek 5/04
Para quem está procurando uma boa solução para usar com o Node.js, posso confirmar que isso funciona. Para decodificar no Node, usei:Buffer.from(b64data, 'base64').toString();
tycrek
26

Existem alguns bugs nas duas implementações de _utf8_decode. c1e c2são atribuídos como variáveis ​​globais devido ao uso incorreto da varinstrução, ec3 não são inicializados ou declarados.

Funciona, mas essas variáveis ​​substituem todas as existentes com o mesmo nome fora desta função.

Aqui está uma versão que não fará isso:

// private method for UTF-8 decoding
_utf8_decode : function (utftext) {
    var string = "";
    var i = 0;
    var c = 0, c1 = 0, c2 = 0;

    while ( i < utftext.length ) {

        c = utftext.charCodeAt(i);

        if (c < 128) {
            string += String.fromCharCode(c);
            i++;
        }
        else if((c > 191) && (c < 224)) {
            c1 = utftext.charCodeAt(i+1);
            string += String.fromCharCode(((c & 31) << 6) | (c1 & 63));
            i += 2;
        }
        else {
            c1 = utftext.charCodeAt(i+1);
            c2 = utftext.charCodeAt(i+2);
            string += String.fromCharCode(((c & 15) << 12) | ((c1 & 63) << 6) | (c2 & 63));
            i += 3;
        }

    }
    return string;
}
risos
fonte
9
@Daan Eu não tinha representante suficiente para editar as respostas quando escrevi esta resposta ... em 2011.
robbles
2
IE7? Eu acho que devemos parar de perder tempo para escrever código para isso, as pessoas não vão parar de usar essa tecnologia antiga, a menos que os desenvolvedores as obriguem a fazê-lo!
Rami Dabain
@RonanDejhero não funciona no IE7? Não me lembro se testei nesse navegador em particular.
robbles
1
O que eu quis dizer com isso, se não funcionar no IE7, ninguém deve se importar! Eu não testei e não testá-lo :)
Rami Dabain
16

Marquei a resposta de Sunny com +1, mas queria contribuir com algumas mudanças que fiz para o meu próprio projeto, caso alguém ache útil. Basicamente, acabei de limpar um pouco o código original para que o JSLint não se queixe tanto, e tornei os métodos marcados como privados nos comentários realmente privados. Eu também adicionei dois métodos que eu precisava no meu próprio projeto, a saber decodeToHexeencodeFromHex .

O código:

var Base64 = (function() {
    "use strict";

    var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

    var _utf8_encode = function (string) {

        var utftext = "", c, n;

        string = string.replace(/\r\n/g,"\n");

        for (n = 0; n < string.length; n++) {

            c = string.charCodeAt(n);

            if (c < 128) {

                utftext += String.fromCharCode(c);

            } else if((c > 127) && (c < 2048)) {

                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);

            } else {

                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);

            }

        }

        return utftext;
    };

    var _utf8_decode = function (utftext) {
        var string = "", i = 0, c = 0, c1 = 0, c2 = 0;

        while ( i < utftext.length ) {

            c = utftext.charCodeAt(i);

            if (c < 128) {

                string += String.fromCharCode(c);
                i++;

            } else if((c > 191) && (c < 224)) {

                c1 = utftext.charCodeAt(i+1);
                string += String.fromCharCode(((c & 31) << 6) | (c1 & 63));
                i += 2;

            } else {

                c1 = utftext.charCodeAt(i+1);
                c2 = utftext.charCodeAt(i+2);
                string += String.fromCharCode(((c & 15) << 12) | ((c1 & 63) << 6) | (c2 & 63));
                i += 3;

            }

        }

        return string;
    };

    var _hexEncode = function(input) {
        var output = '', i;

        for(i = 0; i < input.length; i++) {
            output += input.charCodeAt(i).toString(16);
        }

        return output;
    };

    var _hexDecode = function(input) {
        var output = '', i;

        if(input.length % 2 > 0) {
            input = '0' + input;
        }

        for(i = 0; i < input.length; i = i + 2) {
            output += String.fromCharCode(parseInt(input.charAt(i) + input.charAt(i + 1), 16));
        }

        return output;
    };

    var encode = function (input) {
        var output = "", chr1, chr2, chr3, enc1, enc2, enc3, enc4, i = 0;

        input = _utf8_encode(input);

        while (i < input.length) {

            chr1 = input.charCodeAt(i++);
            chr2 = input.charCodeAt(i++);
            chr3 = input.charCodeAt(i++);

            enc1 = chr1 >> 2;
            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
            enc4 = chr3 & 63;

            if (isNaN(chr2)) {
                enc3 = enc4 = 64;
            } else if (isNaN(chr3)) {
                enc4 = 64;
            }

            output += _keyStr.charAt(enc1);
            output += _keyStr.charAt(enc2);
            output += _keyStr.charAt(enc3);
            output += _keyStr.charAt(enc4);

        }

        return output;
    };

    var decode = function (input) {
        var output = "", chr1, chr2, chr3, enc1, enc2, enc3, enc4, i = 0;

        input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

        while (i < input.length) {

            enc1 = _keyStr.indexOf(input.charAt(i++));
            enc2 = _keyStr.indexOf(input.charAt(i++));
            enc3 = _keyStr.indexOf(input.charAt(i++));
            enc4 = _keyStr.indexOf(input.charAt(i++));

            chr1 = (enc1 << 2) | (enc2 >> 4);
            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
            chr3 = ((enc3 & 3) << 6) | enc4;

            output += String.fromCharCode(chr1);

            if (enc3 !== 64) {
                output += String.fromCharCode(chr2);
            }
            if (enc4 !== 64) {
                output += String.fromCharCode(chr3);
            }

        }

        return _utf8_decode(output);
    };

    var decodeToHex = function(input) {
        return _hexEncode(decode(input));
    };

    var encodeFromHex = function(input) {
        return encode(_hexDecode(input));
    };

    return {
        'encode': encode,
        'decode': decode,
        'decodeToHex': decodeToHex,
        'encodeFromHex': encodeFromHex
    };
}());
Joe Dyndale
fonte
Inicialmente eu pensei que o seu desenrolar da concatenação saída em declarações separadas seria mais ideal, mas depois que eu pensei nisso por um segundo, este deve ser mais ineficiente desde cordas Javascript são imutáveis e que causaria 4 cópias de potencialmente enormes bolhas de dados ao trabalhar com grandes arquivos de dados binários. É uma aposta mais segura concatenar os 4 caracteres juntos primeiro e depois construir uma nova string. Eu gostaria de ter certeza de um método melhor de criação de strings que certamente seria eficiente em todas as plataformas. (mesmo IE6)
Marius
Não considerei desempenho na limpeza do código postado originalmente. Eu apenas tornei mais legível e tornei os métodos marcados como privados nos comentários no original realmente privados usando o padrão do módulo revelador. Tenho certeza de que também pode ser otimizado em relação ao desempenho. Não tenho certeza de quando a coleta de lixo entraria aqui, e o hash de arquivos grandes por meio de Javascript não é muito comum (ou provavelmente não é a solução ideal em nenhum caso).
Joe Dyndale
Engraçado como esse código vive aqui. Já existem 3 versões diferentes nesta página.
precisa saber é o seguinte
16

Para navegadores mais recentes, codificar Uint8Array como string e decodificar string para Uint8Array.

const base64 = {
    decode: s => Uint8Array.from(atob(s), c => c.charCodeAt(0)),
    encode: b => btoa(String.fromCharCode(...new Uint8Array(b)))
};

Para Node.js, você pode usar o seguinte para codificar string, Buffer ou Uint8Array em string e decodificar de string, Buffer ou Uint8Array para Buffer.

const base64 = {
    decode: s => Buffer.from(s, 'base64'),
    encode: b => Buffer.from(b).toString('base64')
};
Rix
fonte
13

Para tornar um URL de String codificado em Base64 amigável, em JavaScript, você pode fazer algo assim:

// if this is your Base64 encoded string
var str = 'VGhpcyBpcyBhbiBhd2Vzb21lIHNjcmlwdA=='; 

// make URL friendly:
str = str.replace(/\+/g, '-').replace(/\//g, '_').replace(/\=+$/, '');

// reverse to original encoding
str = (str + '===').slice(0, str.length + (str.length % 4));
str = str.replace(/-/g, '+').replace(/_/g, '/');

Veja também este Fiddle: http://jsfiddle.net/magikMaker/7bjaT/

magikMaker
fonte
9
Eu sugeriria humildemente que o uso de encodeURIComponentpode resultar em um resultado superior com menos gasto de esforço por parte do desenvolvedor.
Pablo Fernandez
11
encodeURIComponent alterará o comprimento das seqüências codificadas base64, e substituir '-' e '_' por '+' e '/' é uma prática padrão ao usar base64 em URLs (por exemplo, docs.python.org/library/base64.html#base64 .urlsafe_b64encode ). Não há necessidade de ficar chateado.
Natevw
12

Observe que isso não é adequado para cadeias de caracteres Unicode brutas! Consulte a seção Unicode aqui .

Sintaxe para codificação

var encodedData = window.btoa(stringToEncode);

Sintaxe para decodificação

var decodedData = window.atob(encodedData);

Kathir
fonte
1
Link direto para a seção unicode: developer.mozilla.org/en-US/docs/Web/API/…
TomTasche
12

Reescrevi manualmente, esses métodos de codificação e decodificação, com exceção do hexadecimal, em um formato modular para compatibilidade entre plataformas / navegadores e também com escopo privado real, além de utilizações btoae atobse existem devido à velocidade, em vez de utilizar sua própria codificação:

https://gist.github.com/Nijikokun/5192472

Uso:

base64.encode(/* String */);
base64.decode(/* String */);

utf8.encode(/* String */);
utf8.decode(/* String */);
Nijikokun
fonte
12

Esta pergunta e suas respostas me indicaram a direção certa.
Especialmente com unicode atob e btoa não pode ser usado "vanilla" e hoje em dia TUDO é unicode ..

Diretamente da Mozilla, duas boas funções para esse fim (testadas com tags unicode e html dentro)

function b64EncodeUnicode(str) {
    return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
        return String.fromCharCode('0x' + p1);
    }));
}

b64EncodeUnicode('✓ à la mode'); // "4pyTIMOgIGxhIG1vZGU="
b64EncodeUnicode('\n'); // "Cg=="



function b64DecodeUnicode(str) {
    return decodeURIComponent(Array.prototype.map.call(atob(str), function(c) {
        return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
    }).join(''));
}

b64DecodeUnicode('4pyTIMOgIGxhIG1vZGU='); // "✓ à la mode"
b64DecodeUnicode('Cg=='); // "\n"

Essas funções executarão extremamente rápido em comparação à decodificação bruta de base64 usando uma função javascript personalizada, pois btoa e atob são executados fora do intérprete.

Se você pode ignorar o IE antigo e os celulares antigos (como o iphone 3?), Essa deve ser uma boa solução.

John
fonte
10

se você precisar codificar o objeto de imagem HTML, poderá escrever funções simples como:

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");  
  // escape data:image prefix
  return dataURL.replace(/^data:image\/(png|jpg);base64,/, "");  
  // or just return dataURL
  // return dataURL
}  

Para obter base64 da imagem por ID:

function getBase64ImageById(id){  
  return getBase64Image(document.getElementById(id));  
} 

mais aqui

Nedudi
fonte
Sim, e var img = nova imagem (); img.src = "../images/myPic.png";
Pdschuller
7

Contribuindo com um polyfill minificado para window.atob+ window.btoaque estou usando no momento.

(function(){function t(t){this.message=t}var e="undefined"!=typeof exports?exports:this,r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";t.prototype=Error(),t.prototype.name="InvalidCharacterError",e.btoa||(e.btoa=function(e){for(var o,n,a=0,i=r,c="";e.charAt(0|a)||(i="=",a%1);c+=i.charAt(63&o>>8-8*(a%1))){if(n=e.charCodeAt(a+=.75),n>255)throw new t("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");o=o<<8|n}return c}),e.atob||(e.atob=function(e){if(e=e.replace(/=+$/,""),1==e.length%4)throw new t("'atob' failed: The string to be decoded is not correctly encoded.");for(var o,n,a=0,i=0,c="";n=e.charAt(i++);~n&&(o=a%4?64*o+n:n,a++%4)?c+=String.fromCharCode(255&o>>(6&-2*a)):0)n=r.indexOf(n);return c})})();
Johan
fonte
6

Prefiro usar os métodos de codificação / decodificação bas64 do CryptoJS , a biblioteca mais popular para algoritmos criptográficos padrão e seguros implementados em JavaScript usando as melhores práticas e padrões.

Dan Dascalescu
fonte
6

Aqui está uma versão do AngularJS Factory da @ user850789:

'use strict';

var ProjectNameBase64Factory = angular.module('project_name.factories.base64', []);

ProjectNameBase64Factory.factory('Base64', function () {
    var Base64 = {
        // private property
        _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

        // public method for encoding
        encode: function (input) {
            var output = "";
            var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
            var i = 0;

            input = Base64._utf8_encode(input);

            while (i < input.length) {

                chr1 = input.charCodeAt(i++);
                chr2 = input.charCodeAt(i++);
                chr3 = input.charCodeAt(i++);

                enc1 = chr1 >> 2;
                enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
                enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
                enc4 = chr3 & 63;

                if (isNaN(chr2)) {
                    enc3 = enc4 = 64;
                } else if (isNaN(chr3)) {
                    enc4 = 64;
                }

                output = output +
                         Base64._keyStr.charAt(enc1) + Base64._keyStr.charAt(enc2) +
                         Base64._keyStr.charAt(enc3) + Base64._keyStr.charAt(enc4);

            }

            return output;
        },

        // public method for decoding
        decode: function (input) {
            var output = "";
            var chr1, chr2, chr3;
            var enc1, enc2, enc3, enc4;
            var i = 0;

            input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

            while (i < input.length) {

                enc1 = Base64._keyStr.indexOf(input.charAt(i++));
                enc2 = Base64._keyStr.indexOf(input.charAt(i++));
                enc3 = Base64._keyStr.indexOf(input.charAt(i++));
                enc4 = Base64._keyStr.indexOf(input.charAt(i++));

                chr1 = (enc1 << 2) | (enc2 >> 4);
                chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
                chr3 = ((enc3 & 3) << 6) | enc4;

                output = output + String.fromCharCode(chr1);

                if (enc3 != 64) {
                    output = output + String.fromCharCode(chr2);
                }
                if (enc4 != 64) {
                    output = output + String.fromCharCode(chr3);
                }

            }

            output = Base64._utf8_decode(output);

            return output;

        },

        // private method for UTF-8 encoding
        _utf8_encode: function (string) {
            string = string.replace(/\r\n/g, "\n");
            var utftext = "";

            for (var n = 0; n < string.length; n++) {

                var c = string.charCodeAt(n);

                if (c < 128) {
                    utftext += String.fromCharCode(c);
                }
                else if ((c > 127) && (c < 2048)) {
                    utftext += String.fromCharCode((c >> 6) | 192);
                    utftext += String.fromCharCode((c & 63) | 128);
                }
                else {
                    utftext += String.fromCharCode((c >> 12) | 224);
                    utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                    utftext += String.fromCharCode((c & 63) | 128);
                }

            }

            return utftext;
        },

        // private method for UTF-8 decoding
        _utf8_decode: function (utftext) {
            var string = "";
            var i = 0;
            var c = 0, c2 = 0, c3 = 0;

            while (i < utftext.length) {

                c = utftext.charCodeAt(i);

                if (c < 128) {
                    string += String.fromCharCode(c);
                    i++;
                }
                else if ((c > 191) && (c < 224)) {
                    c2 = utftext.charCodeAt(i + 1);
                    string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                    i += 2;
                }
                else {
                    c2 = utftext.charCodeAt(i + 1);
                    c3 = utftext.charCodeAt(i + 2);
                    string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                    i += 3;
                }

            }
            return string;
        }
    };
    return Base64;
});
AT
fonte
6

Eu precisava da codificação de uma string UTF-8 como base64 para um projeto meu. A maioria das respostas aqui não parece lidar adequadamente com pares substitutos UTF-16 ao converter para UTF-8; portanto, para fins de conclusão, publicarei minha solução:

function strToUTF8Base64(str) {

    function decodeSurrogatePair(hi, lo) {
        var resultChar = 0x010000;
        resultChar += lo - 0xDC00;
        resultChar += (hi - 0xD800) << 10;
        return resultChar;
    }

    var bytes = [0, 0, 0];
    var byteIndex = 0;
    var result = [];

    function output(s) {
        result.push(s);
    }

    function emitBase64() {

        var digits =
                'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +
                'abcdefghijklmnopqrstuvwxyz' +
                '0123456789+/';

        function toDigit(value) {
            return digits[value];
        }

        // --Byte 0--    --Byte 1--    --Byte 2--
        // 1111  1122    2222  3333    3344  4444

        var d1 = toDigit(bytes[0] >> 2);
        var d2 = toDigit(
            ((bytes[0] & 0x03) << 4) |
            (bytes[1] >> 4));
        var d3 = toDigit(
            ((bytes[1] & 0x0F) << 2) |
            (bytes[2] >> 6));
        var d4 = toDigit(
            bytes[2] & 0x3F);

        if (byteIndex === 1) {
            output(d1 + d2 + '==');
        }
        else if (byteIndex === 2) {
            output(d1 + d2 + d3 + '=');
        }
        else {
            output(d1 + d2 + d3 + d4);
        }
    }

    function emit(chr) {
        bytes[byteIndex++] = chr;
        if (byteIndex == 3) {
            emitBase64();
            bytes[0] = 0;
            bytes[1] = 0;
            bytes[2] = 0;
            byteIndex = 0;
        }
    }

    function emitLast() {
        if (byteIndex > 0) {
            emitBase64();
        }
    }

    // Converts the string to UTF8:

    var i, chr;
    var hi, lo;
    for (i = 0; i < str.length; i++) {
        chr = str.charCodeAt(i);

        // Test and decode surrogate pairs in the string
        if (chr >= 0xD800 && chr <= 0xDBFF) {
            hi = chr;
            lo = str.charCodeAt(i + 1);
            if (lo >= 0xDC00 && lo <= 0xDFFF) {
                chr = decodeSurrogatePair(hi, lo);
                i++;
            }
        }

        // Encode the character as UTF-8.
        if (chr < 0x80) {
            emit(chr);
        }
        else if (chr < 0x0800) {
            emit((chr >> 6) | 0xC0);
            emit(((chr >> 0) & 0x3F) | 0x80);
        }
        else if (chr < 0x10000) {
            emit((chr >> 12) | 0xE0);
            emit(((chr >>  6) & 0x3F) | 0x80);
            emit(((chr >>  0) & 0x3F) | 0x80);
        }
        else if (chr < 0x110000) {
            emit((chr >> 18) | 0xF0);
            emit(((chr >> 12) & 0x3F) | 0x80);
            emit(((chr >>  6) & 0x3F) | 0x80);
            emit(((chr >>  0) & 0x3F) | 0x80);
        }
    }

    emitLast();

    return result.join('');
}

Observe que o código não foi completamente testado. Testei algumas entradas, incluindo coisas como strToUTF8Base64('衠衢蠩蠨')e comparadas com a saída de uma ferramenta de codificação online ( https://www.base64encode.org/ ).

Ricardo Machado
fonte
5

Para o meu projeto, ainda preciso dar suporte ao IE7 e trabalhar com grandes entradas para codificação.

Com base no código proposto por Joe Dyndale e conforme sugerido no comentário de Marius, é possível melhorar o desempenho com o IE7 construindo o resultado com uma matriz em vez de uma string.

Aqui está o exemplo para codificar:

var encode = function (input) {
    var output = [], chr1, chr2, chr3, enc1, enc2, enc3, enc4, i = 0;

    input = _utf8_encode(input);

    while (i < input.length) {

        chr1 = input.charCodeAt(i++);
        chr2 = input.charCodeAt(i++);
        chr3 = input.charCodeAt(i++);

        enc1 = chr1 >> 2;
        enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
        enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
        enc4 = chr3 & 63;

        if (isNaN(chr2)) {
            enc3 = enc4 = 64;
        } else if (isNaN(chr3)) {
            enc4 = 64;
        }

        output.push(_keyStr.charAt(enc1));
        output.push(_keyStr.charAt(enc2));
        output.push(_keyStr.charAt(enc3));
        output.push(_keyStr.charAt(enc4));

    }

    return output.join("");
};
Nico
fonte
5

Enquanto um pouco mais de trabalho, se você deseja uma solução nativa de alto desempenho, existem algumas funções HTML5 que você pode usar.

Se você conseguir colocar seus dados em um Blob, poderá usar a função FileReader.readAsDataURL () para obter um data://URL e cortar a frente para obter os dados base64.

No entanto, talvez seja necessário fazer mais processamento para codificar os dados, pois não tenho certeza se os +caracteres escaparam ou não do data://URL, mas isso deve ser bastante trivial.

Malvineous
fonte
5

Bem, se você estiver usando dojo, isso nos dá uma maneira direta de codificar ou decodificar em base64.

Experimente o seguinte: -

Para codificar uma matriz de bytes usando dojox.encoding.base64:

var str = dojox.encoding.base64.encode(myByteArray);

Para decodificar uma sequência codificada em base64:

var bytes = dojox.encoding.base64.decode(str);
Vikash Pandey
fonte
3

Você pode usar window.btoae window.atob...

const encoded = window.btoa('Alireza Dezfoolian'); // encode a string
const decoded = window.atob(encoded); // decode the string

Provavelmente, usar a maneira como o MDN pode fazer seu trabalho da melhor maneira ... Aceitando também o Unicode ... usando estas duas funções simples:

// ucs-2 string to base64 encoded ascii
function utoa(str) {
    return window.btoa(unescape(encodeURIComponent(str)));
}
// base64 encoded ascii to ucs-2 string
function atou(str) {
    return decodeURIComponent(escape(window.atob(str)));
}
// Usage:
utoa('✓ à la mode'); // 4pyTIMOgIGxhIG1vZGU=
atou('4pyTIMOgIGxhIG1vZGU='); // "✓ à la mode"

utoa('I \u2661 Unicode!'); // SSDimaEgVW5pY29kZSE=
atou('SSDimaEgVW5pY29kZSE='); // "I ♡ Unicode!"
Alireza
fonte
3

Aqui está uma demonstração ao vivo de atob()e btoa()JS construídos em funções:

<!DOCTYPE html>
<html>
  <head>
    <style>
      textarea{
        width:30%;
        height:100px;
      }
    </style>
    <script>
      // encode string to base64
      function encode()
      {
        var txt = document.getElementById("txt1").value;
        var result = btoa(txt);
        document.getElementById("txt2").value = result;
      }
      // decode base64 back to original string
      function decode()
      {
        var txt = document.getElementById("txt3").value;
        var result = atob(txt);
        document.getElementById("txt4").value = result;
      }
    </script>
  </head>
  <body>
    <div>
      <textarea id="txt1">Some text to decode
      </textarea>
    </div>
    <div>
      <input type="button" id="btnencode" value="Encode" onClick="encode()"/>
    </div>
    <div>
      <textarea id="txt2">
      </textarea>
    </div>
    <br/>
    <div>
      <textarea id="txt3">U29tZSB0ZXh0IHRvIGRlY29kZQ==
      </textarea>
    </div>
    <div>
      <input type="button" id="btndecode" value="Decode" onClick="decode()"/>
    </div>
    <div>
      <textarea id="txt4">
      </textarea>
    </div>
  </body>
</html>
jonathana
fonte
2

Use a biblioteca js-base64 como

btoa () não funciona com emojis

var str = "I was funny 😂";
console.log("Original string:", str);

var encodedStr = Base64.encode(str)
console.log("Encoded string:", encodedStr);

var decodedStr = Base64.decode(encodedStr)
console.log("Decoded string:", decodedStr);
<script src="https://cdn.jsdelivr.net/npm/[email protected]/base64.min.js"></script>

Shivaji Mutkule
fonte