Jak możesz zakodować ciąg do Base64 w JavaScript?


809

Mam skrypt PHP, który może kodować obraz PNG do ciągu Base64.

Chciałbym zrobić to samo za pomocą JavaScript. Wiem, jak otwierać pliki, ale nie jestem pewien, jak wykonać kodowanie. Nie jestem przyzwyczajony do pracy z danymi binarnymi.


2
Oto najlepszy sposób na base64_encode i base64_decode przy użyciu javascript. Zobacz poniższe linki. phpjs.org/functions/base64_encode:358 phpjs.org/functions/base64_decode:357
gautamlakum

oto kolejna wtyczka jquery do kodowania / dekodowania base64
zahid9i


Odpowiedzi:


865

Możesz używać btoa()i atob()konwertować na i z kodowania base64.

Wydaje się, że w komentarzach jest pewne zamieszanie dotyczące tego, co te funkcje akceptują / zwracają, więc…

  • btoa()akceptuje „ciąg”, w którym każdy znak reprezentuje 8-bitowy bajt - jeśli przekażesz ciąg zawierający znaki, których nie można przedstawić w 8 bitach, prawdopodobnie się zepsuje . Nie stanowi to problemu, jeśli faktycznie traktujesz ciąg znaków jako tablicę bajtów, ale jeśli próbujesz zrobić coś innego, najpierw musisz go zakodować.

  • atob()zwraca „ciąg”, gdzie każdy znak reprezentuje 8-bitowy bajt - to znaczy, że jego wartość będzie zawierać się między 0a 0xff. Ten sposób nie oznacza, że jest ASCII - prawdopodobnie jeśli używasz tej funkcji w ogóle, można oczekiwać, aby pracować z danych binarnych, a nie tekst.

Zobacz też:


47
Pamiętaj, że działa to również w przeglądarkach internetowych, takich jak Safari.
Daniel Von Fange

5
ale to nie działa na iPhone3G z iOS 4.1. Działa na symulatorze Symulator iPhone'a, gdy jest ustawiony na iPhone4 lub iPhone.
Grant M

29
Zwróć szczególną uwagę na ciągi znaków Unicode: developer.mozilla.org/En/DOM/Window.btoa#Unicode_Strings btoa i atob działają poprawnie tylko w przypadku ciągów opartych na ASCII. Jako Amerykanin prawdopodobnie nie zauważysz różnicy ... ale przy pierwszym użyciu akcentowanej litery Twój kod się zepsuje.
Dan Esparza

70
powinieneś użyć, btoa(unescape(encodeURIComponent(str))))jeśli str to UFT8
SET

4
Zobacz moją edycję, @Triynko. Nie są one przeznaczone do przetwarzania tekstu , kropki.
Shog9,

289

Stąd :

/**
*
*  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;
}

}

Ponadto wyszukiwanie w „kodowaniu javascript base64” zmienia wiele innych opcji, powyższa była pierwsza.


3
Jest to również przydatne, gdy kodowanie base64 jest niestandardowe; w moim przypadku znak „/” nie został użyty, a „?” zamiast tego użyto znaku, co oznacza, że ​​nawet w Chrome atob () nie zamierzał dekodować przychodzących ciągów base64.
Chris Moschini,

21
Uważaj na ten kod - próbuje on zinterpretować ciąg jako ciąg zakodowany w UTF-8. Mieliśmy przypadek, w którym mieliśmy ciąg binarny (tzn. Każdy znak w ciągu powinien być interpretowany jako bajt), a ten kod uszkodził dane. Przeczytaj źródło, Luke.
Daniel Yankowsky

11
Wszystko, co jest potrzebne, aby było bezpieczne dla większości kodowań / dekodowań binarnych, aby usunąć wątpliwą string = string.replace(/\r\n/g,"\n");instrukcję w metodzie kodowania utf8.
Marius

7
@Marius: Zastanawiam się, dlaczego mieliby w ogóle uwzględniać string = string.replace(/\r\n/g,"\n");, lol. To tak, jakby „och, zakodujmy ten ciąg, ale po pierwsze, dlaczego po prostu losowo nie znormalizujemy wszystkich podziałów linii bez żadnego dobrego powodu”. Należy to absolutnie usunąć z klasy w każdych okolicznościach.
Triynko,

2
Nie jestem guru języka JavaScript, ale wydaje się, że ten kod zawiera błąd: jeśli chr2 to NaN, jego wartość jest nadal używana w instrukcji enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);. W mojej przeglądarce działa to dobrze, NaN>>4równa się 0, ale nie wiem, czy wszystkie przeglądarki to robią ( NaN/16równa się NaN).
stycznia 13

117

Internet Explorer 10+

// 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!"

Przeglądarka

// 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


z Node.js

Oto jak kodować normalny tekst do base64 w 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');

A oto jak dekodujesz ciągi zakodowane w base64:

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

z Dojo.js

Aby zakodować tablicę bajtów przy użyciu dojox.encoding.base64:

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

Aby zdekodować ciąg zakodowany w standardzie base64:

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

altana zainstalować kątowy-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=');
}]);

3
Ta odpowiedź jest oparta na oryginalnym kodzie i NIE zawiera aktualizacji tego kodu zamieszczonych w innych odpowiedziach tutaj.
Eugene Ryabtsev

Proponowane rozwiązanie NodeJS jest przestarzałe.
Vladimir Nul,

94

Kod Sunny jest świetny, z wyjątkiem tego, że psuje się w IE7 z powodu odniesień do „this”. Naprawiono przez zastąpienie takich odniesień „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;
}
}

4
o mój boże, pobierałem dane z adresu URL przeglądarki; gdzie | jest konwertowany na% 7C; stąd też kodowanie jest również nieprawidłowe.
Kanagavelu Sugumar,

Wiem, że to jest naprawdę stare, ale widziałem tę funkcję używaną w więcej niż jednym miejscu, ciąg klucza ma w rzeczywistości 65 znaków, a nie 64. Ciąg nie jest standardową specyfikacją, nie jestem pewien, czy to ma znaczenie, ale po prostu się zastanawiałem Jeśli to robi?
Jonathan Wagner,

„użyj ścisłego”; jest tym, co łamie „to” i inne elementy typu, takie jak „z”, a z tego, co przeczytałem, „eval” dostaje wstrząs. Wszystkie niewłaściwie umieszczone pomysły dotyczące nadużyć. Osobiście nie rozumiem, dlaczego JavaScript musi iść w dół swoją drogą, nigdy nie miał być programem ściśle związanym i bardziej złożonym niż jest już. Jeśli chcesz być związany, stwórz kompilator dla javascript.
Mark Giblin,

Próbuję użyć tej funkcji i pojawia się błąd: Przyczyna: org.mozilla.javascript.EcmaError: TypeError: Nie można znaleźć funkcji zamiany w obiekcie teste teste teste Próbuję zakodować .txt za pomocą „teste teste teste”. Czy ktoś wie, dlaczego ten błąd?
PRVS

@JathanathanWagner - do normalnego kodowania użyto 64 znaków. 65. znak jest używany jako dopełnianie, łańcuch wejściowy nie ma liczby znaków podzielnych przez 3.
Kickstart

90

Możesz użyć btoa(do base-64) i atob(od base-64).

W przypadku przeglądarki IE 9 i starszej wypróbuj wtyczkę jquery-base64 :

$.base64.encode("this is a test");
$.base64.decode("dGhpcyBpcyBhIHRlc3Q=");

133
Dlaczego wszystko musi być plugin jQuery: c to tylko podstawowe funkcje JavaScript to nie ma nic wspólnego z DOM lub jQuery
EaterOfCode

38
To nie jest podstawowa funkcjonalność lub nie byłoby tylu różnych wysoko głosowanych odpowiedzi (w tym zrób to sam tl; dr code). Imho to właściwie dobry przypadek użycia jQuery (jedna linijka, która powinna działać nawet w Android WebView) - tym bardziej, jeśli jest to już zależność.
Risadinha,

1
Lubię instalować takie fragmenty kodu w jQuery głównie dlatego, że będą istnieć w kontrolowanej przestrzeni nazw. Jeśli nie korzystasz z AMD, CommonJS lub podobnego wzorca projektowego, Twoja globalna przestrzeń nazw może być bardzo nieładna dzięki wielu losowym funkcjom.
sffc

9
@Risadinha - poza tym, że jego funkcjonalność w ogóle nie zależy ani nie rozszerza jQuery ... dosłownie jedynymi odniesieniami do jQuery w jego kodzie są dołączanie go do obiektu jQuery ... więc jaki jest sens dołączania go do jQuery, a zatem wymaganie jQuery do użycia? Po prostu stwórz jego własną 1 linijkę base64.encode(...)i base64.decode(...)... dołączenie go do jQuery, gdy ma zerową funkcjonalność jQuery, nie ma absolutnie żadnego sensu ...
Jimbo Jonny

1
jQuery nie było wymagane. Niepoprawna odpowiedź na zwykłe stare pytanie JS.
metaColin

34

Od komentarzy (przez SET i Stefana Steigera) poniżej zaakceptowanej odpowiedzi, oto krótkie podsumowanie, jak kodować / dekodować ciąg znaków do / z base64 bez potrzeby biblioteki.

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

Próbny

(używa biblioteki jQuery, ale nie do kodowania / dekodowania)


Aby potwierdzić, obsługuje to znaki UTF-8?
Crashalot

1
@ Crashalot Zdaję sobie sprawę, że to o dwa lata za późno, ale tak. Właśnie sobie uświadamiam, pisząc to, że dostarczyłeś edycję, która prawdopodobnie sprawiła, że ​​UTF8 działa.
tycrek

Dla każdego, kto szuka dobrego rozwiązania do korzystania z Node.js, mogę potwierdzić, że działa. Do dekodowania w Węźle użyłem:Buffer.from(b64data, 'base64').toString();
tycrek

26

W obu implementacjach jest kilka błędów _utf8_decode. c1i c2są przypisywane jako zmienne globalne z powodu niewłaściwego użycia varinstrukcji i c3nie są w ogóle inicjowane ani deklarowane.

Działa, ale zmienne te zastąpią wszystkie istniejące o tej samej nazwie poza tą funkcją.

Oto wersja, która tego nie zrobi:

// 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;
}

9
@ Daan Nie miałem wystarczającej liczby przedstawicieli, aby edytować odpowiedzi, kiedy napisałem tę odpowiedź ... w 2011 roku.
Robbles

2
IE7? myślę, że powinniśmy przestać marnować czas na pisanie kodu, ludzie nie przestaną używać tej starej technologii, chyba że zmusimy ich do tego deweloperzy!
Rami Dabain

@RonanDejhero nie działa w IE7? Nie pamiętam, czy testowałem w tej konkretnej przeglądarce.
rabuje

1
Co miałem na myśli, że jeśli to nie działa w IE7, nikt nie powinien się tym przejmować! nie testowałem i nie przetestuję :)
Rami Dabain

16

Dałem +1 odpowiedzi Sunny, ale chciałem przekazać kilka zmian, które wprowadziłem dla mojego projektu, na wypadek gdyby ktoś uznał to za przydatne. Zasadniczo właśnie wyczyściłem trochę oryginalny kod, więc JSLint nie narzeka tak bardzo, a metody oznaczyłem jako prywatne w komentarzach jako prywatne. Dodałem także dwie metody, których potrzebowałem w swoim własnym projekcie, a mianowicie decodeToHexiencodeFromHex .

Kod:

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

Początkowo myślałem, że rozwinięcie konkatenacji danych wyjściowych w oddzielne instrukcje byłoby bardziej optymalne, ale po tym, jak pomyślałem o tym przez sekundę, powinno to być bardziej nieefektywne, ponieważ ciągi JavaScript są niezmienne i spowodowałyby 4 kopie potencjalnie dużych obiektów blob danych podczas pracy z dużymi plikami danych binarnych. Bezpieczniej jest połączyć najpierw 4 znaki, a następnie zbudować nowy ciąg. Chciałbym wiedzieć na pewno o lepszej metodzie budowania ciągów, która z pewnością byłaby skuteczna na wszystkich platformach. (nawet IE6)
Marius

Nie brałem pod uwagę wydajności podczas czyszczenia pierwotnie opublikowanego kodu. Właśnie uczyniłem go bardziej czytelnym i uczyniłem metody oznaczone jako prywatne w komentarzach w oryginale tak naprawdę prywatnymi, używając wzorca modułu ujawniającego. Jestem pewien, że można go zoptymalizować również pod względem wydajności. Nie jestem do końca pewien, kiedy rozpocznie się wyrzucanie elementów bezużytecznych, a mieszanie dużych plików za pomocą Javascript nie jest zbyt częste (a nawet nie jest optymalnym rozwiązaniem w każdym przypadku).
Joe Dyndale,

Zabawne, jak żyje ten kod. Na tej stronie są już 3 różne wersje.
gregn3

15

Nowsze przeglądarki kodują Uint8Array na ciąg znaków i dekodują ciąg na Uint8Array.

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

W przypadku Node.js możesz użyć następujących poleceń do kodowania łańcucha, bufora lub Uint8Array do łańcucha i dekodowania z łańcucha, bufora lub Uint8Array do bufora.

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

13

Aby uczynić kod URL ciągiem kodowanym w Base64 przyjaznym, w JavaScript możesz zrobić coś takiego:

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

Zobacz także ten Fiddle: http://jsfiddle.net/magikMaker/7bjaT/


9
Pokornie sugerowałbym, że użycie encodeURIComponentmoże przynieść lepszy wynik przy mniejszym nakładzie pracy dewelopera.
Pablo Fernandez

11
encodeURIComponent zmieni długość zakodowanych ciągów base64, a zamiana „-” i „_” na „+” i „/” jest standardową praktyką przy korzystaniu z base64 w adresach URL (np. docs.python.org/library/base64.html#base64 .urlsafe_b64encode ). Nie musisz się denerwować.
natevw


12

Ponownie napisałem ręcznie, te metody kodowania i dekodowania, z wyjątkiem metody szesnastkowej, na modułowy format dla kompatybilności między platformami / przeglądarkami, a także z rzeczywistym prywatnym zasięgiem, oraz zastosowań btoai atobjeśli istnieją ze względu na szybkość, a nie wykorzystanie własne kodowanie:

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

Stosowanie:

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

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

12

To pytanie i jego odpowiedzi wskazały mi właściwy kierunek.
Zwłaszcza z Unicode atob i btoa nie mogą być używane jako „wanilia”, a obecnie WSZYSTKO jest Unicode.

Bezpośrednio z Mozilli, dwie ładne funkcje do tego celu (przetestowane z tagami Unicode i HTML)

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"

Funkcje te wykonają błyskawicznie w porównaniu do surowego dekodowania base64 przy użyciu niestandardowej funkcji javascript, ponieważ btoa i atob są wykonywane poza interpreterem.

Jeśli możesz zignorować stare IE i stare telefony komórkowe (jak iPhone 3?), Powinno to być dobre rozwiązanie.


10

jeśli chcesz zakodować obiekt obrazu HTML, możesz napisać prostą funkcję, taką jak:

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
}  

Aby uzyskać base64 obrazu według identyfikatora:

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

więcej tutaj


Tak i var img = new Image (); img.src = "../images/myPic.png";
pdschuller,

7

Współtworzenie zminimalizowanego wypełnienia dla window.atob+ window.btoa, którego obecnie używam.

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

6

Wolę używać metod kodowania / dekodowania bas64 z CryptoJS , najpopularniejszej biblioteki standardowych i bezpiecznych algorytmów kryptograficznych zaimplementowanych w JavaScript z wykorzystaniem najlepszych praktyk i wzorców.


6

Oto wersja AngularJS Factory @ 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;
});

6

Potrzebowałem kodowania ciągu UTF-8 jako base64 dla mojego projektu. Większość odpowiedzi tutaj nie wydaje się poprawnie obsługiwać par zastępczych UTF-16 podczas konwersji na UTF-8, więc, ze względu na zakończenie, opublikuję moje rozwiązanie:

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('');
}

Pamiętaj, że kod nie jest dokładnie testowany. Testowałem niektóre dane wejściowe, w tym rzeczy takie jak strToUTF8Base64('衠衢蠩蠨')i porównywałem z danymi wyjściowymi internetowego narzędzia do kodowania ( https://www.base64encode.org/ ).


5

W moim projekcie nadal muszę obsługiwać IE7 i pracować z dużymi danymi wejściowymi do kodowania.

Na podstawie kodu zaproponowanego przez Joe Dyndale i zgodnie z sugestią Mariusa możliwe jest poprawienie wydajności w IE7 poprzez skonstruowanie wyniku za pomocą tablicy zamiast łańcucha.

Oto przykład kodowania:

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

5

Trochę więcej pracy, ale jeśli potrzebujesz wysokowydajnego rozwiązania natywnego, możesz skorzystać z niektórych funkcji HTML5.

Jeśli możesz wprowadzić swoje dane do Blob, możesz użyć funkcji FileReader.readAsDataURL (), aby uzyskać data://adres URL i odciąć jego przód, aby uzyskać dane base64.

Może być jednak konieczne dalsze przetwarzanie w celu urldecode danych, ponieważ nie jestem pewien, czy +znaki są znakami ucieczki, czy nie dla data://adresu URL, ale powinno to być dość trywialne.


5

Cóż, jeśli używasz dojo, daje nam to bezpośredni sposób kodowania lub dekodowania do base64.

Spróbuj tego:-

Aby zakodować tablicę bajtów przy użyciu dojox.encoding.base64:

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

Aby zdekodować ciąg zakodowany w standardzie base64:

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

3

Możesz użyć window.btoai window.atob...

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

Prawdopodobnie wykorzystując sposób, jaki jest MDN, najlepiej wykonasz swoją pracę ... Akceptując także Unicode ... używając tych dwóch prostych funkcji:

// 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!"

3

Oto LIVE DEMO od atob()i btoa()JS wbudowanych funkcji:

<!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>

2

Użyj biblioteki js-base64 jako

btoa () nie działa z emoji

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/js-base64@2.5.2/base64.min.js"></script>

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.