是否将INI文件中的base64编码数据加载回TPicture? [英] Load base64-encoded data from INI file back to 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.Send
的TPicture
通常可以正常工作,在这种情况下,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:
如何编码?好吧,我知道
-
Base64Enc.EncodeBytesToString
-
MyIni.WriteString
Base64Enc.EncodeBytesToString
MyIni.WriteString
因此,要解码,我以相反的顺序执行相反的过程:
So, to decode, I do the opposite procedures in the opposite order:
-
MyIni.ReadString
-
Base64Enc.DecodeStringToBytes
MyIni.ReadString
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屋!