Save Jpeg to base64 in TThread
I have some Delphi problem.
I wrote two simple functions to take a screenshot, convert it to jpeg and decode it to base64 stream. And it works fine if I do it in the main thread program. But if I create a TThread class and run this function in Execute, windows freezes and I can restart my computer.
After doing a few tries I found the PC freezes through the procedure JpegImg.SaveToStream(Input);
AND if I don't convert Bitmap to jpeg it works well and I get the image string.
Help me please.
Here's the code
procedure TEvReader.ScreenShot(DestBitmap : TBitmap) ;
var DC : HDC;
begin DC := GetDC (GetDesktopWindow) ;
try
DestBitmap.Width := GetDeviceCaps (DC, HORZRES) ;
DestBitmap.Height := GetDeviceCaps (DC, VERTRES) ;
BitBlt(DestBitmap.Canvas.Handle, 0, 0, DestBitmap.Width, DestBitmap.Height, DC, 0, 0, SRCCOPY) ;
finally
ReleaseDC (GetDesktopWindow, DC) ;
end;
end;
function TEvReader.Base64FromBitmap(Bitmap: TBitmap): string;
var
Input: TBytesStream;
Output: TStringStream;
JpegImg:TJPEGImage;
begin
Input := TBytesStream.Create;
try
JpegImg:=TJPEGImage.Create;
JpegImg.Assign(Bitmap);
JpegImg.SaveToStream(Input); {here a problem.When i replace "JpegImg" to "Bitmap" all works good }
Input.Position := 0;
Output := TStringStream.Create('', TEncoding.ASCII);
try
Soap.EncdDecd.EncodeStream(Input, Output);
Result := Output.DataString;
finally
Output.Free;
end;
finally
Input.Free;
end;
end;
procedure TOutThread.Execute;
var
bmp:TBitmap;
strrr:String;
begin
bmp:=TBitmap.Create;
mObj.ScreenShot(bmp);
strrr := mObj.Base64FromBitmap(bmp);
Form2.Memo4.Text := strrr;
end;
source to share
TJPEGImage is not thread safe. Although the thread-safe drawing issue mentioned at http://qc.embarcadero.com/wc/qcmain.aspx?d=55871 is somewhat fixed in Delphi XE6 (exposing a Canvas property that you have to block yourself), in yours this hardly helps.
You need to synchronize the TJPEGImage processing with the main stream.
Also in your code you have created some memory leaks since you never released JpgImg and Bmp objects.
Try with the following code:
procedure TEvReader.ScreenShot(DestBitmap: TBitmap);
var
DC: HDC;
begin
DC := GetDC(GetDesktopWindow);
DestBitmap.Canvas.Lock;
try
DestBitmap.Width := GetDeviceCaps(DC, HORZRES);
DestBitmap.Height := GetDeviceCaps(DC, VERTRES);
BitBlt(DestBitmap.Canvas.Handle, 0, 0, DestBitmap.Width, DestBitmap.Height, DC, 0, 0, SRCCOPY);
finally
DestBitmap.Canvas.Unlock;
ReleaseDC(GetDesktopWindow, DC);
end;
end;
function TEvReader.Base64FromBitmap(Bitmap: TBitmap): string;
var
Input: TBytesStream;
Output: TStringStream;
JpegImg: TJPEGImage;
begin
Input := TBytesStream.Create;
try
JpegImg := TJPEGImage.Create;
try
TThread.Synchronize(nil,
procedure
begin
JpegImg.Assign(Bitmap);
JpegImg.SaveToStream(Input);
end);
finally
JpegImg.Free;
end;
Input.Position := 0;
Output := TStringStream.Create('', TEncoding.ASCII);
try
Soap.EncdDecd.EncodeStream(Input, Output);
Result := Output.DataString;
finally
Output.Free;
end;
finally
Input.Free;
end;
end;
procedure TOutThread.Execute;
var
mObj: TEvReader;
bmp: TBitmap;
strrr: string;
begin
mObj := TEvReader.Create;
bmp := TBitmap.Create;
try
mObj.ScreenShot(bmp);
strrr := mObj.Base64FromBitmap(bmp);
finally
bmp.Free;
mObj.Free;
end;
Synchronize(nil,
procedure
begin
Form2.Memo4.Text := strrr;
end);
end;
source to share