拉撒路 TImage 到 Base64
Lazarus TImage to Base64
我正在尝试将 TImage 图片编码为 base64 以进行剩余传输,我尝试了几种方法,但似乎无法将其编码为字符串。这就是我现在拥有的:
imgstream := TStringStream.Create('');
OutputStream := TStringStream.Create('');
Encoder := TBase64EncodingStream.Create(OutputStream);
try
image1.Picture.SaveToStream(imgstream);
Encoder.CopyFrom(imgstream, imgstream.Size);
showmessage(OutputStream.DataString);
finally
imgstream.Free;
Encoder.Free;
OutputStream.Free;
end;
现在它给了我一个例外。当我 showmessage(imgstream.DataString)
我得到一个奇怪的 BM6~
字符串。
在 CopyFrom
之前添加 imgstream.Position := 0;
之后,现在我得到的数据为空白,无一例外:
TBase64EncodingStream
不适合大二进制转换,我是说,会很慢,还有Image1.Picture.SaveToStream
,默认会把图片保存成Bitmap格式,所以会很慢大。尝试使用 JPG 格式。
procedure TForm1.Button1Click(Sender: TObject);
var
imgstream, Outputstream: TStream;
Encoder: TBase64EncodingStream;
jpg: TJPEGImage;
I: Int64;
begin
I := GetTickCount64;
imgstream := TMemoryStream.Create();
Outputstream := TStringStream.Create('');
jpg := TJPEGImage.Create;
Encoder := TBase64EncodingStream.Create(Outputstream);
try
jpg.Assign(Image1.Picture.Bitmap);
jpg.CompressionQuality:=75;
jpg.SaveToStream(imgstream);
imgstream.Position:= 0;
Encoder.CopyFrom(TStringStream(imgstream), imgstream.Size);
Encoder.Flush;
Memo1.Text:='data:image/jpg;base64,'+ TStringStream(Outputstream).DataString;
ShowMessage('Created in '+IntToStr(GetTickCount64-I)+'ms');
finally
imgstream.Free;
Encoder.Free;
Outputstream.Free;
jpg.Free;
end;
end;
为了改进编码,也许您可以尝试使用线程将二进制文件分成 3 的倍数块来处理每个块,并在最后加入处理过的编码块。
例如使用 4 个线程,硬编码。
{ TEncodeThread }
TEncodeThread = class (TThread)
private
fForm: TForm1;
fStream: TStream;
fStatusText: String;
procedure ShowStatus;
protected
procedure Execute; override;
public
constructor Create(CreateSuspended:Boolean; const AForm: TForm1);
procedure SetStream(const AStream: TStream);
end;
...
procedure TForm1.Button3Click(Sender: TObject);
var
jpg: TJPEGImage;
mul3: Int64;
mod3: Int64;
dif3: Int64;
imgstream: TStringStream;
begin
Steps:=0;
Start:=GetTickCount64;
imgstream := TStringStream.Create('');
jpg := TJPEGImage.Create;
try
jpg.Assign(Image1.Picture.Bitmap);
jpg.CompressionQuality:=75;
jpg.SaveToStream(imgstream);
mul3 := imgstream.Size div 4;
mod3 := mul3 mod 3;
if mod3 <> 0 then
mul3 := mul3 + 3 - mod3;
dif3 := imgstream.Size - mul3*4;
memo1.text := 'Total Size: '+ IntToStr(imgstream.size)
+ #13'Part1: '+IntToStr(mul3)
+ #13'Part2: '+IntToStr(mul3)
+ #13'Part3: '+IntToStr(mul3)
+ #13'Part4: '+IntToStr(mul3+dif3)
+ #13'Rest: '+IntToStr(dif3);
Part1.Position:=0;
Part2.Position:=0;
Part3.Position:=0;
Part4.Position:=0;
imgstream.Position:=0;
Part1.CopyFrom(imgstream,mul3);
Part2.CopyFrom(imgstream,mul3);
Part3.CopyFrom(imgstream,mul3);
Part4.CopyFrom(imgstream,mul3+dif3);
Thr1 := TEncodeThread.Create(True, Self);
Thr2 := TEncodeThread.Create(True, Self);
Thr3 := TEncodeThread.Create(True, Self);
Thr4 := TEncodeThread.Create(True, Self);
Thr1.SetStream(Part1);
Thr1.Start;
Thr2.SetStream(Part2);
Thr2.Start;
Thr3.SetStream(Part3);
Thr3.Start;
Thr4.SetStream(Part4);
Thr4.Start;
finally
imgstream.Free;
jpg.Free;
end;
end;
procedure TEncodeThread.Execute;
var
Encoder: TBase64EncodingStream;
buf: TStream;
begin
buf := TStringStream.Create('');
Encoder := TBase64EncodingStream.Create(buf);
try
fStream.Position:= 0;
Encoder.CopyFrom(TStringStream(fStream), fStream.Size);
Encoder.Flush;
buf.Position:= 0;
fForm.Out1.CopyFrom(TStringStream(buf), buf.Size);
Inc(fForm.Steps);
if fForm.Steps = 3 then
begin
fForm.Out1.Position:=0;
fForm.Out2.Position:=0;
fForm.Out3.Position:=0;
fForm.Out4.Position:=0;
fForm.Memo1.Text:='data:image/jpg;base64,'
+ TStringStream(fForm.Out1).DataString
+ TStringStream(fForm.Out2).DataString
+ TStringStream(fForm.Out3).DataString
+ TStringStream(fForm.Out4).DataString;
end;
finally
Encoder.Free;
buf.Free;
end;
end;
这个演示并没有真正优化,也没有正确同步(输出可能格式错误),但是,作为一个起点它可能会有所帮助。 zipped project
我正在尝试将 TImage 图片编码为 base64 以进行剩余传输,我尝试了几种方法,但似乎无法将其编码为字符串。这就是我现在拥有的:
imgstream := TStringStream.Create('');
OutputStream := TStringStream.Create('');
Encoder := TBase64EncodingStream.Create(OutputStream);
try
image1.Picture.SaveToStream(imgstream);
Encoder.CopyFrom(imgstream, imgstream.Size);
showmessage(OutputStream.DataString);
finally
imgstream.Free;
Encoder.Free;
OutputStream.Free;
end;
现在它给了我一个例外。当我 showmessage(imgstream.DataString)
我得到一个奇怪的 BM6~
字符串。
在 CopyFrom
之前添加 imgstream.Position := 0;
之后,现在我得到的数据为空白,无一例外:
TBase64EncodingStream
不适合大二进制转换,我是说,会很慢,还有Image1.Picture.SaveToStream
,默认会把图片保存成Bitmap格式,所以会很慢大。尝试使用 JPG 格式。
procedure TForm1.Button1Click(Sender: TObject);
var
imgstream, Outputstream: TStream;
Encoder: TBase64EncodingStream;
jpg: TJPEGImage;
I: Int64;
begin
I := GetTickCount64;
imgstream := TMemoryStream.Create();
Outputstream := TStringStream.Create('');
jpg := TJPEGImage.Create;
Encoder := TBase64EncodingStream.Create(Outputstream);
try
jpg.Assign(Image1.Picture.Bitmap);
jpg.CompressionQuality:=75;
jpg.SaveToStream(imgstream);
imgstream.Position:= 0;
Encoder.CopyFrom(TStringStream(imgstream), imgstream.Size);
Encoder.Flush;
Memo1.Text:='data:image/jpg;base64,'+ TStringStream(Outputstream).DataString;
ShowMessage('Created in '+IntToStr(GetTickCount64-I)+'ms');
finally
imgstream.Free;
Encoder.Free;
Outputstream.Free;
jpg.Free;
end;
end;
为了改进编码,也许您可以尝试使用线程将二进制文件分成 3 的倍数块来处理每个块,并在最后加入处理过的编码块。
例如使用 4 个线程,硬编码。
{ TEncodeThread }
TEncodeThread = class (TThread)
private
fForm: TForm1;
fStream: TStream;
fStatusText: String;
procedure ShowStatus;
protected
procedure Execute; override;
public
constructor Create(CreateSuspended:Boolean; const AForm: TForm1);
procedure SetStream(const AStream: TStream);
end;
...
procedure TForm1.Button3Click(Sender: TObject);
var
jpg: TJPEGImage;
mul3: Int64;
mod3: Int64;
dif3: Int64;
imgstream: TStringStream;
begin
Steps:=0;
Start:=GetTickCount64;
imgstream := TStringStream.Create('');
jpg := TJPEGImage.Create;
try
jpg.Assign(Image1.Picture.Bitmap);
jpg.CompressionQuality:=75;
jpg.SaveToStream(imgstream);
mul3 := imgstream.Size div 4;
mod3 := mul3 mod 3;
if mod3 <> 0 then
mul3 := mul3 + 3 - mod3;
dif3 := imgstream.Size - mul3*4;
memo1.text := 'Total Size: '+ IntToStr(imgstream.size)
+ #13'Part1: '+IntToStr(mul3)
+ #13'Part2: '+IntToStr(mul3)
+ #13'Part3: '+IntToStr(mul3)
+ #13'Part4: '+IntToStr(mul3+dif3)
+ #13'Rest: '+IntToStr(dif3);
Part1.Position:=0;
Part2.Position:=0;
Part3.Position:=0;
Part4.Position:=0;
imgstream.Position:=0;
Part1.CopyFrom(imgstream,mul3);
Part2.CopyFrom(imgstream,mul3);
Part3.CopyFrom(imgstream,mul3);
Part4.CopyFrom(imgstream,mul3+dif3);
Thr1 := TEncodeThread.Create(True, Self);
Thr2 := TEncodeThread.Create(True, Self);
Thr3 := TEncodeThread.Create(True, Self);
Thr4 := TEncodeThread.Create(True, Self);
Thr1.SetStream(Part1);
Thr1.Start;
Thr2.SetStream(Part2);
Thr2.Start;
Thr3.SetStream(Part3);
Thr3.Start;
Thr4.SetStream(Part4);
Thr4.Start;
finally
imgstream.Free;
jpg.Free;
end;
end;
procedure TEncodeThread.Execute;
var
Encoder: TBase64EncodingStream;
buf: TStream;
begin
buf := TStringStream.Create('');
Encoder := TBase64EncodingStream.Create(buf);
try
fStream.Position:= 0;
Encoder.CopyFrom(TStringStream(fStream), fStream.Size);
Encoder.Flush;
buf.Position:= 0;
fForm.Out1.CopyFrom(TStringStream(buf), buf.Size);
Inc(fForm.Steps);
if fForm.Steps = 3 then
begin
fForm.Out1.Position:=0;
fForm.Out2.Position:=0;
fForm.Out3.Position:=0;
fForm.Out4.Position:=0;
fForm.Memo1.Text:='data:image/jpg;base64,'
+ TStringStream(fForm.Out1).DataString
+ TStringStream(fForm.Out2).DataString
+ TStringStream(fForm.Out3).DataString
+ TStringStream(fForm.Out4).DataString;
end;
finally
Encoder.Free;
buf.Free;
end;
end;
这个演示并没有真正优化,也没有正确同步(输出可能格式错误),但是,作为一个起点它可能会有所帮助。 zipped project