Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Leer imagen y convertir su contenido a base64 (https://www.clubdelphi.com/foros/showthread.php?t=89804)

Ramsay 10-02-2016 04:14:17

Leer imagen y convertir su contenido a base64
 
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:

Código Delphi [-]
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)

Código Delphi [-]
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:

Código Delphi [-]
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


Código Delphi [-]
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:

Código Delphi [-]
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:

Código Delphi [-]
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í 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, 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

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

Cita:

Empezado por ElKurgan (Mensaje 501998)
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 decodificar unos bytes a una imagen bmp
 
Cita:

Empezado por AgustinOrtu (Mensaje 501965)
Y la ultima variante es utilizando las funciones definidas en la unidad Soap.EncdDecd:

Código Delphi [-]
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

convertir imagen de base 64 a imagen .bmp
 
:(:(


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

Cita:

Empezado por tatifuentesvasq (Mensaje 526393)
...

Por favor, lee nuestra guia de estilo, gracias... y bienvenido a clubdelphi :)

escafandra 18-05-2018 20:37:04

Cita:

Empezado por tatifuentesvasq (Mensaje 526393)
:(:(


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


Saludos.


La franja horaria es GMT +2. Ahora son las 19:08:08.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi