PDA

Ver la Versión Completa : Leer imagen y convertir su contenido a base64


Ramsay
10-02-2016, 04:14:17
Hola , necesito leer una imagen para convertir su contenido a base64 y usarlos en html facilmente , pero no encuentro referencias sobre como leer la imagen , ¿ como podria hacer esto ?

AgustinOrtu
10-02-2016, 04:59:32
Una alternativa es usando los componentes Indy:


unit Unit2;

interface

uses
Windows,
Messages,
SysUtils,
Variants,
Classes,
Graphics,
Controls,
Forms,
Dialogs,
StdCtrls,
ExtCtrls,
IdBaseComponent,
IdCoder,
IdCoder3to4,
IdCoderMIME;

type
TForm2 = class(TForm)
IdEncoderMIME1: TIdEncoderMIME;
imLoad: TImage;
OpenDialog1: TOpenDialog;
imBase64: TImage;
btnLoad: TButton;
btnToBase64: TButton;
IdDecoderMIME1: TIdDecoderMIME;
procedure btnLoadClick(Sender: TObject);
procedure btnToBase64Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.btnLoadClick(Sender: TObject);
begin
if not OpenDialog1.Execute then
Exit;

imLoad.Picture.LoadFromFile(OpenDialog1.FileName);
end;

procedure TForm2.btnToBase64Click(Sender: TObject);
var
AImageStream: TMemoryStream;
AStringStream: TStringStream;
ABase64, DecodedBase64: string;
begin
AImageStream := TMemoryStream.Create;
try
imLoad.Picture.Graphic.SaveToStream(AImageStream);
AImageStream.Position := 0;
ABase64 := IdEncoderMIME1.Encode(AImageStream);
finally
AImageStream.Free;
end;

DecodedBase64 := IdDecoderMIME1.DecodeString(ABase64);
AStringStream := TStringStream.Create(DecodedBase64);
try
AStringStream.Position := 0;
imBase64.Picture.Bitmap.LoadFromStream(AStringStream);
finally
AStringStream.Free;
end;
end;

end.

AgustinOrtu
10-02-2016, 05:03:25
Esta es otra forma similar a la anterior, pero usando metodos estaticos (de clase)


procedure TForm2.btnToBase64Click(Sender: TObject);
var
AStringStream: TStringStream;
ABase64, DecodedBase64: string;
begin
AStringStream := TStringStream.Create;
try
imLoad.Picture.Graphic.SaveToStream(AStringStream);
AStringStream.Position := 0;
ABase64 := TIdEncoderMIME.EncodeString(AStringStream.DataString);
finally
AStringStream.Free;
end;

DecodedBase64 := TIdDecoderMIME.DecodeString(ABase64);
AStringStream := TStringStream.Create(DecodedBase64);
try
AStringStream.Position := 0;
imBase64.Picture.Bitmap.LoadFromStream(AStringStream);
finally
AStringStream.Free;
end;
end;

AgustinOrtu
10-02-2016, 05:11:09
Y la ultima variante es utilizando las funciones definidas en la unidad Soap.EncdDecd:


var
AMemStream: TMemoryStream;
AStreamBase64, ADecodedStream: TStringStream;
ABase64, DecodedBase64: string;
begin
AMemStream := TMemoryStream.Create;
AStreamBase64 := TStringStream.Create;
try
imLoad.Picture.Bitmap.SaveToStream(AMemStream);
AMemStream.Position := 0;
EncodeStream(AMemStream, AStreamBase64);
AStreamBase64.Position := 0;
ABase64 := AStreamBase64.DataString;
finally
AStreamBase64.Free;
end;

DecodedBase64 := DecodeString(ABase64);
ADecodedStream := TStringStream.Create(DecodedBase64);
try
ADecodedStream.Position := 0;
imBase64.Picture.Bitmap.LoadFromStream(ADecodedStream);
finally
ADecodedStream.Free;
end;


Esta ultima fue la que logro replicar la imagen exactamente a como estaba antes; curioso que los componentes Indy tengan alguna falla

Las pruebas las hice con formato BMP

ElKurgan
10-02-2016, 09:22:01
¿En que Delphi estás probando?

Yo estoy haciendo la prueba de la función de Soap en Delphi XE7 y no decodifica bien, me devuelve una excepción "EEncodingError": No mapping for the Unicode character exists in the target multi-byte code page"

No tengo ni idea de porqué pasa esto... :(

AgustinOrtu
10-02-2016, 09:46:01
Los 3 ejemplos Delphi 2010

Cual te da error? El componente Indy te permite especificar un TEncoding que creo que es lo que te esta fallando

ElKurgan
10-02-2016, 11:20:37
Los componentes Indy no me dan error, eso si, no decodifican bien. Es justamente la línea siguiente



DecodedBase64 := DecodeString(ABase64);


¿Tendrá que ver con la configuración del equipo y la página de códigos?

En fin, gracias y un saludo

escafandra
10-02-2016, 20:10:27
Yo utilizo la API para esos fines:


const
CRYPT_STRING_BASE64 = 1;

function CryptBinaryToString(pbBinary: PByte; cbBinary: DWORD; dwFlags: DWORD;
pszString: PChar; var pcchString: DWORD): BOOL; stdcall;
external 'Crypt32.dll' name 'CryptBinaryToStringA';

function CryptStringToBinary(pszString: PChar; cchString: DWORD; dwFlags: DWORD;
pbBinary: PByte; var pcbBinary: DWORD; pdwSkip: PDWORD;
pdwFlags: PDWORD): BOOL; stdcall;
external 'Crypt32.dll' name 'CryptStringToBinaryA';

//---------------------------------------------------------------------------
// Codifica un TNMemoryStrean a cadena Encode64
function StreamToStrB64(MStream: TMemoryStream; var Str: String): boolean;
var
Size: DWORD;
begin
Result:= CryptBinaryToString(MStream.Memory, MStream.Size, CRYPT_STRING_BASE64, 0 , Size);
if Result then
begin
SetLength(Str, Size);
Result:= CryptBinaryToString(MStream.Memory, MStream.Size, CRYPT_STRING_BASE64, @Str[1], Size);
end;
end;

//---------------------------------------------------------------------------
// Decodifica una cadena Encode64 a su binario original en un TMemoryStream
function StrB64ToStream(var Str: String; MStream: TMemoryStream): boolean;
var
Size: DWORD;
begin
Result:= CryptStringToBinary(@Str[1], Length(Str), CRYPT_STRING_BASE64, 0, Size, nil, nil);
if Result then
begin
MStream.SetSize(Size);
Result:= CryptStringToBinary(@Str[1], Length(Str), CRYPT_STRING_BASE64, MStream.Memory, Size, nil, nil);
end;
end;


Para el tema en cuestión, el uso sería:


var
MStream: TMemoryStream;
S: String; // Aquí tendremos la cadena BASE64 de la Imagen
begin
MStream:= TMemoryStream.Create;
Image1.Picture.Bitmap.SaveToStream(MStream);
StreamToStrB64(MStream, S);
MStream.Free;
end;


Por si interesa, aquí (http://delphiaccess.com/foros/index.php/topic/8239-multilenguaje-mostrar-imagen-codificada-base64/) mostré un ejemplo de como leer una imagen codificada en BASE64 sin conocer el tipo de la misma usando GDI+.


Saludos,

escafandra
10-02-2016, 20:16:36
Una aclaración:

Hay que tener en cuenta que la API CryptBinaryToString (http://msdn.microsoft.com/en-us/library/aa379887%28VS.85%29.aspx), cuando la usamos para codificar en Base64 (CRYPT_STRING_BASE64) codifica el buffer pasado completo y le añade un retorno de carro (13) y otro de línea (10) y un nulo final. Cuando se encripta una cadena PCHAR, el cero final también lo encripta.

No he probado con Inddy, pero el detalle que describo puede ocasionar errores aparentes en el cifrado-descifrado.


Saludos.

AgustinOrtu
10-02-2016, 20:31:24
Excelente como siempre escafandra

Otra forma de leer *cualquier tipo de imagen* sin conocer el formato se expone aca Vcl.BlobImageLoader (https://github.com/ortuagustin/Delphi-Utils/blob/master/Vcl/Vcl.BlobImageLoader.pas)

Si bien esta enfocado a leer campos de una BD (campos blob) adaptarlo para que reciba un string o TStream deberia ser muy sencillo

Toda la magia de averiguar el formato de la imagen es obra del gran Chris Rolliston

Saludos

ElKurgan
11-02-2016, 06:58:20
O.K., muchas gracias por tus siempre interesantes aporte, Escafandra.

Cuando pueda lo pruebo y te comento.

De todas formas, en XE7 he encontrado algunos "fallitos" que, oh maravilla, se han corregido en la versión XE8, es decir, a pagar si quieres tener esos detalles arreglados. :)

Gracias y un saludo

ElKurgan
11-02-2016, 08:14:57
Con las llamadas al API funciona perfecto.

Gracias de nuevo.

escafandra
11-02-2016, 08:24:58
De todas formas, en XE7 he encontrado algunos "fallitos" que, oh maravilla, se han corregido en la versión XE8, es decir, a pagar si quieres tener esos detalles arreglados. :)

Pues los fallitos en temas perfectamente estandarizados no son otra cosa que un "defecto de fábrica" sujeto a la garantía del fabricante, solucionarlos no son una mejora, sino la garantía de un producto fiable. Si has de pagar por lo que debería ser un derecho, mejor no comprar el producto.

Saludos.

tatifuentesvasq
18-05-2018, 15:43:21
Y la ultima variante es utilizando las funciones definidas en la unidad Soap.EncdDecd:


var
AMemStream: TMemoryStream;
AStreamBase64, ADecodedStream: TStringStream;
ABase64, DecodedBase64: string;
begin
AMemStream := TMemoryStream.Create;
AStreamBase64 := TStringStream.Create;
try
imLoad.Picture.Bitmap.SaveToStream(AMemStream);
AMemStream.Position := 0;
EncodeStream(AMemStream, AStreamBase64);
AStreamBase64.Position := 0;
ABase64 := AStreamBase64.DataString;
finally
AStreamBase64.Free;
end;

DecodedBase64 := DecodeString(ABase64);
ADecodedStream := TStringStream.Create(DecodedBase64);
try
ADecodedStream.Position := 0;
imBase64.Picture.Bitmap.LoadFromStream(ADecodedStream);
finally
ADecodedStream.Free;
end;


Esta ultima fue la que logro replicar la imagen exactamente a como estaba antes; curioso que los componentes Indy tengan alguna falla

Las pruebas las hice con formato BMP



:confused: :confused: PODRIAS POR FAVOR EXPLICARME UN POCO, QUE YA ME HICE BOLAS... por lo que entiendo hay decodifican la imagen par volverla un string... (estoy mal?), y yo lo que tengo es un archivo extenso donde tengo que decodificar para convertir a imagen, podrian ayudarme?

tatifuentesvasq
18-05-2018, 17:07:09
:(:(


PODRIAS POR FAVOR EXPLICARME UN POCO, QUE YA ME HICE BOLAS... por lo que entiendo hay decodificas una imagen para replicarla... (estoy mal?), y yo lo que tengo es un archivo extenso .txt que debo decodificar para convertir a imagen, podrian ayudarme?

Casimiro Notevi
18-05-2018, 18:17:30
...Por favor, lee nuestra guia de estilo (https://www.clubdelphi.com/foros/guiaestilo.php), gracias... y bienvenido a clubdelphi :)

escafandra
18-05-2018, 20:37:04
:(:(


PODRIAS POR FAVOR EXPLICARME UN POCO, QUE YA ME HICE BOLAS... por lo que entiendo hay decodificas una imagen para replicarla... (estoy mal?), y yo lo que tengo es un archivo extenso .txt que debo decodificar para convertir a imagen, podrian ayudarme?

Si tu archivo txt es encode64, puedes usar la función StrB64ToStream descrita en la respuesta 8 (http://www.clubdelphi.com/foros/showpost.php?p=501981&postcount=8)


Saludos.