2012-05-10 5 views
8

Ich würde gerne die Farbe einer Fläche mit einem reinen Windows GDI (also ohne GDI +, DirectX oder ähnliches, kein OpenGL, kein Assembler oder eine 3rd-Party-Bibliothek) mischen (mit angegebenem Alpha-Wert).
Wie wird der Canvas-Bereich mit reinem GDI eingefärbt (mit dem angegebenen Alpha-Wert eingefärbt)?

Ich habe die folgende Funktion erstellt, und ich würde gerne wissen, ob es eine effizientere oder einfacher Weg, dies zu tun:

procedure ColorBlend(const ACanvas: HDC; const ARect: TRect; 
    const ABlendColor: TColor; const ABlendValue: Integer); 
var 
    DC: HDC; 
    Brush: HBRUSH; 
    Bitmap: HBITMAP; 
    BlendFunction: TBlendFunction; 
begin 
    DC := CreateCompatibleDC(ACanvas); 
    Bitmap := CreateCompatibleBitmap(ACanvas, ARect.Right - ARect.Left, 
    ARect.Bottom - ARect.Top); 
    Brush := CreateSolidBrush(ColorToRGB(ABlendColor)); 
    try 
    SelectObject(DC, Bitmap); 
    Windows.FillRect(DC, Rect(0, 0, ARect.Right - ARect.Left, 
     ARect.Bottom - ARect.Top), Brush); 
    BlendFunction.BlendOp := AC_SRC_OVER; 
    BlendFunction.BlendFlags := 0; 
    BlendFunction.AlphaFormat := 0; 
    BlendFunction.SourceConstantAlpha := ABlendValue; 
    Windows.AlphaBlend(ACanvas, ARect.Left, ARect.Top, 
     ARect.Right - ARect.Left, ARect.Bottom - ARect.Top, DC, 0, 0, 
     ARect.Right - ARect.Left, ARect.Bottom - ARect.Top, BlendFunction); 
    finally 
    DeleteObject(Brush); 
    DeleteObject(Bitmap); 
    DeleteDC(DC); 
    end; 
end; 

Für die Vorstellung von dem, was sollte diese Funktion das sehen Sie Beobachtet (Unterscheiden :-) Bilder:

enter image description hereenter image description here

Und der Code, die this image an der oberen linken Seite der Form, in der Art und Weise gezeigt oben machen kann:

uses 
    PNGImage; 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    Image: TPNGImage; 
begin 
    Image := TPNGImage.Create; 
    try 
    Image.LoadFromFile('d:\6G3Eg.png'); 
    ColorBlend(Image.Canvas.Handle, Image.Canvas.ClipRect, $0000FF80, 175); 
    Canvas.Draw(0, 0, Image); 
    finally 
    Image.Free; 
    end; 
end; 

Gibt es eine effizientere Möglichkeit, dies mit reinem GDI oder Delphi VCL zu tun?

+0

Warum denken Sie, was Sie bereits haben nicht effizient ist? –

+0

Deshalb fragte ich. Ich weiß, es ist effizient, aber ich will mehr (wenn möglich :-) – TLama

+0

Was willst du mehr davon? –

Antwort

4

Haben Sie die Leinwandzeichnung mit AlphaBlend ausprobiert?

so etwas wie

Canvas.Draw(Arect.Left, ARect.Top, ABitmap, AAlphaBlendValue); 

mit einem FillRect für die Mischfarbe kombiniert

aktualisieren: Und hier ist ein Code, so nah wie möglich an Ihre Schnittstelle, sondern reine VCL.
Vielleicht nicht so effizient, aber viel einfacher (und etwas portabel).
Als Remy sagte in einer Pseudo-persistent in einem Formular zu malen, dann würden Sie OnPaint verwenden müssen ...

procedure ColorBlend(const ACanvas: TCanvas; const ARect: TRect; 
    const ABlendColor: TColor; const ABlendValue: Integer); 
var 
    bmp: TBitmap; 
begin 
    bmp := TBitmap.Create; 
    try 
    bmp.Canvas.Brush.Color := ABlendColor; 
    bmp.Width := ARect.Right - ARect.Left; 
    bmp.Height := ARect.Bottom - ARect.Top; 
    bmp.Canvas.FillRect(Rect(0,0,bmp.Width, bmp.Height)); 
    ACanvas.Draw(ARect.Left, ARect.Top, bmp, ABlendValue); 
    finally 
    bmp.Free; 
    end; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    Image: TPNGImage; 
begin 
    Image := TPNGImage.Create; 
    try 
    Image.LoadFromFile('d:\6G3Eg.png'); 
    ColorBlend(Image.Canvas, Image.Canvas.ClipRect, $0000FF80, 175); 
    Canvas.Draw(0, 0, Image); 
    // then for fun do it to the Form itself 
    ColorBlend(Canvas, ClientRect, clYellow, 15); 
    finally 
    Image.Free; 
    end; 
end; 
+0

+1, danke! Ich habe diese Überladung nie zuvor gesehen (ich habe Delphi 2009 von Hand).Schön, etwas Neues zu lernen, aber ich muss auch den Kolorierungseffekt anwenden. – TLama

+1

Sie könnten die solide Bitmap als 'TBitmap'-Objekt und' Draw() 'erstellen, wobei Alpha auf dem Canvas Ihres Bildes angegeben wird, und dann' Draw() 'das fertige Bild auf Ihr Formular. Übrigens, wenn Sie möchten, dass die endgültige Zeichnung dauerhaft ist, müssen Sie sie über das Ereignis OnPaint auf das Formular ziehen, nicht auf das OnClick-Ereignis der Schaltfläche. Sie können das Bild im 'OnClick'-Ereignis vorbereiten und dann' Invalidate() 'das Formular zum Auslösen eines Repaint-Vorgangs verwenden und dann das aktuelle Bild zeichnen, sobald das 'OnPaint'-Ereignis ausgelöst wird. Oder fügen Sie einfach das endgültige Bild in eine 'TImage'-Komponente ein. –

+0

François, angenommen, danke! Übrigens. 'bmp.Canvas.FillRect (bmp.Canvas.ClipRect);' könnte auch nützlich sein ;-) @Remy, danke für den Hinweis zum Zeichnen von Persistenzen, aber hier ist es nicht nötig, da diese Funktion in VirtualTreeViews ['verwendet werden sollte OnBeforeCellPaint '] (http://Stackoverflow.com/a/10537589/960757) wo der Hintergrund zum Beispiel animiert werden könnte (ich habe vergessen, das zu erwähnen, mein Schlechter). – TLama

Verwandte Themen