3

我有一个油漆盒,我画了一个像这样的 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 Thread”的副本。因此,当 GUI 将副本保存在后台时(所以没有 TTimer),GUI 应该仍然处于活动状态并绘制到画框。最后一件事是“副本”的实际文件名。我想设置一个从 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”。进程停止。使用 Step 或 Run 继续。

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

谢谢你的帮助。

编辑:

然后我还考虑只制作 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;

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

4

1 回答 1

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;
.

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

于 2012-06-19T16:41:13.767 回答