TBase64EncodingStream
is not suitable for big binary conversion, I mean, it will be very slow, also Image1.Picture.SaveToStream
, by default, will save the picture as Bitmap format, so it will be very big. Try using JPG format.
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;
To improve encoding it, maybe you could try using threads separating the binary in chunks multiple of 3 to process each one and join the processed encoded chunks at the end.
e.g. Using 4 threads, hard encoded.
{ 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;
This demo, is not really optimized, neither correctly synchronized (output maybe wrongly formed), though, as a starting point it could be of help. zipped project
imgstream.Position := 0;
before theCopyFrom
. – Ken WhiteOutputStream
by setting it's position before you access it. – Ken WhiteEReadError, Stream Read Error
, I've reset position beforeshowmessage
but still empty.OutputStream.Position := 0;
– jfreak53showmessage
comes up blank, trying to add the output to a TMemo component freezes the program with no errors:memo1.Lines.LoadFromStream(OutputStream);
– jfreak53