Base64 encoding and decoding

  • Revision slug: Web/JavaScript/Base64_encoding_and_decoding
  • Revision title: Base64 encoding and decoding
  • Revision id: 426437
  • Created:
  • Creator: fusionchess
  • Is current revision? No
  • Comment

Revision Content

Base64 is a group of similar binary-to-text encoding schemes that represent binary data in an ASCII string format by translating it into a radix-64 representation. The term Base64 originates from a specific MIME content transfer encoding.

Base64 encoding schemes are commonly used when there is a need to encode binary data that needs to be stored and transferred over media that are designed to deal with textual data. This is to ensure that the data remain intact without modification during transport. Base64 is commonly used in a number of applications including email via MIME, and storing complex data in XML.

In JavaScript there are two functions respectively for decoding and encoding base64 strings:

  • {{domxref("window.atob","atob()")}}
  • {{domxref("window.btoa","btoa()")}}

The atob() function decodes a string of data which has been encoded using base-64 encoding. On the contrary, the btoa() function creates a base-64 encoded ASCII string from a "string" of binary data.

Documentation

data URIs
data URIs, defined by RFC 2397, allow content creators to embed small files inline in documents.
Base64
Wikipedia article about Base64 encoding.
{{domxref("window.atob","atob()")}}
Decodes a string of data which has been encoded using base-64 encoding.
{{domxref("window.btoa","btoa()")}}
Creates a base-64 encoded ASCII string from a "string" of binary data.
The "Unicode Problem"
In most browsers, calling btoa() on a Unicode string will cause a Character Out Of Range exception. This paragraph shows some solutions.
URIScheme
List of Mozilla supported URI schemes
StringView
In this article is published a library of ours whose aims are:
  • creating a C-like interface for strings (i.e. array of characters codes — ArrayBufferView in JavaScript) based upon the JavaScript ArrayBuffer interface,
  • creating a collection of methods for such string-like objects (since now: stringViews) which work strictly on array of numbers rather than on immutable JavaScript strings,
  • working with other Unicode encodings, different from default JavaScript's UTF-16 DOMStrings,

View All...

Tools

View All...

The "Unicode Problem"

Since DOMStrings are 16-bit-encoded strings, in most browsers calling window.btoa on a Unicode string will cause a Character Out Of Range exception if a character exceeds the range of a 8-bit ASCII-encoded character. There are two possible methods to solve this problem:

  • the first one is to escape the whole string and then encode it;
  • the second one is to convert the UTF-16 DOMString to an UTF-8 array of characters and then encode it.

Here are the two possible methods.

Solution #1 – escaping the string before encoding it

function utf8_to_b64( str ) {
  return window.btoa(unescape(encodeURIComponent( str )));
}

function b64_to_utf8( str ) {
  return decodeURIComponent(escape(window.atob( str )));
}

// Usage:
utf8_to_b64('✓ à la mode'); // "4pyTIMOgIGxhIG1vZGU="
b64_to_utf8('4pyTIMOgIGxhIG1vZGU='); // "✓ à la mode"

This solution has been proposed by Johan Sundström.

Solution #2 – rewriting atob() and btoa() using TypedArrays and UTF-8

Note: The following code is also useful to get an ArrayBuffer from a Base64 string and/or viceversa (see below). For a complete typed arrays library, see this article.
"use strict";

/*\
|*|
|*|  Base64 / binary data / UTF-8 strings utilities
|*|
|*|  https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding
|*|
\*/

/* Array of bytes to base64 string decoding */

function b64ToUint6 (nChr) {

  return nChr > 64 && nChr < 91 ?
      nChr - 65
    : nChr > 96 && nChr < 123 ?
      nChr - 71
    : nChr > 47 && nChr < 58 ?
      nChr + 4
    : nChr === 43 ?
      62
    : nChr === 47 ?
      63
    :
      0;

}

function base64DecToArr (sBase64, nBlocksSize) {

  var
    sB64Enc = sBase64.replace(/[^A-Za-z0-9\+\/]/g, ""), nInLen = sB64Enc.length,
    nOutLen = nBlocksSize ? Math.ceil((nInLen * 3 + 1 >> 2) / nBlocksSize) * nBlocksSize : nInLen * 3 + 1 >> 2, taBytes = new Uint8Array(nOutLen);

  for (var nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) {
    nMod4 = nInIdx & 3;
    nUint24 |= b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << 18 - 6 * nMod4;
    if (nMod4 === 3 || nInLen - nInIdx === 1) {
      for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) {
        taBytes[nOutIdx] = nUint24 >>> (16 >>> nMod3 & 24) & 255;
      }
      nUint24 = 0;

    }
  }

  return taBytes;
}

/* Base64 string to array encoding */

function uint6ToB64 (nUint6) {

  return nUint6 < 26 ?
      nUint6 + 65
    : nUint6 < 52 ?
      nUint6 + 71
    : nUint6 < 62 ?
      nUint6 - 4
    : nUint6 === 62 ?
      43
    : nUint6 === 63 ?
      47
    :
      65;

}

function base64EncArr (aBytes) {

  var nMod3, sB64Enc = "";

  for (var nLen = aBytes.length, nUint24 = 0, nIdx = 0; nIdx < nLen; nIdx++) {
    nMod3 = nIdx % 3;
    if (nIdx > 0 && (nIdx * 4 / 3) % 76 === 0) { sB64Enc += "\r\n"; }
    nUint24 |= aBytes[nIdx] << (16 >>> nMod3 & 24);
    if (nMod3 === 2 || aBytes.length - nIdx === 1) {
      sB64Enc += String.fromCharCode(uint6ToB64(nUint24 >>> 18 & 63), uint6ToB64(nUint24 >>> 12 & 63), uint6ToB64(nUint24 >>> 6 & 63), uint6ToB64(nUint24 & 63));
      nUint24 = 0;
    }
  }

  return sB64Enc.replace(/A(?=A$|$)/g, "=");

}

/* UTF-8 array to DOMString and vice versa */

function UTF8ArrToStr (aBytes) {

  var sView = "";

  for (var nPart, nLen = aBytes.length, nIdx = 0; nIdx < nLen; nIdx++) {
    nPart = aBytes[nIdx];
    sView += String.fromCharCode(
      nPart > 251 && nPart < 254 && nIdx + 5 < nLen ? /* six bytes */
        /* (nPart - 252 << 32) is not possible in ECMAScript! So...: */
        (nPart - 252) * 1073741824 + (aBytes[++nIdx] - 128 << 24) + (aBytes[++nIdx] - 128 << 18) + (aBytes[++nIdx] - 128 << 12) + (aBytes[++nIdx] - 128 << 6) + aBytes[++nIdx] - 128
      : nPart > 247 && nPart < 252 && nIdx + 4 < nLen ? /* five bytes */
        (nPart - 248 << 24) + (aBytes[++nIdx] - 128 << 18) + (aBytes[++nIdx] - 128 << 12) + (aBytes[++nIdx] - 128 << 6) + aBytes[++nIdx] - 128
      : nPart > 239 && nPart < 248 && nIdx + 3 < nLen ? /* four bytes */
        (nPart - 240 << 18) + (aBytes[++nIdx] - 128 << 12) + (aBytes[++nIdx] - 128 << 6) + aBytes[++nIdx] - 128
      : nPart > 223 && nPart < 240 && nIdx + 2 < nLen ? /* three bytes */
        (nPart - 224 << 12) + (aBytes[++nIdx] - 128 << 6) + aBytes[++nIdx] - 128
      : nPart > 191 && nPart < 224 && nIdx + 1 < nLen ? /* two bytes */
        (nPart - 192 << 6) + aBytes[++nIdx] - 128
      : /* nPart < 127 ? */ /* one byte */
        nPart
    );
  }

  return sView;

}

function strToUTF8Arr (sDOMStr) {

  var aBytes, nChr, nStrLen = sDOMStr.length, nArrLen = 0;

  /* mapping... */

  for (var nMapIdx = 0; nMapIdx < nStrLen; nMapIdx++) {
    nChr = sDOMStr.charCodeAt(nMapIdx);
    nArrLen += nChr < 0x80 ? 1 : nChr < 0x800 ? 2 : nChr < 0x10000 ? 3 : nChr < 0x200000 ? 4 : nChr < 0x4000000 ? 5 : 6;
  }

  aBytes = new Uint8Array(nArrLen);

  /* transcription... */

  for (var nIdx = 0, nChrIdx = 0; nIdx < nArrLen; nChrIdx++) {
    nChr = sDOMStr.charCodeAt(nChrIdx);
    if (nChr < 128) {
      /* one byte */
      aBytes[nIdx++] = nChr;
    } else if (nChr < 0x800) {
      /* two bytes */
      aBytes[nIdx++] = 192 + (nChr >>> 6);
      aBytes[nIdx++] = 128 + (nChr & 63);
    } else if (nChr < 0x10000) {
      /* three bytes */
      aBytes[nIdx++] = 224 + (nChr >>> 12);
      aBytes[nIdx++] = 128 + (nChr >>> 6 & 63);
      aBytes[nIdx++] = 128 + (nChr & 63);
    } else if (nChr < 0x200000) {
      /* four bytes */
      aBytes[nIdx++] = 240 + (nChr >>> 18);
      aBytes[nIdx++] = 128 + (nChr >>> 12 & 63);
      aBytes[nIdx++] = 128 + (nChr >>> 6 & 63);
      aBytes[nIdx++] = 128 + (nChr & 63);
    } else if (nChr < 0x4000000) {
      /* five bytes */
      aBytes[nIdx++] = 248 + (nChr >>> 24);
      aBytes[nIdx++] = 128 + (nChr >>> 18 & 63);
      aBytes[nIdx++] = 128 + (nChr >>> 12 & 63);
      aBytes[nIdx++] = 128 + (nChr >>> 6 & 63);
      aBytes[nIdx++] = 128 + (nChr & 63);
    } else /* if (nChr <= 0x7fffffff) */ {
      /* six bytes */
      aBytes[nIdx++] = 252 + /* (nChr >>> 32) is not possible in ECMAScript! So...: */ (nChr / 1073741824);
      aBytes[nIdx++] = 128 + (nChr >>> 24 & 63);
      aBytes[nIdx++] = 128 + (nChr >>> 18 & 63);
      aBytes[nIdx++] = 128 + (nChr >>> 12 & 63);
      aBytes[nIdx++] = 128 + (nChr >>> 6 & 63);
      aBytes[nIdx++] = 128 + (nChr & 63);
    }
  }

  return aBytes;

}

Tests

/* Tests */

var sMyInput = "Base 64 \u2014 Mozilla Developer Network";

var aMyUTF8Input = strToUTF8Arr(sMyInput);

var sMyBase64 = base64EncArr(aMyUTF8Input);

alert(sMyBase64);

var aMyUTF8Output = base64DecToArr(sMyBase64);

var sMyOutput = UTF8ArrToStr(aMyUTF8Output);

alert(sMyOutput);

Appendix: Decode a Base64 string to Uint8Array or ArrayBuffer

These function let us to create also uint8Arrays or arrayBuffers from base64-encoded strings:

var myArray = base64DecToArr("QmFzZSA2NCDigJQgTW96aWxsYSBEZXZlbG9wZXIgTmV0d29yaw=="); // "Base 64 \u2014 Mozilla Developer Network"

var myBuffer = base64DecToArr("QmFzZSA2NCDigJQgTW96aWxsYSBEZXZlbG9wZXIgTmV0d29yaw==").buffer; // "Base 64 \u2014 Mozilla Developer Network"

alert(myBuffer.byteLength);
Note: The function base64DecToArr(sBase64[, nBlocksSize]) returns an uint8Array of bytes. If your aim is to build a buffer of 16-bit / 32-bit / 64-bit raw data, use the nBlocksSize argument, which is the number of bytes of which the uint8Array.buffer.bytesLength property must result a multiple (1 or omitted for ASCII, binary strings or UTF-8-encoded strings, 2 for UTF-16 strings, 4 for UTF-32 strings).

For a more complete library, see StringView – a C-like representation of strings based on typed arrays.

Functions which natively return Base64-encoded strings in JavaScript

See also

Revision Source

<p><b>Base64</b> is a group of similar <a href="https://en.wikipedia.org/wiki/Binary-to-text_encoding">binary-to-text encoding</a> schemes that represent binary data in an ASCII string format by translating it into a radix-64 representation. The term <i>Base64</i> originates from a specific <a href="https://en.wikipedia.org/wiki/MIME#Content-Transfer-Encoding">MIME content transfer encoding</a>.</p>
<p>Base64 encoding schemes are commonly used when there is a need to encode binary data that needs to be stored and transferred over media that are designed to deal with textual data. This is to ensure that the data remain intact without modification during transport. Base64 is commonly used in a number of applications including email via <a href="https://en.wikipedia.org/wiki/MIME">MIME</a>, and storing complex data in <a href="/en-US/docs/XML">XML</a>.</p>
<p>In JavaScript there are two functions respectively for decoding and encoding <em>base64</em> strings:</p>
<ul>
  <li>{{domxref("window.atob","atob()")}}</li>
  <li>{{domxref("window.btoa","btoa()")}}</li>
</ul>
<p>The <code>atob()</code> function decodes a string of data which has been encoded using base-64 encoding. On the contrary, the <code>btoa()</code> function creates a base-64 encoded ASCII string from a "string" of binary data.</p>
<table class="topicpage-table">
  <tbody>
    <tr>
      <td>
        <h2 class="Documentation" id="Documentation" name="Documentation">Documentation</h2>
        <dl>
          <dt>
            <a href="https://developer.mozilla.org/en-US/docs/data_URIs" title="https://developer.mozilla.org/en-US/docs/data_URIs"><code>data</code> URIs</a></dt>
          <dd>
            <small><code>data</code> URIs, defined by <a class="external" href="http://tools.ietf.org/html/rfc2397" title="http://tools.ietf.org/html/rfc2397">RFC 2397</a>, allow content creators to embed small files inline in documents.</small></dd>
          <dt>
            <a href="https://en.wikipedia.org/wiki/Base64" title="https://en.wikipedia.org/wiki/Base64">Base64</a></dt>
          <dd>
            <small>Wikipedia article about Base64 encoding.</small></dd>
          <dt>
            {{domxref("window.atob","atob()")}}</dt>
          <dd>
            <small>Decodes a string of data which has been encoded using base-64 encoding.</small></dd>
          <dt>
            {{domxref("window.btoa","btoa()")}}</dt>
          <dd>
            <small>Creates a base-64 encoded ASCII string from a "string" of binary data.</small></dd>
          <dt>
            <a href="#The_.22Unicode_Problem.22">The "Unicode Problem"</a></dt>
          <dd>
            <small>In most browsers, calling <code>btoa()</code> on a Unicode string will cause a <code>Character Out Of Range</code> exception. This paragraph shows some solutions.</small></dd>
          <dt>
            <a href="/en-US/docs/URIScheme" title="/en-US/docs/URIScheme">URIScheme</a></dt>
          <dd>
            <small>List of Mozilla supported URI schemes</small></dd>
          <dt>
            <a href="/en-US/docs/Web/JavaScript/Typed_arrays/StringView" title="/en-US/docs/Web/JavaScript/Typed_arrays/StringView"><code>StringView</code></a></dt>
          <dd>
            In this article is published a library of ours whose aims are:
            <ul>
              <li>creating a <a class="external" href="http://en.wikipedia.org/wiki/C_%28programming_language%29" title="http://en.wikipedia.org/wiki/C_%28programming_language%29">C</a>-like interface for strings (i.e. array of characters codes —<a href="/en-US/docs/Web/JavaScript/Typed_arrays/ArrayBufferView" title="/en-US/docs/Web/JavaScript/Typed_arrays/ArrayBufferView"> <code>ArrayBufferView</code></a> in JavaScript) based upon the JavaScript <a href="/en-US/docs/Web/JavaScript/Typed_arrays/ArrayBuffer" title="/en-US/docs/Web/JavaScript/Typed_arrays/ArrayBuffer"><code>ArrayBuffer</code></a> interface,</li>
              <li>creating a collection of methods for such string-like objects (since now: <code>stringView</code>s) which work <strong>strictly on array of numbers</strong> rather than on immutable JavaScript strings,</li>
              <li>working with other Unicode encodings, different from default JavaScript's UTF-16 <a href="/en-US/docs/Web/API/DOMString" title="/en-US/docs/Web/API/DOMString"><code>DOMString</code></a>s,</li>
            </ul>
          </dd>
        </dl>
        <p><span class="alllinks"><a href="/en-US/docs/tag/Base64">View All...</a></span></p>
      </td>
      <td>
        <h2 class="Tools" id="Tools" name="Tools">Tools</h2>
        <ul>
          <li><a href="#Solution_.232_.E2.80.93_rewriting_atob()_and_btoa()_using_TypedArrays_and_UTF-8">Rewriting <code>atob()</code> and <code>btoa()</code> using <code>TypedArray</code>s and UTF-8</a></li>
          <li><a href="/en-US/docs/Web/JavaScript/Typed_arrays/StringView" title="/en-US/docs/Web/JavaScript/Typed_arrays/StringView"><code>StringView</code> – a C-like representation of strings based on typed arrays</a></li>
        </ul>
        <p><span class="alllinks"><a href="/en-US/docs/tag/Base64">View All...</a></span></p>
        <h2 class="Related_Topics" id="Related_Topics" name="Related_Topics">Related Topics</h2>
        <ul>
          <li><a href="/en-US/docs/Web/JavaScript/Typed_arrays/ArrayBuffer"><code>ArrayBuffer</code></a></li>
          <li><a href="/en-US/docs/Web/JavaScript/Typed_arrays">Typed arrays</a></li>
          <li><a href="/en-US/docs/Web/JavaScript/Typed_arrays/ArrayBufferView">ArrayBufferView</a></li>
          <li><a href="/en-US/docs/Web/JavaScript/Typed_arrays/Uint8Array"><code>Uint8Array</code></a></li>
          <li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays/StringView" title="/en-US/docs/Web/JavaScript/Typed_arrays/StringView"><code>StringView</code> – a C-like representation of strings based on typed arrays</a></li>
          <li><a href="/en-US/docs/Web/API/DOMString" title="/en-US/docs/Web/API/DOMString"><code>DOMString</code></a></li>
          <li><a href="/en-US/docs/URI" title="/en-US/docs/URI"><code>URI</code></a></li>
          <li><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI"><code>encodeURI()</code></a></li>
        </ul>
      </td>
    </tr>
  </tbody>
</table>
<h2 id="The_.22Unicode_Problem.22">The "Unicode Problem"</h2>
<p>Since <a href="/en-US/docs/Web/API/DOMString" title="/en-US/docs/Web/API/DOMString"><code>DOMString</code></a>s are 16-bit-encoded strings, in most browsers calling <code>window.btoa</code> on a Unicode string will cause a <code>Character Out Of Range</code> exception if a character exceeds the range of a 8-bit ASCII-encoded character. There are two possible methods to solve this problem:</p>
<ul>
  <li>the first one is to escape the whole string and then encode it;</li>
  <li>the second one is to convert the UTF-16 <a href="/en-US/docs/Web/API/DOMString" title="/en-US/docs/Web/API/DOMString"><code>DOMString</code></a> to an UTF-8 array of characters and then encode it.</li>
</ul>
<p>Here are the two possible methods.</p>
<h3 id="Solution_.231_.E2.80.93_escaping_the_string_before_encoding_it">Solution #1 – escaping the string before encoding it</h3>
<pre class="brush:js">
function utf8_to_b64( str ) {
  return window.btoa(unescape(encodeURIComponent( str )));
}

function b64_to_utf8( str ) {
  return decodeURIComponent(escape(window.atob( str )));
}

// Usage:
utf8_to_b64('✓ à la mode'); // "4pyTIMOgIGxhIG1vZGU="
b64_to_utf8('4pyTIMOgIGxhIG1vZGU='); // "✓ à la mode"</pre>
<p>This solution has been proposed by <a href="http://ecmanaut.blogspot.com/2006/07/encoding-decoding-utf8-in-javascript.html">Johan Sundström</a>.</p>
<h3 id="Solution_.232_.E2.80.93_rewriting_atob()_and_btoa()_using_TypedArrays_and_UTF-8">Solution #2 – rewriting <code>atob()</code> and <code>btoa()</code> using <code>TypedArray</code>s and UTF-8</h3>
<div class="note">
  <strong>Note:</strong> The following code is also useful to get an <a href="/en-US/docs/Web/JavaScript/Typed_arrays/ArrayBuffer">ArrayBuffer</a> from a <em>Base64</em> string and/or viceversa (<a href="#Appendix.3A_Decode_a_Base64_string_to_Uint8Array_or_ArrayBuffer" title="#Appendix.3A_Decode_a_Base64_string_to_Uint8Array_or_ArrayBuffer">see below</a>). <strong>For a complete typed arrays library, see <a href="/en-US/docs/Web/JavaScript/Typed_arrays/StringView" title="/en-US/docs/Web/JavaScript/Typed_arrays/StringView">this article</a></strong>.</div>
<pre class="brush: js">
"use strict";

/*\
|*|
|*|&nbsp; Base64 / binary data / UTF-8 strings utilities
|*|
|*|&nbsp; https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding
|*|
\*/

/* Array of bytes to base64 string decoding */

function b64ToUint6 (nChr) {

&nbsp; return nChr &gt; 64 &amp;&amp; nChr &lt; 91 ?
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nChr - 65
&nbsp;&nbsp;&nbsp; : nChr &gt; 96 &amp;&amp; nChr &lt; 123 ?
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nChr - 71
&nbsp;&nbsp;&nbsp; : nChr &gt; 47 &amp;&amp; nChr &lt; 58 ?
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nChr + 4
&nbsp;&nbsp;&nbsp; : nChr === 43 ?
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 62
&nbsp;&nbsp;&nbsp; : nChr === 47 ?
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 63
&nbsp;&nbsp;&nbsp; :
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0;

}

function base64DecToArr (sBase64, nBlocksSize) {

&nbsp; var
&nbsp;&nbsp;&nbsp; sB64Enc = sBase64.replace(/[^A-Za-z0-9\+\/]/g, ""), nInLen = sB64Enc.length,
&nbsp;&nbsp;&nbsp; nOutLen = nBlocksSize ? Math.ceil((nInLen * 3 + 1 &gt;&gt; 2) / nBlocksSize) * nBlocksSize : nInLen * 3 + 1 &gt;&gt; 2, taBytes = new Uint8Array(nOutLen);

&nbsp; for (var nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx &lt; nInLen; nInIdx++) {
&nbsp;&nbsp;&nbsp; nMod4 = nInIdx &amp; 3;
&nbsp;&nbsp;&nbsp; nUint24 |= b64ToUint6(sB64Enc.charCodeAt(nInIdx)) &lt;&lt; 18 - 6 * nMod4;
&nbsp;&nbsp;&nbsp; if (nMod4 === 3 || nInLen - nInIdx === 1) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (nMod3 = 0; nMod3 &lt; 3 &amp;&amp; nOutIdx &lt; nOutLen; nMod3++, nOutIdx++) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; taBytes[nOutIdx] = nUint24 &gt;&gt;&gt; (16 &gt;&gt;&gt; nMod3 &amp; 24) &amp; 255;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nUint24 = 0;

&nbsp;&nbsp;&nbsp; }
&nbsp; }

&nbsp; return taBytes;
}

/* Base64 string to array encoding */

function uint6ToB64 (nUint6) {

&nbsp; return nUint6 &lt; 26 ?
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nUint6 + 65
&nbsp;&nbsp;&nbsp; : nUint6 &lt; 52 ?
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nUint6 + 71
&nbsp;&nbsp;&nbsp; : nUint6 &lt; 62 ?
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nUint6 - 4
&nbsp;&nbsp;&nbsp; : nUint6 === 62 ?
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 43
&nbsp;&nbsp;&nbsp; : nUint6 === 63 ?
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 47
&nbsp;&nbsp;&nbsp; :
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 65;

}

function base64EncArr (aBytes) {

&nbsp; var nMod3, sB64Enc = "";

&nbsp; for (var nLen = aBytes.length, nUint24 = 0, nIdx = 0; nIdx &lt; nLen; nIdx++) {
&nbsp;&nbsp;&nbsp; nMod3 = nIdx % 3;
&nbsp;&nbsp;&nbsp; if (nIdx &gt; 0 &amp;&amp; (nIdx * 4 / 3) % 76 === 0) { sB64Enc += "\r\n"; }
&nbsp;&nbsp;&nbsp; nUint24 |= aBytes[nIdx] &lt;&lt; (16 &gt;&gt;&gt; nMod3 &amp; 24);
&nbsp;&nbsp;&nbsp; if (nMod3 === 2 || aBytes.length - nIdx === 1) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sB64Enc += String.fromCharCode(uint6ToB64(nUint24 &gt;&gt;&gt; 18 &amp; 63), uint6ToB64(nUint24 &gt;&gt;&gt; 12 &amp; 63), uint6ToB64(nUint24 &gt;&gt;&gt; 6 &amp; 63), uint6ToB64(nUint24 &amp; 63));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nUint24 = 0;
&nbsp;&nbsp;&nbsp; }
&nbsp; }

&nbsp; return sB64Enc.replace(/A(?=A$|$)/g, "=");

}

/* UTF-8 array to DOMString and vice versa */

function UTF8ArrToStr (aBytes) {

&nbsp; var sView = "";

&nbsp; for (var nPart, nLen = aBytes.length, nIdx = 0; nIdx &lt; nLen; nIdx++) {
&nbsp;&nbsp;&nbsp; nPart = aBytes[nIdx];
&nbsp;&nbsp;&nbsp; sView += String.fromCharCode(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nPart &gt; 251 &amp;&amp; nPart &lt; 254 &amp;&amp; nIdx + 5 &lt; nLen ? /* six bytes */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* (nPart - 252 &lt;&lt; 32) is not possible in ECMAScript! So...: */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (nPart - 252) * 1073741824 + (aBytes[++nIdx] - 128 &lt;&lt; 24) + (aBytes[++nIdx] - 128 &lt;&lt; 18) + (aBytes[++nIdx] - 128 &lt;&lt; 12) + (aBytes[++nIdx] - 128 &lt;&lt; 6) + aBytes[++nIdx] - 128
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : nPart &gt; 247 &amp;&amp; nPart &lt; 252 &amp;&amp; nIdx + 4 &lt; nLen ? /* five bytes */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (nPart - 248 &lt;&lt; 24) + (aBytes[++nIdx] - 128 &lt;&lt; 18) + (aBytes[++nIdx] - 128 &lt;&lt; 12) + (aBytes[++nIdx] - 128 &lt;&lt; 6) + aBytes[++nIdx] - 128
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : nPart &gt; 239 &amp;&amp; nPart &lt; 248 &amp;&amp; nIdx + 3 &lt; nLen ? /* four bytes */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (nPart - 240 &lt;&lt; 18) + (aBytes[++nIdx] - 128 &lt;&lt; 12) + (aBytes[++nIdx] - 128 &lt;&lt; 6) + aBytes[++nIdx] - 128
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : nPart &gt; 223 &amp;&amp; nPart &lt; 240 &amp;&amp; nIdx + 2 &lt; nLen ? /* three bytes */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (nPart - 224 &lt;&lt; 12) + (aBytes[++nIdx] - 128 &lt;&lt; 6) + aBytes[++nIdx] - 128
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : nPart &gt; 191 &amp;&amp; nPart &lt; 224 &amp;&amp; nIdx + 1 &lt; nLen ? /* two bytes */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (nPart - 192 &lt;&lt; 6) + aBytes[++nIdx] - 128
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : /* nPart &lt; 127 ? */ /* one byte */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nPart
&nbsp;&nbsp;&nbsp; );
&nbsp; }

&nbsp; return sView;

}

function strToUTF8Arr (sDOMStr) {

&nbsp; var aBytes, nChr, nStrLen = sDOMStr.length, nArrLen = 0;

&nbsp; /* mapping... */

&nbsp; for (var nMapIdx = 0; nMapIdx &lt; nStrLen; nMapIdx++) {
&nbsp;&nbsp;&nbsp; nChr = sDOMStr.charCodeAt(nMapIdx);
&nbsp;&nbsp;&nbsp; nArrLen += nChr &lt; 0x80 ? 1 : nChr &lt; 0x800 ? 2 : nChr &lt; 0x10000 ? 3 : nChr &lt; 0x200000 ? 4 : nChr &lt; 0x4000000 ? 5 : 6;
&nbsp; }

&nbsp; aBytes = new Uint8Array(nArrLen);

&nbsp; /* transcription... */

&nbsp; for (var nIdx = 0, nChrIdx = 0; nIdx &lt; nArrLen; nChrIdx++) {
&nbsp;&nbsp;&nbsp; nChr = sDOMStr.charCodeAt(nChrIdx);
&nbsp;&nbsp;&nbsp; if (nChr &lt; 128) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* one byte */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aBytes[nIdx++] = nChr;
&nbsp;&nbsp;&nbsp; } else if (nChr &lt; 0x800) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* two bytes */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aBytes[nIdx++] = 192 + (nChr &gt;&gt;&gt; 6);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aBytes[nIdx++] = 128 + (nChr &amp; 63);
&nbsp;&nbsp;&nbsp; } else if (nChr &lt; 0x10000) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* three bytes */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aBytes[nIdx++] = 224 + (nChr &gt;&gt;&gt; 12);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aBytes[nIdx++] = 128 + (nChr &gt;&gt;&gt; 6 &amp; 63);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aBytes[nIdx++] = 128 + (nChr &amp; 63);
&nbsp;&nbsp;&nbsp; } else if (nChr &lt; 0x200000) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* four bytes */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aBytes[nIdx++] = 240 + (nChr &gt;&gt;&gt; 18);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aBytes[nIdx++] = 128 + (nChr &gt;&gt;&gt; 12 &amp; 63);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aBytes[nIdx++] = 128 + (nChr &gt;&gt;&gt; 6 &amp; 63);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aBytes[nIdx++] = 128 + (nChr &amp; 63);
&nbsp;&nbsp;&nbsp; } else if (nChr &lt; 0x4000000) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* five bytes */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aBytes[nIdx++] = 248 + (nChr &gt;&gt;&gt; 24);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aBytes[nIdx++] = 128 + (nChr &gt;&gt;&gt; 18 &amp; 63);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aBytes[nIdx++] = 128 + (nChr &gt;&gt;&gt; 12 &amp; 63);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aBytes[nIdx++] = 128 + (nChr &gt;&gt;&gt; 6 &amp; 63);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aBytes[nIdx++] = 128 + (nChr &amp; 63);
&nbsp;&nbsp;&nbsp; } else /* if (nChr &lt;= 0x7fffffff) */ {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* six bytes */
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aBytes[nIdx++] = 252 + /* (nChr &gt;&gt;&gt; 32) is not possible in ECMAScript! So...: */ (nChr / 1073741824);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aBytes[nIdx++] = 128 + (nChr &gt;&gt;&gt; 24 &amp; 63);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aBytes[nIdx++] = 128 + (nChr &gt;&gt;&gt; 18 &amp; 63);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aBytes[nIdx++] = 128 + (nChr &gt;&gt;&gt; 12 &amp; 63);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aBytes[nIdx++] = 128 + (nChr &gt;&gt;&gt; 6 &amp; 63);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aBytes[nIdx++] = 128 + (nChr &amp; 63);
&nbsp;&nbsp;&nbsp; }
&nbsp; }

&nbsp; return aBytes;

}
</pre>
<h4 id="Tests">Tests</h4>
<pre class="brush: js">
/* Tests */

var sMyInput = "Base 64 \u2014 Mozilla Developer Network";

var aMyUTF8Input = strToUTF8Arr(sMyInput);

var sMyBase64 = base64EncArr(aMyUTF8Input);

alert(sMyBase64);

var aMyUTF8Output = base64DecToArr(sMyBase64);

var sMyOutput = UTF8ArrToStr(aMyUTF8Output);

alert(sMyOutput);</pre>
<h4 id="Appendix.3A_Decode_a_Base64_string_to_Uint8Array_or_ArrayBuffer">Appendix: Decode a <em>Base64</em> string to <a href="/en-US/docs/Web/JavaScript/Typed_arrays/Uint8Array">Uint8Array</a> or <a href="/en-US/docs/Web/JavaScript/Typed_arrays/ArrayBuffer">ArrayBuffer</a></h4>
<p>These function let us to create also <a href="/en-US/docs/Web/JavaScript/Typed_arrays/Uint8Array">uint8Arrays</a> or <a href="/en-US/docs/Web/JavaScript/Typed_arrays/ArrayBuffer">arrayBuffers</a> from <em>base64</em>-encoded strings:</p>
<pre class="brush: js">
var myArray = base64DecToArr("QmFzZSA2NCDigJQgTW96aWxsYSBEZXZlbG9wZXIgTmV0d29yaw=="); // "Base 64 \u2014 Mozilla Developer Network"

var myBuffer = base64DecToArr("QmFzZSA2NCDigJQgTW96aWxsYSBEZXZlbG9wZXIgTmV0d29yaw==").buffer; // "Base 64 \u2014 Mozilla Developer Network"

alert(myBuffer.byteLength);</pre>
<div class="note">
  <strong>Note:</strong> The function <code>base64DecToArr(sBase64[, <em>nBlocksSize</em>])</code> returns an <a href="/en-US/docs/Web/JavaScript/Typed_arrays/Uint8Array"><code>uint8Array</code></a> of bytes. If your aim is to build a buffer of 16-bit / 32-bit / 64-bit raw data, use the <code>nBlocksSize</code> argument, which is the number of bytes of which the <code>uint8Array.buffer.bytesLength</code> property must result a multiple (<code>1</code> or omitted for ASCII, <a href="https://developer.mozilla.org/en-US/docs/Web/API/DOMString/Binary">binary strings</a> or UTF-8-encoded strings, <code>2</code> for UTF-16 strings, <code>4</code> for UTF-32 strings).</div>
<p>For a more complete library, see <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays/StringView" title="/en-US/docs/Web/JavaScript/Typed_arrays/StringView"><code>StringView</code> – a C-like representation of strings based on typed arrays</a>.</p>
<h2 id="Functions_which_natively_return_Base64-encoded_strings_in_JavaScript">Functions which natively return <em>Base64</em>-encoded strings in JavaScript</h2>
<ul>
  <li>The <a href="/en-US/docs/Web/API/FileReader#readAsDataURL()" title="/en-US/docs/Web/API/FileReader#readAsDataURL()"><code>readAsDataURL()</code></a> method of the <a href="/en-US/docs/Web/API/FileReader" title="/en-US/docs/Web/API/FileReader"><code>FileReader</code> API</a></li>
  <li>The <code><code>toDataURL()</code> and toDataURLHD()</code> methods of the <a href="/en-US/docs/Web/API/HTMLCanvasElement" title="/en-US/docs/Web/API/HTMLCanvasElement"><code>HTMLCanvasElement</code></a> interface</li>
</ul>
<h2 id="See_also">See also</h2>
<ul>
  <li>{{domxref("window.atob","atob()")}}</li>
  <li>{{domxref("window.btoa","btoa()")}}</li>
  <li><a href="/en-US/docs/data_URIs" title="/en-US/docs/data_URIs"><code>data</code> URIs</a></li>
  <li><a href="/en-US/docs/Web/JavaScript/Typed_arrays/ArrayBuffer">ArrayBuffer</a></li>
  <li><a href="/en-US/docs/Web/JavaScript/Typed_arrays">TypedArrays</a></li>
  <li><a href="/en-US/docs/Web/JavaScript/Typed_arrays/ArrayBufferView">ArrayBufferView</a></li>
  <li><a href="/en-US/docs/Web/JavaScript/Typed_arrays/Uint8Array">Uint8Array</a></li>
  <li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays/StringView" title="/en-US/docs/Web/JavaScript/Typed_arrays/StringView"><code>StringView</code> – a C-like representation of strings based on typed arrays</a></li>
  <li><a href="/en-US/docs/Web/API/DOMString" title="/en-US/docs/Web/API/DOMString">DOMString</a></li>
  <li><a href="/en-US/docs/URI" title="/en-US/docs/URI"><code>URI</code></a></li>
  <li><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI"><code>encodeURI()</code></a></li>
  <li><a href="/en-US/docs/XPCOM_Interface_Reference/nsIURIFixup" title="/en-US/docs/XPCOM_Interface_Reference/nsIURIFixup"><code>nsIURIFixup()</code></a></li>
  <li><a href="https://en.wikipedia.org/wiki/Base64" title="https://en.wikipedia.org/wiki/Base64"><code>Base64 on Wikipedia</code></a></li>
</ul>
Revert to this revision