Ubah string base64 menjadi ArrayBuffer

105

Saya perlu mengubah string encode base64 menjadi ArrayBuffer. String base64 adalah input pengguna, string tersebut akan disalin dan ditempelkan dari email, jadi string tersebut tidak ada saat halaman dimuat. Saya ingin melakukan ini dalam javascript tanpa melakukan panggilan ajax ke server jika memungkinkan.

Saya menemukan tautan itu menarik, tetapi tidak membantu saya:

ArrayBuffer ke string berenkode base64

ini tentang konversi kebalikan, dari ArrayBuffer ke base64, bukan sebaliknya

http://jsperf.com/json-vs-base64/2

ini terlihat bagus tetapi saya tidak tahu cara menggunakan kode.

Apakah ada cara mudah (mungkin asli) untuk melakukan konversi? Terima kasih

Tony
sumber

Jawaban:

153

Coba ini:

function _base64ToArrayBuffer(base64) {
    var binary_string = window.atob(base64);
    var len = binary_string.length;
    var bytes = new Uint8Array(len);
    for (var i = 0; i < len; i++) {
        bytes[i] = binary_string.charCodeAt(i);
    }
    return bytes.buffer;
}
Goran.it
sumber
4
Tolong jelaskan saya apa yang sebenarnya terjadi di sini.
Govi S
4
Ini cukup mudah, pertama kita mendekode string base64 (atob), lalu kita membuat array baru bilangan bulat unsigned 8-bit dengan panjang yang sama dengan string yang didekodekan. Setelah itu kita mengulang string dan mengisi array dengan nilai Unicode dari setiap karakter dalam string.
Goran.it
2
Dari MDN: Base64 adalah sekelompok skema pengkodean biner-ke-teks serupa yang mewakili data biner dalam format string ASCII dengan menerjemahkannya ke dalam representasi radix-64. Larik yang diketik Uint8Array mewakili larik bilangan bulat unsigned 8-bit, dan kami bekerja dengan representasi data ASCII (yang juga merupakan tabel 8-bit) ..
Goran.it
3
Ini tidak benar. Ini memungkinkan javascript untuk menafsirkan byte sebagai string, yang memengaruhi data yang sebenarnya merupakan biner sejati.
Tomáš Zato - Kembalikan Monica
4
masalahnya adalah bahwa a) tidak setiap urutan byte adalah unicode yang valid b) tidak setiap karakter dalam unicode adalah satu byte jadi bytes[i] = binary_string.charCodeAt(i);bisa salah
campuran
54

Menggunakan TypedArray.from :

Uint8Array.from(atob(base64_string), c => c.charCodeAt(0))

Performa dibandingkan dengan versi for loop dari jawaban Goran.it.

ofavre
sumber
2
Untuk yang menyukai jenis satu liner ini, perlu diingat bahwa Uint8Array.frommasih memiliki sedikit kompatibilitas dengan beberapa browser.
IzumiSy
2
Harap tidak merekomendasikan atob atau btoa: developer.mozilla.org/en-US/docs/Web/API/WindowBase64/…
Kugel
rails compiler tidak bisa menangani string ini dan gagal dengan ExecJS::RuntimeError: SyntaxError: Unexpected token: operator (>); (rel 5)
Avael Kross
3
Ini bukan buffer array. Ini adalah array yang diketik. Anda mendapatkan akses ke buffer array melalui .bufferproperti dari apa yang dikembalikan dariUint8Array
oligofren
4
@Saites, Tidak ada yang salah dengan atobatau btoa, Anda hanya perlu memberi mereka masukan yang valid. atobmembutuhkan string base64 yang valid, jika tidak maka akan menimbulkan kesalahan. Dan btoamembutuhkan byte string yang valid (disebut juga string biner) yang merupakan string berisi karakter dalam kisaran 0-255. Jika string Anda memiliki karakter di luar rentang itu, btoaakan menimbulkan kesalahan.
Dapatkan Gratis
34

Jawaban Goran.it tidak berfungsi karena masalah unicode di javascript - https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding .

Saya akhirnya menggunakan fungsi yang diberikan di blog Daniel Guerrero: http://blog.danguer.com/2011/10/24/base64-binary-decoding-in-javascript/

Fungsi tercantum di tautan github: https://github.com/danguer/blog-examples/blob/master/js/base64-binary.js

Gunakan baris ini

var uintArray = Base64Binary.decode(base64_string);  
var byteArray = Base64Binary.decodeArrayBuffer(base64_string); 
Yaan
sumber
1
Cara ini 2x lebih cepat dibanding menggunakan atob.
xiaoyu2er
4
Dapatkah Anda memberikan contoh yang tidak akan berhasil? Artikel ini membahas tentang encoding string arbitrer, yang mungkin berisi karakter unicode, tetapi tidak berlaku untuk atobsemua itu.
riv
1
decodeArrayBuffermengembalikan ArrayBufferyang memiliki ukuran selalu habis dibagi 3, yang saya tidak mengerti apakah itu oleh desain atau bug. Saya akan bertanya di proyek github.
ceztko
@ceztko Mungkin karena desain (tidak disengaja). Algoritme pengkodean base64 mengambil grup yang terdiri dari 3 byte dan mengubahnya menjadi 4 karakter. Metode decode mungkin mengalokasikan ArrayBuffer yang panjangnya adalah base64String.length / 4 * 3 byte dan tidak pernah memotong byte yang tidak digunakan setelah selesai.
AlwaysLearning
1
@AlwaysLearning yang artinya mungkin disadap karena sisa nol byte dapat merusak konten keluaran yang diinginkan.
ceztko
23

Baru saja menemukan base64-arraybuffer, paket npm kecil dengan penggunaan yang sangat tinggi, 5 juta unduhan bulan lalu (2017-08).

https://www.npmjs.com/package/base64-arraybuffer

Untuk siapa saja yang mencari solusi standar terbaik, ini mungkin saja.

jv-dev
sumber
10

Solusi Async , lebih baik jika datanya besar:

// base64 to buffer
function base64ToBufferAsync(base64) {
  var dataUrl = "data:application/octet-binary;base64," + base64;

  fetch(dataUrl)
    .then(res => res.arrayBuffer())
    .then(buffer => {
      console.log("base64 to buffer: " + new Uint8Array(buffer));
    })
}

// buffer to base64
function bufferToBase64Async( buffer ) {
    var blob = new Blob([buffer], {type:'application/octet-binary'});    
    console.log("buffer to blob:" + blob)

    var fileReader = new FileReader();
    fileReader.onload = function() {
      var dataUrl = fileReader.result;
      console.log("blob to dataUrl: " + dataUrl);

      var base64 = dataUrl.substr(dataUrl.indexOf(',')+1)      
      console.log("dataUrl to base64: " + base64);
    };
    fileReader.readAsDataURL(blob);
}
张浩然
sumber
7

Untuk pengguna Node.js:

const myBuffer = Buffer.from(someBase64String, 'base64');

myBuffer akan berjenis Buffer yang merupakan subclass dari Uint8Array. Sayangnya, Uint8Array BUKAN sebuah ArrayBuffer seperti yang diminta OP. Tetapi ketika memanipulasi ArrayBuffer saya hampir selalu membungkusnya dengan Uint8Array atau yang serupa, jadi itu harus mendekati apa yang diminta.

DoomGoober
sumber
6

Javascript adalah lingkungan pengembangan yang bagus sehingga terlihat aneh daripada tidak memberikan solusi untuk masalah kecil ini. Solusi yang ditawarkan di tempat lain di halaman ini berpotensi lambat. Inilah solusi saya. Ini menggunakan fungsionalitas bawaan yang menerjemahkan url data gambar dan suara base64.

var req = new XMLHttpRequest;
req.open('GET', "data:application/octet;base64," + base64Data);
req.responseType = 'arraybuffer';
req.onload = function fileLoaded(e)
{
   var byteArray = new Uint8Array(e.target.response);
   // var shortArray = new Int16Array(e.target.response);
   // var unsignedShortArray = new Int16Array(e.target.response);
   // etc.
}
req.send();

Permintaan kirim gagal jika string basis 64 terbentuk dengan buruk.

Jenis pantomim (aplikasi / oktet) mungkin tidak diperlukan.

Diuji di chrome. Harus berfungsi di browser lain.

dinosaurclover
sumber
1
Ini adalah solusi sempurna bagi saya, sederhana dan bersih. Saya segera mengujinya di Firefox, IE 11, Edge dan bekerja dengan baik!
cs-NET
Saya tidak yakin bagaimana cara kerjanya untuk Anda di IE11, tetapi saya mendapatkan Access Deniedkesalahan, yang tampaknya menjadi batasan CORS.
Sergiu
2

JS murni - tanpa string middlestep (tanpa atob)

Saya menulis fungsi berikut yang mengubah base64 secara langsung (tanpa konversi ke string di middlestep). IDE

  • dapatkan 4 potongan karakter base64
  • temukan indeks setiap karakter dalam alfabet base64
  • konversikan indeks menjadi angka 6-bit (string biner)
  • gabungkan empat angka 6 bit yang memberikan angka 24-bit (disimpan sebagai string biner)
  • pisahkan string 24-bit menjadi tiga 8-bit dan ubah masing-masing menjadi angka dan simpan dalam larik keluaran
  • kasus sudut: jika input string base64 diakhiri dengan satu / dua =karakter, hapus satu / dua angka dari array output

Solusi di bawah ini memungkinkan untuk memproses string input base64 yang besar. Fungsi serupa untuk mengonversi byte ke base64 tanpa btoa ada DI SINI

Kamil Kiełczewski
sumber
jadi tidak ada yang hilang "."?
Gillsoft AB
Uji di browser, saya tidak yakin ini adalah hasil yang diharapkan? "Petualangan Alice di Negeri
Ajaib
1
@GillsoftAB terima kasih atas info ini - Anda benar - Saya memperbaiki masalah
Kamil Kiełczewski
-4
const str = "dGhpcyBpcyBiYXNlNjQgc3RyaW5n"
const encoded = new TextEncoder().encode(str) // is Uint8Array
const buf = encoded.buffer // is ArrayBuffer
Andrii Nemchenko
sumber
6
Perhatikan bahwa ini tidak melakukan decoding / encoding Base64. Ini hanya mengubah 6 byte "base64" menjadi 6-elemen ArrayBuffer atau Uint8Array.
dubek
2
@dubek itu yang ditanyakan.
Andrii Nemchenko