2012-05-10 8 views
8

Me gustaría mezclar colores (colorear por valor alfa especificado) el área de un lienzo utilizando Windows GDI puro (sin GDI +, DirectX o similar, sin OpenGL, sin ensamblador o bibliotecas de terceros).
Cómo colorear mezcla (colorear por valor alfa especificado) el área del lienzo usando GDI puro?

He creado la siguiente función y me gustaría saber si hay una manera más eficiente o más fácil de hacer esto:

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; 

Para la noción de lo que esta función no debería ver el siguiente (que discriminan imágenes :-):

enter image description hereenter image description here

y el código que puede hacer que this image hacia el lado izquierdo superior de la forma de la forma indicada anteriormente:

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; 

¿Hay una manera más eficiente de hacer esto usando GDI puro o Delphi VCL?

+0

¿Por qué creen lo que ya tiene, no es eficiente? –

+0

Es por eso que pregunté. Sé que es eficiente, pero quiero más (si es posible :-) – TLama

+0

¿Qué más quieres de él? –

Respuesta

4

¿Has probado el Canvas Drawing con AlphaBlend?

algo así como

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

combinado con un fillRect para el color de fusión

actualización: Y aquí está un cierto código, lo más cerca posible a su interfaz, pero pura VCL.
Puede que no sea tan eficiente, pero mucho más simple (y algo portátil).
Como Remy dicho, para pintar en un formulario de una manera persistente seudo, que tendría que utilizar OnPaint ...

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, gracias! Nunca antes había visto esta sobrecarga (tengo Delphi 2009 a mano).Es bueno aprender algo nuevo, sin embargo, necesito aplicar el efecto de colorear también. – TLama

+1

Puede crear el mapa de bits sólido como un objeto 'TBitmap' y' Draw() 'con el alfa especificado en el' Canvas' de su imagen, luego 'Draw()' la imagen terminada en su Formulario. Por cierto, si quieres que el sorteo final sea persistente, debes dibujarlo en el formulario del evento 'OnPaint', no en el evento' OnClick' del botón. Puede preparar la imagen en el evento 'OnClick' y luego' Invalidar() 'la forma para desencadenar un repintado, luego dibuje la imagen actual siempre que se active el evento' OnPaint'. O simplemente coloque la imagen final en un componente 'TImage'. –

+0

François, aceptado, gracias! Por cierto. 'bmp.Canvas.FillRect (bmp.Canvas.ClipRect);' podría ser también útil ;-) @Remy, gracias por la nota sobre la persistencia del dibujo, pero aquí no es necesario ya que esta función fue pensada para ser utilizada en VirtualTreeView's [' OnBeforeCellPaint'] (http://stackoverflow.com/a/10537589/960757) donde el fondo podría estar animado, por ejemplo (olvidé mencionar eso, mi mal). – TLama

Cuestiones relacionadas