Jpeg保存到TThread中的base64
我在Delphi中遇到了一些问题。Jpeg保存到TThread中的base64
我写使截图两个简单的功能,将其转换为JPEG和解码为base64,流。 它的作品不错,如果我在主流程序上制作。但是,如果我创建一个TThread类并启动此功能执行,Windows冻结,我只能重新启动我的电脑。
通过多次尝试,我发现挂起电脑通过程序JpegImg.SaveToStream(Input);
如果我不转换位图为JPEG,其作品很好,我得到的图像字符串。
请帮忙。
这里代码
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;
TJPEGImage不是线程安全的。虽然http://qc.embarcadero.com/wc/qcmain.aspx?d=55871中提到的线程安全绘图问题在Delphi XE6中有所修复(通过暴露Canvas属性,您必须锁定自己),但在您的情况下,它可能没有多大帮助。
您必须将TJPEGImage处理与主线程同步。
另外,在你的代码中创建了一些内存泄漏,因为你从来没有发布JpgImg和BMP的对象。
尝试用下面的代码:
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;
必须有一个适当的第三方JPEG LIB – 2014-11-23 20:12:15
@DavidHeffernan我用来修补TJPEGImage自己,但我只需要绘制JPEG的线程,并且部分是没有问题的修补(除非,当然,英巴卡迪诺忘了,包括所有的源文件需要重新编译,这是经常发生的事情)。 – 2014-11-23 20:17:38
最安全的方法是使用GDI + /'CreateCompatibleDC'和'CreateBitmap'作为描述这里(http://stackoverflow.com/a/14804378/937125),我也不能确定同步'JpegImg.Assign'部分。但在“ScreenShot”中锁定/解锁“DestBitmap.Canvas.Handle”是必不可少的。 +1 – kobik 2014-11-23 21:01:11
我猜测,但是这可能会有所帮助:http://qc.embarcadero.com/wc/qcmain.aspx?d=55871。位图不是线程安全的。您需要锁定/解锁其画布。 – kobik 2014-11-23 12:53:59
@kobik听起来好像他从多个线程访问相同的位图对象。还是有一些疯狂的实施与VCL位图搞砸了? – 2014-11-23 16:51:12
@DavidHeffernan TJPEGImage被搞砸了,有问题,其Bitmap.Canvas DC是在graphics.pas – 2014-11-23 20:10:17