是否将INI文件中的base64编码数据加载回TPicture? [英] Load base64-encoded data from INI file back to TPicture?

查看:149
本文介绍了是否将INI文件中的base64编码数据加载回TPicture?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Delphi 10.4中,我已使用以下代码成功将有效的TPicture base64编码保存到INI文件中:

In Delphi 10.4, I have sucessfully saved a valid TPicture base64-encoded to an INI file, using this code:

procedure TForm1.SavePictureToIniFile(const APicture: TPicture);
// https://stackoverflow.com/questions/63216011/tinifile-writebinarystream-creates-exception
var
  LInput: TMemoryStream;
  MyIni: TMemIniFile;
  Base64Enc: TBase64Encoding;
  ThisFile: string;
begin
  if FileSaveDialog1.Execute then
    ThisFile := FileSaveDialog1.FileName
  else EXIT;

  //CodeSite.Send('TForm1.btnSaveToIniClick: VOR Speichern');
  LInput := TMemoryStream.Create;
  try
    APicture.SaveToStream(LInput);
    LInput.Position := 0;
    MyIni := TMemIniFile.Create(ThisFile);
    try
      Base64Enc := TBase64Encoding.Create(Integer.MaxValue, '');
      try
        MyIni.WriteString('Custom', 'IMG', Base64Enc.EncodeBytesToString(LInput.Memory, LInput.Size));
      finally
        Base64Enc.Free;
      end;
      MyIni.UpdateFile;
    finally
      MyIni.Free;
    end;
  finally
    LInput.Free;
  end;
  //CodeSite.Send('TForm1.btnSaveToIniClick: NACH Speichern'); // 0,024 Sek.
end;

现在我要逆转此过程,即将数据从INI文件加载回TPicture:

Now I want to REVERSE this process, i.e. load the data back from the INI file to a TPicture:

procedure TForm1.btnLoadFromIniClick(Sender: TObject);
var
  LInput: TMemoryStream;
  LOutput: TMemoryStream;
  ThisFile: string;
  MyIni: TMemIniFile;
  Base64Enc: TBase64Encoding;
  ThisEncodedString: string;
  ThisPicture: TPicture;
begin
  if FileOpenDialog1.Execute then
    ThisFile := FileOpenDialog1.FileName
  else EXIT;

  MyIni := TMemIniFile.Create(ThisFile);
  try
    Base64Enc := TBase64Encoding.Create(Integer.MaxValue, '');
    try
      (*ThisEncodedString := MyIni.ReadString('Custom', 'IMG', '');
      Base64Enc.Decode(ThisEncodedString); // And now???*)
      LInput := TMemoryStream.Create;
      LOutput := TMemoryStream.Create;
      try
        MyIni.ReadBinaryStream('Custom', 'IMG', LInput);
        MyIni.UpdateFile;
        LInput.Position := 0;
        Base64Enc.Decode(LInput, LOutput);
        LOutput.Position := 0;

        ThisPicture := TPicture.Create;
        try
          ThisPicture.LoadFromStream(LOutput);
          CodeSite.Send('TForm1.btnLoadFromIniClick: ThisPicture', ThisPicture); // AV!
        finally
          ThisPicture.Free;
        end;
      finally
        LOutput.Free;
        LInput.Free;
      end;
    finally
      Base64Enc.Free;
    end;        
  finally
    MyIni.Free;
  end;
end;

但是用CodeSite.Send发送图片时会创建一个AV! (发送带有CodeSite.SendTPicture通常可以正常工作,在这种情况下,AV显然意味着图片已损坏.)

But when sending the Picture with CodeSite.Send creates an AV! (Sending a TPicture with CodeSite.Send usually DOES work, in this case, the AV obviously means the Picture is corrupted).

那么如何将数据从INI文件加载回TPicture?

So how can I load the data back from the INI file to a TPicture?

推荐答案

这与原始问题本质上是相同的问题.

This is essentially the same problem as in the original question.

INI文件的数据是二进制映像的Base64表示形式,即 string .因此,您需要读取此Base64字符串,并使用Base64Enc将该字符串转换为二进制blob.

The INI file's data is a Base64 representation of the binary image, that is, a string. So you need to read this Base64 string and convert it to a binary blob using Base64Enc.

但是您的代码使用ReadBinaryStream方法,该方法不将文本视为Base64字符串而是十六进制字节序列,并将其作为二进制blob返回,然后将其提供给Base64Enc.

But your code uses the ReadBinaryStream method, which treats the text not as a Base64 string but as a hexadecimal byte sequence and returns it as a binary blob, and then you give it to Base64Enc.

相反,请执行以下操作:

Do this instead:

var
  ImgData: TBytes;
begin
  MyIni := TMemIniFile.Create('D:\img.ini');
  try
    Base64Enc := TBase64Encoding.Create(Integer.MaxValue, '');
    try
      LInput := TMemoryStream.Create;
      try
        ImgData := Base64Enc.DecodeStringToBytes(MyIni.ReadString('Custom', 'IMG', ''));
        LInput.WriteData(ImgData, Length(ImgData));
        LInput.Position := 0;
        ThisPicture := TPicture.Create;
        try
          ThisPicture.LoadFromStream(LInput);
          // Use ThisPicture
        finally
          ThisPicture.Free;
        end;
      finally
        LInput.Free;
      end;
    finally
      Base64Enc.Free;
    end;
  finally
    MyIni.Free;
  end;

您可能会意识到这一点的一种方式是通过这样的思考:

One way you could have realised this is by thinking like this:

如何编码?好吧,我知道

  1. Base64Enc.EncodeBytesToString
  2. MyIni.WriteString
  1. Base64Enc.EncodeBytesToString
  2. MyIni.WriteString

因此,要解码,我以相反的顺序执行相反的过程:

So, to decode, I do the opposite procedures in the opposite order:

  1. MyIni.ReadString
  2. Base64Enc.DecodeStringToBytes
  1. MyIni.ReadString
  2. Base64Enc.DecodeStringToBytes

摆脱不必要的副本

在注释中, Remy Lebeau 正确地指出,上面的代码执行了不必要的内存副本二进制图像数据.尽管实际上这不太可能是一个问题(甚至无法衡量!),但鉴于我们正在从INI文件中的Base64编码字段读取图像,但这仍然是浪费和丑陋的.

Getting rid of the unnecessary copy

In the comments, Remy Lebeau correctly points out that the code above performs an unnecessary in-memory copy of the binary image data. Although this is unlikely to be a problem (or even measurable!) in practice, given that we are reading the image from a Base64-encoded field in an INI file, it is nevertheless wasteful and ugly.

通过用TBytesStream(TMemoryStream的后代)替换TMemoryStream,我们可以将Base64数据直接解码为流:

By replacing the TMemoryStream with a TBytesStream (a descendant of TMemoryStream), we can decode the Base64 data directly into the stream:

var
  ImgStream: TBytesStream;
begin
  MyIni := TMemIniFile.Create('D:\img.ini');
  try
    Base64Enc := TBase64Encoding.Create(Integer.MaxValue, '');
    try
      ImgStream := TBytesStream.Create(Base64Enc.DecodeStringToBytes(MyIni.ReadString('Custom', 'IMG', '')));
      try
        ThisPicture := TPicture.Create;
        try
          ThisPicture.LoadFromStream(ImgStream);
          // Use ThisPicture
        finally
          ThisPicture.Free;
        end;
      finally
        ImgStream.Free;
      end;
    finally
      Base64Enc.Free;
    end;
  finally
    MyIni.Free;
  end;

这篇关于是否将INI文件中的base64编码数据加载回TPicture?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆