4

いくつかの画像 (jpg、png など) をサムネイルとしてすばやく表示したい。デコードとサイズ変更のプロセスが遅いため、1 つまたは複数のスレッドで実行する必要があります。

ただし、TBitmap と TJpeg のキャンバスを使用すると、マルチスレッド セーフではないようです。

この場合、私の質問は次のとおり
です。
2. Embarcadero の Gif および Png ライブラリも安全でないかどうか知っている人はいますか?
3. Lock を使用してキャンバスをロックすると、サイズ変更部分がキャンバスにアクセスし、ほとんどの CPU サイクルが消費されるため、パフォーマンスが低下しませんか?


私はこれが私を悩ませていることを発見しました:

David HAROUCHE は次のように書いています。本当に紛らわしいのは、ローカルの TBitmap でさえ、ロックしない限りスレッド セーフではないということです。これは、すべての TBitmap が、graphics.pas のグローバルな BitmapCanvasList リストに自身を登録するためです。また、DC ガベージ コレクションの FreeMemoryContexts()

http://www.codenewsfast.com/cnf/thread/0/permalink.thr-ng1908q2024

4

1 に答える 1

6

CreateCompatibleDC および CreateBitmap で GDI+ を使用すると、多くの画像形式に対応し、キャンバス スレッドの問題を回避できます。
これは単なる実装例であり、変更される可能性があります。GDI+ API には 3 つのユニットが必要で、インストールは必要ありません。たとえば、http://www.progdigy.com/から入手できます。

unit ScaleImageThread;
// 2013 Thomas Wassermann
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls
  ,GDIPAPI, GDIPOBJ, StdCtrls;
Type
  TScaleImageThread=Class(TThread)
    FBMP:TBitMap;
    FMemDC:HDC;
    FMemBMP:HBitmap;
    Procedure Execute;Override;
  private
    Ffn:String;
    FDestWidth,FDestHeight:Integer;
    procedure SyncFinished;
    Public
    Constructor Create(aBitMap:TBitmap;const fn:String);overload;
    property BMP:TBitmap read FBMP;
    Property FileName:String read Ffn;
  End;
implementation
{ TGDIThread }
Procedure ScaleOneImage(Const source:String;aHDC:HDC;DestWidth,DestHeight:Integer;Qual:Integer=92;WithOutMargins:Boolean=false;BgColor:TColor=ClWhite;DoNotUpScale:Boolean=false);
var
  graphics : TGPGraphics;
  image: TGPImage;
  width, height: UINT;
  faktor:Double;
  destx,desty:Double;
  rct:TGPRectF;
  Ext:String;
begin

  image:= TGPImage.Create(source);
  width  := image.GetWidth;
  height := image.GetHeight;


    if (DestWidth / width) < (DestHeight/Height) then faktor  := (DestWidth / width) else faktor:= (DestHeight/Height);
    destx :=  (DestWidth - faktor * width) / 2;
    desty :=  (DestHeight - faktor * Height) / 2;
    graphics := TGPGraphics.Create(aHDC);
    graphics.SetInterpolationMode(InterpolationModeHighQualityBicubic);

    graphics.DrawImage(
      image,
      MakeRect(destx,  desty , faktor * width, faktor * height),  // destination rectangle
      0, 0,        // upper-left corner of source rectangle
      width,       // width of source rectangle
      height,      // height of source rectangle
      UnitPixel);
    image.Free;
    graphics.Free;
end;

constructor TScaleImageThread.Create(aBitMap: TBitmap;const fn:String);
begin
  inherited create(False);
  Ffn :=fn;
  FreeOnTerminate := true;
  FBmp := aBitMap;
  FMemDC := CreateCompatibleDC(FBmp.Canvas.Handle);
  FMemBMP := CreateBitmap(FBmp.Width ,FBmp.Height ,1,GetDeviceCaps(FBmp.Canvas.Handle, BITSPIXEL),nil);
  SelectObject(FMemDC, FMemBMP);
  FDestWidth :=FBMP.Width;
  FDestHeight:=FBMP.Height;
end;


procedure TScaleImageThread.Execute;
begin
  inherited;
  ScaleOneImage(Ffn,FMemDC,FDestWidth,FDestHeight);
  Synchronize(SyncFinished);
end;

procedure TScaleImageThread.SyncFinished;
begin
 BitBlt(FBmp.Canvas.Handle, 0, 0, FBmp.Width, FBmp.Height, FMemDC, 0, 0, SRCCOPY);
 DeleteObject(FMemBMP);
 DeleteDC (FMemDC);
end;

end.

実装のテスト

uses ScaleImageThread;
{$R *.dfm}

procedure TForm1.ThreadTerminate(Sender: TObject);
begin
  Canvas.Draw(FX, FY, TGDIThread(Sender).BMP);
  TGDIThread(Sender).BMP.Free;
  FX := FX + 70;
  if FX > 500 then
    begin
    FX := 0;
    FY := FY + 70;
    end;

end;

procedure TForm1.Button1Click(Sender: TObject);
const
  C_DIM = 64;
var
  i: Integer;
  Function GetNewBitMap: TBitMap;
  begin
    Result := TBitMap.Create;
    Result.Width := C_DIM;
    Result.Height := C_DIM;
  end;

begin
  ReportMemoryLeaksOnShutDown := true;
  for i := 1 to 10 do
    With TGDIThread.Create(GetNewBitMap,
      'C:\temp\bild ' + intToStr(i) + '.png') do
      OnTerminate := ThreadTerminate;

  for i := 1 to 10 do
    With TGDIThread.Create(GetNewBitMap,
      'C:\Bilder\Kids' + intToStr(i) + '.jpg') do
      OnTerminate := ThreadTerminate;


end;
于 2013-02-11T00:39:04.807 に答える