atob
Funkcja dekodowania Base64 zakodowany ciąg do nowego napisu z charakterem każdego bajta danych binarnych.
const byteCharacters = atob(b64Data);
Punkt kodowy każdego znaku (charCode) będzie wartością bajtu. Możemy utworzyć tablicę wartości bajtów, stosując tę .charCodeAt
metodę za pomocą metody dla każdego znaku w ciągu.
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
Możesz przekonwertować tablicę wartości bajtów na tablicę bajtów o typie rzeczywistym, przekazując ją do Uint8Array
konstruktora.
const byteArray = new Uint8Array(byteNumbers);
To z kolei można przekonwertować na BLOB, zawijając go w tablicę i przekazując do Blob
konstruktora.
const blob = new Blob([byteArray], {type: contentType});
Powyższy kod działa. Jednak wydajność można nieco poprawić, przetwarzając byteCharacters
mniejsze kawałki, a nie wszystkie naraz. W moich testach zgrubnych 512 bajtów wydaje się mieć dobry rozmiar wycinka. To daje nam następującą funkcję.
const b64toBlob = (b64Data, contentType='', sliceSize=512) => {
const byteCharacters = atob(b64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
const blob = new Blob(byteArrays, {type: contentType});
return blob;
}
const blob = b64toBlob(b64Data, contentType);
const blobUrl = URL.createObjectURL(blob);
window.location = blobUrl;
Pełny przykład:
const b64toBlob = (b64Data, contentType='', sliceSize=512) => {
const byteCharacters = atob(b64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
const blob = new Blob(byteArrays, {type: contentType});
return blob;
}
const contentType = 'image/png';
const b64Data = 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==';
const blob = b64toBlob(b64Data, contentType);
const blobUrl = URL.createObjectURL(blob);
const img = document.createElement('img');
img.src = blobUrl;
document.body.appendChild(img);
Oto bardziej minimalna metoda bez żadnych zależności i bibliotek.
Wymaga nowego interfejsu API pobierania. ( Czy mogę tego użyć? )
Za pomocą tej metody można również łatwo uzyskać ReadableStream, ArrayBuffer, tekst i JSON.
Jako funkcja:
Zrobiłem prosty test wydajności w stosunku do wersji synchronizacji ES6 Jeremy'ego.
Wersja synchronizacji blokuje interfejs użytkownika na chwilę. utrzymywanie devtoola otwartego może spowolnić działanie pobierania
Pokaż fragment kodu
źródło
createObjectURL
zamiastreadAsDataURL
jest na przykład znacznie lepszy. A jeśli przesyłasz pliki za pomocą ajax, wybierzFormData
zamiastJSON
lub użyjcanvas.toBlob
zamiasttoDataURL
await (await fetch(imageDataURL)).blob()
await fetch(url).then(r=>r.blob())
jest sorterAccess is denied.
błędu. Wydaje mi się, żefetch
ujawnia obiekt blob pod adresem URL obiektu blob - w ten sam sposóbURL.createObjectUrl
- który nie działa na ie11. odniesienie . Może jest jakieś obejście, aby użyć pobierania z IE11? Wygląda znacznie lepiej niż inne rozwiązania synchronizacji :)Zoptymalizowana (ale mniej czytelna) implementacja:
źródło
W przypadku wszystkich przeglądarek, zwłaszcza na Androidzie, możesz dodać:
źródło
W przypadku danych obrazu korzystanie z niego jest prostsze
canvas.toBlob
(asynchroniczne)źródło
image/jpg
z ciągu base64, a następnie przekazując go jako drugi parametr dotoBlob
funkcji, aby wynik był tego samego typu. Poza tym uważam, że jest to idealne - pozwala zaoszczędzić 30% ruchu i miejsca na dysku na serwerze (w porównaniu do base64) i działa dobrze nawet z przezroczystym PNG.Zobacz ten przykład: https://jsfiddle.net/pqhdce2L/
źródło
Zauważyłem, że Internet Explorer 11 staje się niesamowicie wolny podczas krojenia danych, jak sugerował Jeremy. Dotyczy to przeglądarki Chrome, ale wydaje się, że Internet Explorer ma problem z przesyłaniem podzielonych danych do Konstruktora obiektów blob. Na moim komputerze przekazanie 5 MB danych powoduje awarię programu Internet Explorer i zużycie pamięci spada. Chrome tworzy kroplę w mgnieniu oka.
Uruchom ten kod, aby porównać:
Dlatego postanowiłem zawrzeć obie metody opisane przez Jeremy'ego w jednej funkcji. Podziękowania należą się mu za to.
źródło
Dla wszystkich miłośników kopiowania i wklejania, takich jak ja, oto gotowana funkcja pobierania, która działa w Chrome, Firefox i Edge:
źródło
createObjectURL
nie akceptują 2nd argumentu ...Jeśli możesz znieść dodanie jednej zależności do swojego projektu, istnieje świetny
blob-util
pakiet npm, który zapewnia przydatnąbase64StringToBlob
funkcję. Po dodaniupackage.json
możesz użyć go w następujący sposób:źródło
Publikuję bardziej deklaratywny sposób synchronizacji konwersji Base64. Chociaż async
fetch().blob()
jest bardzo schludny i bardzo podoba mi się to rozwiązanie, nie działa on w przeglądarce Internet Explorer 11 (i prawdopodobnie Edge - nie testowałem tego), nawet z polifillem - spójrz na mój komentarz do Endless ' opublikuj po więcej szczegółów.Premia
Jeśli chcesz go wydrukować, możesz zrobić coś takiego:
Bonus x 2 - Otwarcie pliku BLOB w nowej karcie dla Internet Explorera 11
Jeśli możesz wykonać wstępne przetwarzanie ciągu Base64 na serwerze, możesz udostępnić go pod jakimś adresem URL i użyć linku
printJS
:)źródło
Poniżej znajduje się mój kod TypeScript, który można łatwo przekonwertować na JavaScript i można z niego korzystać
źródło
Typescript code
kod ma tylko POJEDYNCZY typ, a ten typ toany
. Na przykład, dlaczego w ogóle przeszkadzaMetoda z pobieraniem jest najlepszym rozwiązaniem, ale jeśli ktoś musi użyć metody bez pobierania, oto ona, ponieważ wspomniane wcześniej nie działały dla mnie:
źródło