Feedback

C# - Image in string wandeln und zurück

Veröffentlicht von am 01.12.2008
(1 Bewertungen)
Diese Snippets wandeln:
a) ein Image unter Angabe des ImageFormat in einen Base64String
b) einen Base64String wieder zurück in ein Image

Diese Methoden können z.B. bei der Serialisierung in eine XML Datei verwendet werden um Thumbs abzulegen.
public string ImageToBase64String( Image image, ImageFormat format )
{
   MemoryStream memory = new MemoryStream();
   image.Save( memory, format );
   string base64 = Convert.ToBase64String( memory.ToArray() );
   memory.Close();

   return base64;
}

public Image ImageFromBase64String( string base64 )
{
   MemoryStream memory = new MemoryStream( Convert.FromBase64String( base64 ) );
   Image result = Image.FromStream( memory );
   memory.Close();

   return result;
}
Abgelegt unter Image, Bitmap, Serialisieren, string, Base64String.

2 Kommentare zum Snippet

Günther Foidl schrieb am 02.12.2008:
Die Ressourcen des MemoryStreams werden nicht freigegeben (Dispose).
Dazu empfiehlt sich die Verwendung von

using (MemoryStream memory = new MemoryStream())
{
image.Save(memory, format);
string base64 = Convert.ToBase64String(memory.ToArray());
}

Das Close und Dispose wird dann automatisch erledigt - auch im Falle eines Fehlers.
AI schrieb am 16.01.2026:
Ich versuche mal, den gut 17 Jahre alten Code (veröffentlicht am 01.12.2008) in die aktuelle Zeit zu heben.

Die Idee „Bild <-> Base64-String“ ist weiterhin relevant, aber das Snippet hat heute ein paar echte Fallstricke: Streams werden manuell geschlossen statt sauber disposed, es wird unnötig kopiert (ToArray), und das Zurückwandeln ist in der gezeigten Form fehleranfällig, weil Image.FromStream den Stream oft länger benötigt als nur bis zum Return. Zusätzlich ist „Image“ hier System.Drawing, was seit .NET 6 auf Nicht-Windows nur eingeschränkt bzw. praktisch nicht mehr sinnvoll unterstützt ist (Server/Container/Linux).

Analyse nach heutigen Kriterien:
- Korrektheit: Image.FromStream kann den zugrunde liegenden Stream später noch verwenden. Den Stream direkt nach FromStream zu schließen/zu disposen kann später zu GDI+-Fehlern führen. Lösung: Bild klonen (entkoppeln) oder Stream-Lifetime an das Image koppeln.
- Ressourcen/Dispose: MemoryStream sollte per using/using var disposed werden, nicht per Close. Das gilt besonders bei Exceptions.
- Performance/Allokationen: memory.ToArray() kopiert die Daten. Besser ist Convert.ToBase64String über den internen Buffer (TryGetBuffer) ohne zusätzliche Kopie.
- Thread-Safety: Die Methoden sind als reine Umwandlung thread-safe. Das Image-Objekt selbst ist nicht für parallele Nutzung garantiert thread-safe; das ist aber ein fachliches Thema der Aufrufer.
- Cloud/Container: System.Drawing/Image ist in modernen, cross-platform Server-Setups problematisch. Wenn das in einer Web-API oder in Linux-Containern laufen soll, ist ein Wechsel auf eine echte cross-platform Imaging-Library sinnvoll oder das Feature muss als Windows-only gekennzeichnet werden.
- Sicherheit: Base64 ist keine Sicherheit, nur Darstellung. Außerdem sollte die Eingabe validiert werden (Null/Empty, FormatException). Bei untrusted Input: Größenlimits setzen, sonst drohen Memory-Pressure/DoS durch riesige Strings.

Modernisierte Variante (sauberes Dispose, weniger Kopien, Stream entkoppelt):

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;

public static class ImageBase64
{
public static string ImageToBase64String(Image image, ImageFormat format)
{
if (image is null) throw new ArgumentNullException(nameof(image));
if (format is null) throw new ArgumentNullException(nameof(format));

using var ms = new MemoryStream();
image.Save(ms, format);

if (ms.TryGetBuffer(out ArraySegment<byte> buffer))
return Convert.ToBase64String(buffer.Array!, buffer.Offset, (int)ms.Length);

return Convert.ToBase64String(ms.ToArray());
}

public static Image ImageFromBase64String(string base64)
{
if (base64 is null) throw new ArgumentNullException(nameof(base64));
if (base64.Length == 0) throw new ArgumentException("base64 must not be empty.", nameof(base64));

byte[] bytes = Convert.FromBase64String(base64);
using var ms = new MemoryStream(bytes, writable: false);
using var img = Image.FromStream(ms, useEmbeddedColorManagement: false, validateImageData: true);
return (Image)img.Clone();
}
}


Warum das heute objektiv besser ist:
- Korrektheit: Das zurückgegebene Image ist vom Stream entkoppelt; keine späteren Überraschungen durch disposed Streams.
- Robustheit: using/using var sorgt für korrektes Freigeben auch bei Exceptions.
- Performance: Vermeidet die zusätzliche Kopie durch ToArray in der Standard-Route (Fallback bleibt für alte/ungewöhnliche Fälle).
- Plattformrealität: Der Code ist weiterhin System.Drawing-basiert, aber die Einschränkung ist klar: Für echte Cross-Platform-Server sollte man das Imaging-Subsystem austauschen oder Windows-only deklarieren.

Security-Realitätscheck:
Bei Base64 aus untrusted Quellen sind Grenzen wichtig: maximal erlaubte String-Länge/Bytes, sonst kann ein Angreifer über sehr große Payloads Memory-Pressure erzeugen. Außerdem ist Base64 keine Verschlüsselung und kein Schutz vor Einsicht.
 

Logge dich ein, um hier zu kommentieren!