Over coderen met Base64

Soms zie je in een HTML-code een <img>-tag die eruit ziet als:

<img src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ...">

In CSS kun je iets dergelijks tegenkomen:

.mijn-class {
  background:url('data:image/jpeg;base64,/9j/4RiDRXhpZgAATU0AKgA...');
}

In beide gevallen staat er op de plaats van de filenaam een data-statement: image/jpeg;base64, gevolgd door een reeks letters, cijfers en een paar andere tekens.
Hiermee wordt aan de browser gemeld dat gaat om een image (plaatje) van het type .jpg en dat het plaatje is gecodeerd met base64. Er hoeft dus niet apart een plaatje te worden opgehaald en daardoor laadt de pagina sneller (mits de karakterreeks achter de komma niet al te groot is).

In HTML kun je dit toepassen in alle tags die iets doen met binaire data: <img>, <audio>, <video>, enz.

In CSS is de toepasbaarheid beperkt tot achtergrond-afbeeldingen, in de eigenschap background.

De meest voorkomende grafische formaten die met image worden gebruikt zijn jpeg, gif, png en svg+xml.

Het keyword image wordt het MIME-type genoemd. MIME betekent Multi-purpose Internet Mail Extensions. Oorspronkelijk is het ontwikkeld om plaatjes en andere zaken te embedden in e-mail berichten, maar het is ook toepasbaar gemaakt in HTML en CSS.

Naast image bestaan er nog veel andere MIME-types. In HTML kun je Base64-codering toepassen op images, audio, video, pdf, zip, en nog veel meer. Zie bijvoorbeeld het (niet complete!) overzicht op https://www.sitepoint.com/mime-types-complete-list/. Je vindt daar behalve MIME-type ook de aanduidingen voor het soort gegevens dat kan worden toegepast.

Hoe het werkt
Base64 is in eerste aanleg een methode om (onleesbare) binaire informatie om te zetten in leesbare tekst (ASCII-tekens), zodat het eenvoudig en betrouwbaar kan wordt uitgewisseld tussen computers, waarbij die computers niet dezelfde hardware en/of operating system hoeven te hebben. Het is echter ook mogelijk om leesbare tekst hiermee te coderen, zoals bij SVG-plaatjes gebeurt.

Base64 is een 6 bitscodering. Dat betekent dat er 26 = 64 verschillende tekens zijn, vandaar de naam base64. Dit zijn de tekens: A ... Z a ...z 0 ... 9 + / =

De data wordt verdeeld in groepjes van zes bits. Er worden zo nodig twee of vier nullen aan toegevoegd, zodat het aantal bits altijd een zesvoud is.
Elk blokje van zes bits wordt omgezet in een decimaal getal. Dat is een getal ≥ 0 en ≤ 63. Dat is de index van het teken uit de code-reeks.
Het =-teken wordt alleen gebruikt om de extra paren nullen aan te geven om het laatste blokje aan te vullen tot 6 bits.

Dit wordt verduidelijkt aan de hand van een voorbeeld, dat is overgenomen van Wikipedia:

De string π ∈ ℜ wordt gecodeerd met base64. De karakterset is UTF-8.
Dat is omgezet in bitpatronen van 2 bytes (16 bits) per karakter.
Vervolgens worden daar blokjes van 6 bits van gemaakt. Daarna worden omgerekend in decimale getallen en worden de karakters bepaald.

Karakterπ(spatie)(spatie)
Binair1100 1111
1000 0000
0010 0000
1110 0010
1000 1000
1000 1000
0010 0000
1110 0010
1000 0100
1001 1101

Er zijn 10 bytes, dat is 80 bits. Om daar blokjes van 6 van te kunnen maken, zijn er vier extra nullen nodig. De gecodeerde string eindigt dus met twee =-tekens.
Zie onderstaande tabel. Er zijn 14 blokjes van 6 bits. De extra nullen zijn vet gedrukt.

Blokjes van 6110011111000000000100000111000101000100010
Decimaal5156032564034
base64 karakterz4Ag4oi
Blokjes van 6001000001000001110001010000100100111010000
Decimaal88141043916
base64 karakterIIOKEnQ

Het uiteindelijke resultaat is: z4Ag4oiIIOKEnQ==

Opmerking: De binaire codes voor π, ∈, ℜ en de spatie komen niet overeen met hexadecimale code die in de UTF-8 tabel staan. Hier staat voor π (binair): 1100 1111 1000 0000, wat overeenkomt met (hexadecimaal) CF80. Volgens de UTF-8 tabel moet dat zijn: 03C0, ofwel 0000 0011 1100 0000.
Ik begrijp het verschil niet, temeer omdat het resultaat dat je krijgt door coderen-decoderen met diverse online base64 conversie-programma's wel het resultaat geven dat hier wordt getoond.
Stuur me a.u.b. een mailtje als je weet hoe dit in elkaar steekt.

Als je een tekst codeert die extended characters bevat, moet je coderen en decoderen in dezelfde karakterset.
Voorbeeld: codeer de string: a2 + b2 = c2

  1. coderen met ISO-8859-1 geeft YbIgKyBisiA9IGOy
  2. coderen met UTF-8 geeft YcKyICsgYsKyID0gY8Ky

Als je de string I (ISO-8859-1) decodeert met UTF-8 verlies je de kwadraten. Je krijgt:
  a + b = c
Als je string II (UTF-8) decodeert met ISO-8859-1 krijg je er wat extra's bij:
  aÂ2 + bÂ2 = cÂ2

Zelf doen
Op een van mijn andere websites, www.webmasterij.nl, kun je eenvoudig tooltje downloaden om zelf bestanden mee te coderen of te decoderen.
Ook op internet zijn veel websites te vinden waar je dit kunt doen. Zoek maar eens op "base64 encode decode online". Je hebt zo een hele lijst met hits. Houd wel in de gaten of je de karakterset goed kan instellen.

Elke moderne programmeertaal heeft wel mogelijkheden aan boord om strings met base64 te coderen en te decoderen.
In JavaScript heeft het window-object de methodes btoa() om te coderen en atob() om te decoderen. Deze functions werken prima zolang er geen extended characters worden gedecodeerd. De oorzaak is ook hier de karakterset. Op internet is wel JavaScript code te vinden die dit probleem omzeilt.

Tenslotte …
Een plaatje dat in een webdocument wordt opgenomen zoals hier wordt beschreven wordt ook wel inline-image genoemd.

Het met bases64 coderen van gegevens (al of niet in een webdocument) is geen beveiliging tegen ongewenst kopiëren. De methode om te decoderen is bekend, dus iedereen kan het.

Hierboven is beschreven dat elk groepje van 6 bits wordt opgeslagen in een byte (dus 8 bits). De lengte van de gecodeerde string is dus (ongeveer) 8/6 = 1,33 × de lengte van de originele string. Base64 is dus géén compressiemethode!

Hier en daar lees je wel eens dat de omvang van een plaatje in een <img>-tag beperkt is, omdat er maar een beperkte hoeveelheid informatie in een <img>-tag past.
Dat is tot op zekere hoogte waar. Een testje met een .JPG van 250 x 147 gaf geen problemen (Base64-string is 191 464 bytes).

 
terug

html-466; Laatste wijziging: 25 mei 2020