Cuando partimos de una imagen codificada en una cadena Base64 se precisan varios pasos para poder visualizarla. Esto se complica cuando no sabemos el formato gráfico. Para solucionar el problema tenemos armamento pesado en GDIplus. Partiendo de éste truco en el que mostré como visualizar una imagen desde un fichero y en varios formatos, vamos a modificarlo para que lo haga desde un TStream:
uses Windows, ActiveX, SysUtils, Classes; function GdiplusStartup(var GdiToken: DWORD; Startup, Output: PBYTE): DWORD; stdcall external 'gdiplus'; function GdipCreateBitmapFromStream(stream: IStream; var GBitmap: THANDLE): DWORD; stdcall external 'gdiplus'; function GdipCreateHBITMAPFromBitmap(GBitmap: THANDLE; var hBitmap: HBITMAP; BKColor: DWORD): DWORD; stdcall external 'gdiplus'; procedure GdiplusShutdown(GdiToken: DWORD); stdcall external 'gdiplus'; function CreateHBITMAPFromStream(MStream: TMemoryStream ): HBITMAP; var FileName: array of WCHAR; gdiplusToken: DWORD; GdiPlusStartupInput: array[0..2] of int64; GBitmap: THANDLE; hMem: HGLOBAL; Memory: Pointer; Stream: IStream; begin Result:= 0; // Inicializamos GDI+. GdiPlusStartupInput[0]:= 1; GdiPlusStartupInput[1]:= 0; if GdiplusStartup(gdiplusToken, @GdiPlusStartupInput, nil) = 0 then begin if CreateStreamOnHGlobal(0, TRUE, Stream) = S_OK then begin if Stream.SetSize(MStream.Size) = S_OK then if GetHGlobalFromStream(Stream, hMem) = S_OK then begin Memory:= GlobalLock(hMem); if Memory <> nil then begin CopyMemory(Memory, MStream.Memory, MStream.Size); if GdipCreateBitmapFromStream(Stream, GBitmap) = S_OK then GdipCreateHBITMAPFromBitmap(GBitmap, Result, 0); end; GlobalUnlock(hMem); end; //Stream.Release; end; // Cerramos GDI+ GdiplusShutdown(gdiplusToken); end; end;
El resto simplemente consiste en decodificar la cadena Base64 en un TMemoryStream que pasaremos a la función anterior.
function CryptStringToBinary(pszString: PChar; cchString: DWORD; dwFlags: DWORD; pbBinary: PByte; var pcbBinary: DWORD; pdwSkip: PDWORD; pdwFlags: PDWORD): BOOL; stdcall; external 'Crypt32.dll' name 'CryptStringToBinaryA'; function StrB64ToStream(var Str: String; MStream: TMemoryStream): boolean; var Size: DWORD; begin Result:= CryptStringToBinary(@Str[1], Length(Str), 1, 0, Size, nil, nil); if Result then begin MStream.SetSize(Size); Result:= CryptStringToBinary(@Str[1], Length(Str), 1, MStream.Memory, Size, nil, nil); end; end;
Lo siguiente es un ejemplo de como usar el código expuesto:
var StreamBase64: String; // Cadena donde tenemos la imagen Base64 MStream: TMemoryStream; begin //... MStream:= TMemoryStream.Create; StrB64ToStream(StreamBase64, MStream); Image1.Picture.Bitmap.Handle:= CreateHBITMAPFromStream(MStream); MStream.Free; end;
Espero que el código sea útil.
Saludos.
Edito para arreglar etiquetas de código