Charger un fichier
  1. base64hub
  2. Base64 dans le code
  3. Dart
Code

Base64 en Dart

La bibliothèque dart:convert de Dart contient des codecs Base64 pour les deux alphabets, plus une méthode normalize qui corrige le remplissage. Les sorties ci-dessous proviennent de Dart 3.13.

Encoder et décoder une chaîne

En interne, les chaînes Dart sont en UTF-16 : convertissez-les en octets UTF-8 avec utf8.encode avant d’encoder.

import 'dart:convert';

void main() {
  final enc = base64Encode(utf8.encode('héllo wörld'));
  print(enc);                            // aMOpbGxvIHfDtnJsZA==
  print(utf8.decode(base64Decode(enc))); // héllo wörld
}

base64Encode(bytes) est un raccourci pour base64.encode(bytes), et base64Decode(s) pour base64.decode(s). Si les octets décodés ne sont pas de l’UTF-8, utf8.decode lève FormatException: Invalid UTF-8 byte ; passez allowMalformed: true pour obtenir des caractères de remplacement à la place.

Les deux mêmes appels permettent de construire un en-tête HTTP Basic Auth, par exemple pour package:http :

final headers = {'Authorization': 'Basic ${base64Encode(utf8.encode('user:pass'))}'};
// Authorization: Basic dXNlcjpwYXNz

Le générateur d’en-tête Basic Auth affiche la même valeur pour n’importe quels identifiants.

Base64 URL-safe et normalize()

base64Url est un second codec, avec l’alphabet -_. Les deux encodeurs écrivent toujours le remplissage : supprimez-le si votre format n’en veut pas.

final d = utf8.encode('<<???>>');
print(base64Url.encode(d));                     // PDw_Pz8-Pg==
print(base64Url.encode(d).replaceAll('=', '')); // PDw_Pz8-Pg

C’est au décodage que Dart se montre plus accommodant que la plupart des langages. Les deux décodeurs acceptent les deux alphabets, mais exigent un remplissage correct. normalize corrige ce point et convertit aussi l’alphabet :

base64Url.normalize('PDw_Pz8-Pg');   // PDw_Pz8-Pg==
base64.normalize('PDw_Pz8-Pg');      // PDw/Pz8+Pg==

utf8.decode(base64Url.decode(base64Url.normalize('PDw_Pz8-Pg')));  // <<???>>
utf8.decode(base64Decode('PDw_Pz8-Pg=='));                         // <<???>>

normalize lève aussi une FormatException si l’entrée n’est pas du Base64 valide : elle sert donc également de validateur. Les segments d’un JWT sont en Base64URL sans remplissage ; voir Base64 ou Base64URL et le remplissage expliqué, ou collez-en un dans le décodeur JWT.

Avec normalize, lire le payload d’un JWT tient en une ligne :

const jwt = 'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0In0.sig';
final payload = utf8.decode(base64Url.decode(base64Url.normalize(jwt.split('.')[1])));
print(payload);                        // {"sub":"1234"}
print(jsonDecode(payload)['sub']);     // 1234

Cela ne fait que lire les claims, sans vérifier la signature : ne leur faites jamais confiance pour une autorisation côté client.

Encoder et décoder un fichier

import 'dart:io';

final bytes = await File('hello.txt').readAsBytes();
print(base64Encode(bytes));                              // aGVsbG8K
await File('copy.txt').writeAsBytes(base64Decode('aGVsbG8K'));

Gros fichiers en flux

base64.encoder et base64.decoder sont des transformateurs de flux : un fichier peut donc être converti morceau par morceau.

// encode: bytes -> Base64 text -> ASCII bytes on disk
await File('big.bin')
    .openRead()
    .transform(base64.encoder)
    .transform(ascii.encoder)
    .pipe(File('big.b64').openWrite());

// decode: ASCII bytes -> String chunks -> bytes
await File('big.b64')
    .openRead()
    .transform(ascii.decoder)
    .transform(base64.decoder)
    .pipe(File('big.out').openWrite());

Les transformateurs conservent les octets restants d’un morceau à l’autre : la taille des morceaux n’a pas d’importance. Dans les deux sens, un fichier de test de 300 Ko a donné, octet pour octet, le même résultat qu’avec les fonctions en mémoire.

Flutter : images et data URI

Pour afficher une image Base64 :

Image.memory(base64Decode(b64))

Pour produire du Base64 à partir d’un asset ou d’un fichier choisi, lisez les octets et appelez base64Encode. Pour les data URI, UriData gère le préfixe :

UriData.parse('data:text/plain;base64,aGk=').contentAsBytes();  // [104, 105]
UriData.fromBytes(pngBytes, mimeType: 'image/png').toString();   // data:image/png;base64,...

Passer directement une data URI à base64Decode échoue avec Invalid character (at character 5), c’est-à-dire le : après data. Pour savoir ce que contient une chaîne inconnue, Base64 en image en affiche un aperçu dans le navigateur.

Validation et messages FormatException

Toutes les erreurs de décodage sont des FormatException. toString() contient le message, l’entrée et un accent circonflexe sous le problème ; e.message et e.offset donnent ces éléments séparément. Avec base64Decode :

EntréeMessage
aGkInvalid length, must be multiple of four (at character 4)
aInvalid length, must be multiple of four (at character 2)
aGk=!!Invalid padding character (at character 5)
aGk==Invalid padding character (at character 5)
aGl=Invalid encoding before padding (at character 4)
"aGVs\nbG8K"Invalid character (at character 5)

Dart est strict sur deux points où beaucoup de langages sont tolérants : il rejette les sauts de ligne (supprimez-les pour une entrée MIME ou PEM) et les bits de remplissage non nuls (aGl=). Un test de validité :

bool isBase64(String s) {
  try {
    base64Decode(s);
    return true;
  } on FormatException {
    return false;
  }
}

Si une chaîne échoue et que le message ne suffit pas, le validateur Base64 signale le problème ; les erreurs Base64 courantes en détaillent les causes.

Pièges

  • Encoder codeUnits. base64Encode('é'.codeUnits) renvoie 6Q== (Latin-1, pas UTF-8), et '✓'.codeUnits lève ArgumentError: Invalid argument (Not a byte value at index 0: 0x2713). Passez toujours par utf8.encode.
  • Les sauts de ligne venus d’autres systèmes. Une sortie MIME issue d’un e-mail ou de base64 sous Linux contient des \n ; retirez d’abord les espaces avec s.replaceAll(RegExp(r'\s'), '').
  • Croire que base64Encode produit du URL-safe. Il écrit + et /. Utilisez base64Url.encode pour tout ce qui va dans une URL.
  • Pas de découpage MIME. Les codecs n’insèrent jamais de sauts de ligne. Coupez vous-même en lignes de 76 caractères si nécessaire.

FAQ

Comment afficher une image Base64 dans Flutter ?

Décodez en octets et utilisez Image.memory(base64Decode(b64)). Si la chaîne est une data URI, supprimez d’abord tout jusqu’à la virgule, ou utilisez UriData.parse(uri).contentAsBytes().

Pourquoi base64Decode affiche-t-il « Invalid length, must be multiple of four » ?

L’entrée n’a pas de remplissage, ce qui est typique des JWT et des jetons URL-safe. Appelez d’abord base64.normalize(s) ou base64Url.normalize(s) : la méthode ajoute les = manquants.

base64Decode accepte-t-il une entrée URL-safe ?

Oui. Le décodeur accepte à la fois +/ et -_ : base64Decode('PDw_Pz8-Pg==') fonctionne. Seuls les encodeurs diffèrent : base64 écrit +/, base64Url écrit -_.

Continuer la lecture