Ir al contenido


Foto

[MULTILENGUAJE] Mostrar imagen codificada Base64


  • Por favor identifícate para responder
5 respuestas en este tema

#1 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 20 septiembre 2012 - 03:56

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:
 


delphi
  1. uses Windows, ActiveX, SysUtils, Classes;
  2.  
  3. function GdiplusStartup(var GdiToken: DWORD; Startup, Output: PBYTE): DWORD; stdcall external 'gdiplus';
  4. function GdipCreateBitmapFromStream(stream: IStream; var GBitmap: THANDLE): DWORD; stdcall external 'gdiplus';
  5. function GdipCreateHBITMAPFromBitmap(GBitmap: THANDLE; var hBitmap: HBITMAP; BKColor: DWORD): DWORD; stdcall external 'gdiplus';
  6. procedure GdiplusShutdown(GdiToken: DWORD); stdcall external 'gdiplus';
  7.  
  8. function CreateHBITMAPFromStream(MStream: TMemoryStream ): HBITMAP;
  9. var
  10.   FileName: array of WCHAR;
  11.   gdiplusToken: DWORD;
  12.   GdiPlusStartupInput: array[0..2] of int64;
  13.   GBitmap: THANDLE;
  14.   hMem: HGLOBAL;
  15.   Memory: Pointer;
  16.   Stream: IStream;
  17. begin
  18.   Result:= 0;
  19.  
  20.   // Inicializamos GDI+.
  21.   GdiPlusStartupInput[0]:= 1; GdiPlusStartupInput[1]:= 0;
  22.   if GdiplusStartup(gdiplusToken, @GdiPlusStartupInput, nil) = 0 then
  23.   begin
  24.     if CreateStreamOnHGlobal(0, TRUE, Stream) = S_OK then
  25.     begin
  26.       if Stream.SetSize(MStream.Size) = S_OK then
  27.         if GetHGlobalFromStream(Stream, hMem) = S_OK then
  28.         begin
  29.           Memory:= GlobalLock(hMem);
  30.           if Memory <> nil then
  31.           begin
  32.             CopyMemory(Memory, MStream.Memory, MStream.Size);
  33.             if GdipCreateBitmapFromStream(Stream, GBitmap) = S_OK then
  34.               GdipCreateHBITMAPFromBitmap(GBitmap, Result, 0);
  35.           end;
  36.           GlobalUnlock(hMem);
  37.         end;
  38.       //Stream.Release;
  39.     end;
  40.  
  41.     // Cerramos GDI+
  42.     GdiplusShutdown(gdiplusToken);
  43.   end;
  44. end;

El resto simplemente consiste en decodificar la cadena Base64 en un TMemoryStream que pasaremos a la función anterior.
 


delphi
  1. function CryptStringToBinary(pszString: PChar; cchString: DWORD; dwFlags: DWORD;
  2.   pbBinary: PByte; var pcbBinary: DWORD; pdwSkip: PDWORD;
  3.   pdwFlags: PDWORD): BOOL; stdcall;
  4.   external 'Crypt32.dll' name 'CryptStringToBinaryA';
  5.  
  6.  
  7. function StrB64ToStream(var Str: String; MStream: TMemoryStream): boolean;
  8. var
  9.   Size: DWORD;
  10. begin
  11.   Result:= CryptStringToBinary(@Str[1], Length(Str),  1, 0, Size, nil, nil);
  12.   if Result then
  13.   begin
  14.     MStream.SetSize(Size);
  15.     Result:= CryptStringToBinary(@Str[1], Length(Str), 1, MStream.Memory, Size, nil, nil);
  16.   end;
  17. end;

Lo siguiente es un ejemplo de como usar el código expuesto:
 


delphi
  1. var
  2.   StreamBase64: String;            // Cadena donde tenemos la imagen Base64
  3.   MStream: TMemoryStream;
  4. begin
  5.   //...
  6.   MStream:= TMemoryStream.Create;
  7.   StrB64ToStream(StreamBase64, MStream);
  8.   Image1.Picture.Bitmap.Handle:= CreateHBITMAPFromStream(MStream);
  9.   MStream.Free;
  10. end;

Espero que el código sea útil.


Saludos.

Edito para arreglar etiquetas de código


  • 0

#2 seoane

seoane

    Advanced Member

  • Administrador
  • 1.259 mensajes
  • LocationEspaña

Escrito 20 septiembre 2012 - 05:09

Aprovecho para hacer "spam"

http://code.google.c...se/#svn/SeCrypt

:cheesy:

  • 0

#3 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.419 mensajes
  • LocationRepública Dominicana

Escrito 20 septiembre 2012 - 06:50

¿Eso aplica en los casos de los SDK de huellas digitales que la mayoría usan BASE64?.

Saludos..
  • 0

#4 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 20 septiembre 2012 - 07:07

¿Eso aplica en los casos de los SDK de huellas digitales que la mayoría usan BASE64?.

Saludos..


Es aplicable a cualquier imagen codificada como Base64 soportada por GDIplus y que no esté, a su vez, encriptada.

Saludos.
  • 0

#5 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 20 septiembre 2012 - 12:37

Ahora que dispongo un ratito tranquilo, voy a publicar el código equivalente en C/C++:
 


cpp
  1. // Decodifica una cadena Encode64 a su binario original
  2. bool StrB64ToStream(String &Str, TMemoryStream* MStream)
  3. {
  4.   typedef BOOL (WINAPI *pCryptStringToBinary)(LPTSTR pszString, DWORD pcchString, DWORD dwFlags, BYTE *pbBinary, DWORD *cbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
  5.  
  6.   HMODULE hLib = LoadLibrary("Crypt32.dll");
  7.   if(!hLib) return false;
  8.  
  9.   pCryptStringToBinary CryptStringToBinary = (pCryptStringToBinary)GetProcAddress(hLib, "CryptStringToBinaryA");
  10.   DWORD Size;
  11.   bool Result = CryptStringToBinary(&Str[1], Str.Length(), 1, 0, &Size, 0, 0);
  12.   MStream->SetSize(Size);
  13.   Result = CryptStringToBinary(&Str[1], Str.Length(), 1, (PBYTE)MStream->Memory, &Size, 0, 0);
  14.   FreeLibrary(hLib);
  15.   return Result;
  16. }
  17.  
  18. HBITMAP CreateHBITMAPFromStream(TMemoryStream *MStream)
  19. {
  20.   typedef DWORD (__stdcall *PGdiplusStartup)(ULONG_PTR *hToken, void *input, void *Output);
  21.   typedef void  (__stdcall *PGdiplusShutdown)(ULONG_PTR token);
  22.   typedef DWORD (__stdcall *PGdipCreateBitmapFromStream)(IStream* stream, HANDLE* bitmap);
  23.   typedef DWORD (__stdcall *PGdipCreateHBITMAPFromBitmap)(HANDLE bitmap, HBITMAP* hBitmap, DWORD BKColor);
  24.   PGdiplusStartup GdiplusStartup = (PGdiplusStartup)GetProcAddress(LoadLibrary("gdiplus.dll"), "GdiplusStartup");
  25.   PGdipCreateBitmapFromStream GdipCreateBitmapFromStream = (PGdipCreateBitmapFromStream)GetProcAddress(LoadLibrary("gdiplus.dll"), "GdipCreateBitmapFromStream");
  26.   PGdipCreateHBITMAPFromBitmap GdipCreateHBITMAPFromBitmap = (PGdipCreateHBITMAPFromBitmap)GetProcAddress(LoadLibrary("gdiplus.dll"), "GdipCreateHBITMAPFromBitmap");
  27.   PGdiplusShutdown GdiplusShutdown = (PGdiplusShutdown)GetProcAddress(LoadLibrary("gdiplus.dll"), "GdiplusShutdown");
  28.   if(!GdiplusStartup || !GdiplusShutdown || !GdipCreateBitmapFromStream || !GdipCreateHBITMAPFromBitmap) return 0;
  29.  
  30.   // Inicializamos GDI+.
  31.   HBITMAP hBitmap = 0;
  32.   ULONG_PTR  gdiplusToken;
  33.   char GdiPlusStartupInput[16] = {1,0};
  34.   if(!GdiplusStartup(&gdiplusToken, GdiPlusStartupInput, NULL)){
  35.     HANDLE GBitmap = 0;
  36.     IStream* Stream;
  37.     if(CreateStreamOnHGlobal(0, TRUE, &Stream) == S_OK){
  38.       __int64 Size = MStream->Size;
  39.       Stream->SetSize(*(ULARGE_INTEGER*)&Size);
  40.       HGLOBAL hMem;
  41.       if(GetHGlobalFromStream(Stream, &hMem) == S_OK) {
  42.         void* Memory = GlobalLock(hMem);
  43.         if(Memory){
  44.           CopyMemory(Memory, MStream->Memory, Size);
  45.           if(GdipCreateBitmapFromStream(Stream, &GBitmap) == S_OK)
  46.             GdipCreateHBITMAPFromBitmap(GBitmap, &hBitmap, 0);
  47.         }
  48.         GlobalUnlock(hMem);
  49.         Stream->Release();
  50.       }
  51.     }
  52.     // Cerramos GDI+
  53.     GdiplusShutdown(gdiplusToken);
  54.   }
  55.   return hBitmap;
  56. }

Con un ejemplo de uso:


cpp
  1.   TMemoryStream* MStream = new TMemoryStream;
  2.   StrB64ToStream(ImageStringBase64, MStream);
  3.   Image1->Picture->Bitmap->Handle = CreateHBITMAPFromStream(MStream);
  4.   delete MStream;

Por el momento GDIplus soporta los formatos: BMP, GIF, JPEG, PNG, TIFF, WMF, EMF e ICON.

Espero que sea útil.


Saludos.
Edito para arreglar etiquetas de código


  • 0

#6 poliburro

poliburro

    Advanced Member

  • Administrador
  • 4.945 mensajes
  • LocationMéxico

Escrito 20 septiembre 2012 - 02:35

Caramba amigo... gracias por el aporte........
  • 0




IP.Board spam blocked by CleanTalk.