TPaintBox到JPEG / BMP - 缓冲区

时间:2012-06-19 15:11:12

标签: delphi graphics delphi-7

我有一个paintbox,我画了这样的TBitmap:

procedure MyForm.PaintBoxPaint(Sender: TObject); // ONPAINT
begin
 PaintBox.Canvas.Lock;
 MyBitMap.Canvas.Lock;
 PaintBox.Canvas.Draw(0, 0, MyBitMap);
 PaintBox.Canvas.UnLock;
 MyBitMap.Canvas.UnLock;
end;

我想从PaintBox“映射”/“复制”JPEG或BMP。 我必须先考虑一些挑战。 首先,我想将JPEG或BMP保存到支持WidePath / WideFileName的文件中。我使用Delphi 7,而.SaveToFile程序只支持AnsiPaths / AnsiFileNames。接下来就是我要创建一个独立于“MainGUI线程”的副本。因此GUI应该仍然是活动的并且在将副本保存在后台时绘制到绘图框(所以没有TTimer)。最后一件事是“副本”的实际文件名。我想设置一个从1.jpg ...到2.jpg ...到N.jpg的计数器 问题是由于每个函数都试图递增计数器而导致访问违规的整数计数。

我的想法如下:

保存线程的结构:

type
 PTRTSaveImage = ^TSaveImage;
 TSaveImage = record
 Number : Integer;
 Pic    : TBitMap;
end;

实际的SaveImageThread:

function SaveImageToHDD ( p : pointer ) : Integer; stdcall;
var
 jpg      : TJpegImage;
 jpgStr   : TStringStream;
 _infos   : TSaveImage;
begin
 CopyMemory(@_infos, p, SizeOf(_infos));
 jpg    := TJpegImage.Create;
 jpgStr := TStringStream.Create ('');
 jpg.assign (_infos.Pic);
 _infos.Pic.Free;
 jpg.SaveToStream(jpgStr);
 jpg.Free;
 StrToFile ('C:\' + inttostr(_infos.Number) + '.jpg',0,jpgStr.DataString); // for WidePath/WideFileName Support.
 jpgStr.Free;
end;

这就是我称之为线程的方式:

procedure MyForm.PaintBoxPaint(Sender: TObject); // ONPAINT
var
 Saving : PTRTSaveImage;
 BackUp : TBitMap;
begin
 PaintBox.Canvas.Lock;
 MyBitMap.Canvas.Lock;
 PaintBox.Canvas.Draw(0, 0, MyBitMap);
 BackUp := TBitMap.Create;
 BackUp.Assign (MyBitMap); // Immediate copy of the actual drawing! 
 Saving   := PTRTSaveImage(LocalAlloc(LPTR, SizeOf(TSaveImage)));
 Saving^.Pic    := BackUp;
 Saving^.Number := Counter;
 inc (Counter);
 PaintBox.Canvas.UnLock;
 MyBitMap.Canvas.UnLock;
end;

它只需要几张照片就可以了,但调试器给我看了一个例外:

调试器故障通知 项目C:.... exe出现错误信息:'应用程序定义的异常(代码0x0eedfade)位于0x759d9617'。流程已停止。使用步骤或运行继续。

有没有“更好的方法”来做到这一点?同时保存和绘图......?!

感谢您的帮助。

编辑:

然后我还考虑过将1个线程替换为这样的TTimer:

function SaveImages ( p : TMyForm ) : Integer; stdcall
var
 jpg    : TJpegImage; 
 jpgStr : TStringStream;
begin
while true do begin   // ---> constant LOOP that saves pictures in the intervall
 sleep (1000);        // Intervall
 jpg    := TJpegImage.Create;
 jpg.assign (p.MyBitMap);
 jpgStr := TStringStream.Create ('');
 jpg.SaveToStream(jpgStr);
 jpg.Free;
 StrToFile ('C:\' + inttostr(p.Counter) + '.jpg',0,jpgStr.DataString); // for WidePath/WideFileName Support.  
 inc (p.Counter);  
 jpgStr.Free;
end;
end;

但发生相同的错误/异常。

1 个答案:

答案 0 :(得分:1)

AVI文件......我确实想知道......我会创建一个从TPaintBox派生的新Paintbox控件。 (你可能已经这样做了吗?)

为它添加一个计数器属性和代码,使用BitBlit捕获画布到Bmp然后创建一个线程来转换并将位图保存为jpg,并在启动时递增计数器。 (您将需要使用Synchronize进行该调用)。将其命名为CaptureCanvas。

最后添加一个名为say afterChange或afterTimePeriod的方法,调用captureCanvas。确保你有一个尝试...最终确保如果保存出现任何问题,位图和Jpeg将被销毁。它然后全部在一个地方(在TNewPaintbox内部,如果它落后,那么正在创建的图像已经有它们的索引,你不会将它们保存在乱序中......只是一个想法:)

抱歉,添加表单代码然后会简化为:

Form1.Paintboxpaint()
begin
.
.
PaintBox.Canvas.Draw(x, y, bitmap);
Paintbox.AfterChange;
.

很抱歉为了简洁,编辑答案,看不到原帖