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 を「マップ」/「コピー」したいと思います。最初に考えなければならない課題がいくつかあります。まず、WidePath/WideFileName をサポートするファイルに JPEG または BMP を保存したいと考えています。私は Delphi 7 を使用しており、.SaveToFile プロシージャは AnsiPaths/AnsiFileNames のみをサポートしています。次は「MainGUIスレッド」から独立したコピーを作りたいということです。そのため、バックグラウンドでコピーを保存している間、GUI は引き続きアクティブで、ペイントボックスに描画する必要があります (したがって、TTimer ではありません)。最後は「コピー」の実際のファイル名です。1.jpg ... から 2.jpg ... から N.jpg になるカウンターを設定したいと思います。問題は、関数がカウンターをインクリメントしようとするたびにアクセス違反が発生する可能性がある Integer のカウントです。

私のアイデアは次のとおりです。

保存スレッドの構造:

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;

数枚の写真は問題なく撮れますが、デバッガーは例外を表示します:

Debugger Fault Notification プロジェクト C:....exe がメッセージで失敗しました: 'アプリケーション定義の例外 (コード 0x0eedfade) at 0x759d9617'。プロセスが停止しました。Step または Run を使用して続行します。

これを行う「より良い方法」はありますか?保存と描画が同時に…!?

ご協力いただきありがとうございます。

編集:

次に、次のような TTimer の代わりに 1 つのスレッドを作成することも考えました。

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 という名前を付けます。

最後に、captureCanvas を呼び出す say afterChange または afterTimePeriod というメソッドを追加します。最後に、保存に問題が発生した場合にビットマップと Jpeg が確実に破棄されるようにしてください。その後、すべてが1か所(TNewPaintbox内)にあり、遅れた場合、作成中の画像にはすでにインデックスがあり、それらを順不同で保存することはありません....単なるアイデア:)

申し訳ありませんが、フォームコードを追加すると、次のように簡略化されます。

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

簡潔に申し訳ありませんが、回答を編集して元の投稿を表示できません

于 2012-06-19T16:41:13.767 に答える