首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将base64 64编码的数据从INI文件加载回TPicture?

将base64 64编码的数据从INI文件加载回TPicture?
EN

Stack Overflow用户
提问于 2020-08-03 09:32:46
回答 1查看 320关注 0票数 2

在Delphi10.4中,我成功地使用以下代码将有效的TPicture base64 64保存到INI文件中:

代码语言:javascript
复制
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

代码语言:javascript
复制
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!(用TPicture发送CodeSite.Send通常是有效的,在这种情况下,AV显然意味着图片已经损坏)。

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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-08-03 09:47:18

这与原来的问题实质上是同一个问题。

INI文件的数据是二进制图像的Base64表示,即字符串。因此,您需要读取这个Base64字符串,并使用Base64Enc将其转换为二进制blob。

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

取而代之的是这样做:

代码语言:javascript
复制
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;

你能意识到这一点的一种方法是这样想:

我该怎么编码?好吧,我知道

  1. Base64Enc.EncodeBytesToString
  2. MyIni.WriteString

所以,为了解码,我用相反的顺序做相反的步骤:

  1. MyIni.ReadString
  2. Base64Enc.DecodeStringToBytes

摆脱不必要的拷贝

在注释中,Remy Lebeau正确地指出,上面的代码对二进制图像数据执行不必要的内存副本。虽然这不太可能是一个问题(甚至是可测量的!)实际上,考虑到我们从INI文件中的Base64 64编码字段读取图像,它仍然是浪费和丑陋的。

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

代码语言:javascript
复制
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;
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63226950

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档