2012-10-03 5 views
5

यह प्रश्न SO पर मेरे earlier question से संबंधित है।Alphablend और TransparentBlt

मैं अल्फा के साथ दो परतों को जोड़ना चाहता हूं जो केवल स्रोत परत के एक विशिष्ट भाग पर लागू होते हैं। एक तरीका मैंने कोशिश की थी SourceConstantAlpha को $ ff (और फ़ंक्शन को स्रोत परत में अल्फा चैनल का उपयोग करें) सेट करना था।

इस तरह के काम - हालांकि धीमा (मुझे लगता है कि मैं स्कैनलाइन का उपयोग करके इसे तेज कर सकता हूं), इस तरह का हिस्सा यह है कि मैं यह नहीं समझ सकता कि अल्फा चैनल को सेट करना है या नहीं। प्रलेखन पता चलता है कि गणना है:

st.Red = Src.Red + (1 - Src.Alpha) * Dst.Red 

मुझे लगता है कि काम से कुछ अलग मूल्यों की कोशिश की है, लेकिन मेरा पहला सवाल यह है: मैं अल्फा मूल्य की गणना कैसे करूँ?

कुछ अन्य SO प्रश्न पढ़ने के बाद, मैं ट्रांसपेरेंटब्लैट फ़ंक्शन में आया, जो मास्किंग अच्छी तरह से (और तेज़) लेकिन पारदर्शिता नहीं करता है, क्या को इन दो कॉलों को एक साथ जोड़ने का एक तरीका है (शायद एक तीसरी परत का उपयोग करना)?

unit MainWnd; 

interface 

uses 
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
    Dialogs, ExtCtrls, ControlsEx; 

type 
{------------------------------------------------------------------------------} 
    TfrmMain = class(TForm) 
    PaintBox1: TPaintBox; 
    procedure PaintBox1Paint(Sender: TObject); 
    private 
    { Private declarations } 
    public 
    { Public declarations } 
    end; 

var 
    frmMain: TfrmMain; 

implementation 

{$R *.dfm} 

{..............................................................................} 
procedure copyToAlpha(const in_bitmap : TBitmap; const in_transparentColor : TColor; 
     const in_transparency : integer); 
var 
    x : integer; 
    y : integer; 
    p : integer; 
begin 
    ASSERT(in_bitmap.PixelFormat = pf32bit); 

    for x := 0 to in_bitmap.Width - 1 do 
    begin 
    for y := 0 to in_bitmap.Height - 1 do 
    begin 
     p := in_bitmap.Canvas.Pixels[x, y]; 
     if TColor(p) <> in_transparentColor then 
     begin 
     in_bitmap.Canvas.Pixels[x, y] := p or (in_transparency shl 24); 
     end 
     else 
     in_bitmap.Canvas.Pixels[x, y] := p or ($ff shl 24); 
    end; 
    end; 
end; 

{..............................................................................} 
procedure alphaBlendTest(
     const in_target : TCanvas; 
     const in_width : integer; 
     const in_height : integer); 
const 
    BARSIZE = 30; 
var 
    bitmap : TBitmap; 
    r  : TRect; 
    blendFn : BLENDFUNCTION; 
    ret  : Boolean; 
begin 
    blendFn.BlendOp    := AC_SRC_OVER; 
    blendFn.SourceConstantAlpha := $ff; 
    blendFn.BlendFlags   := 0; 
    blendFn.alphaFormat   := AC_SRC_ALPHA; 

    bitmap := TBitmap.Create; 
    try 
    bitmap.Width    := in_width; 
    bitmap.Height    := in_height; 
    bitmap.PixelFormat  := pf32bit; 
    bitmap.HandleType   := bmDIB; 
    bitmap.TransparentColor := clFuchsia; 
    bitmap.Transparent  := true; 
    bitmap.Canvas.Brush.Color := clFuchsia; 
    bitmap.Canvas.FillRect(Bounds(0, 0, in_width, in_height)); 
    bitmap.Canvas.Brush.Color := clGreen; 

    r := Bounds(
     in_width div 2 - (in_width div 3) div 2, 
     0, 
     (in_width div 3) + 1, 
     BARSIZE   + 1); 

    bitmap.Canvas.Rectangle(r); 
    // done drawing 

    //copyToAlpha(bitmap, clFuchsia, 1); 
    ret := Windows.TransparentBlt(
     in_target.Handle, 
     0, 
     0, 
     in_width, 
     in_height, 
     bitmap.Canvas.Handle, 
     0, 
     0, 
     in_width, 
     in_height, 
     clFuchsia); 
     //blendFn); 

    ASSERT(ret); 
    finally 
    bitmap.Free; 
    end; 
end; 



{..............................................................................} 
procedure TfrmMain.PaintBox1Paint(Sender: TObject); 
var 
    r: TRect; 
begin 
    PaintBox1.Canvas.Brush.Color := clBlue; 
    r := Bounds(0, 0, PaintBox1.ClientWidth, PaintBox1.ClientHeight); 
    PaintBox1.Canvas.FillRect(r); 
    PaintBox1.Canvas.Brush.Color := clRed; 
    PaintBox1.Canvas.Ellipse(0, 0, PaintBox1.ClientWidth, PaintBox1.ClientHeight); 

    alphaBlendTest(PaintBox1.Canvas, PaintBox1.ClientWidth, PaintBox1.ClientHeight); 
end; 

end. 
+0

आप गुणक y प्रत्येक पिक्सेल की आर, जी, बी आपके वांछित अल्फा के साथ और 'अल्फाब्लेंड' के लिए 255 तक विभाजित करें, बेशक पिक्सेल के अल्फा को अल्फा मान पर भी सेट करें। मैं 'पारदर्शी बीएलटी' के बारे में सवाल नहीं समझता, पारदर्शिता कैसे अच्छी तरह से नहीं है? –

+3

@ सर्टैक ओपी में एक बिटमैप है जो आंशिक रूप से एक पारदर्शी रंग से बना है। पारदर्शी हिस्सों को गंतव्य कैनवास पर बरकरार रखना है, खींचे गए हिस्सों को गंतव्य कैनवास में वर्णित किया जाना है। – NGLN

उत्तर

8

ट्रिक: उसी रंग में उसी अनुपात में उसी रंग को मिश्रित करना।

तो, सबसे आसान तरीका (और शायद सबसे कुशल) पहले पारदर्शी परिणाम को अस्थायी बिटमैप में खींचना है, और गंतव्य कैनवास पर उस बिटमैप को जोड़ना है।

गंतव्य कैनवास के उपयोग के साथ

ड्राइंग दौरान:

procedure TfrmMain.PaintBox1Paint(Sender: TObject); 
const 
    BarSize = 30; 
var 
    R: TRect; 
    Bmp: TBitmap; 
    BlendFunc: TBlendFunction; 
begin 
    with PaintBox1 do 
    begin 
    R := ClientRect; 
    Canvas.Brush.Color := clBlue; 
    Canvas.FillRect(R); 
    Canvas.Brush.Color := clRed; 
    Canvas.Ellipse(R); 
    Bmp := TBitmap.Create; 
    try 
     Bmp.Width := Width; 
     Bmp.Height := Height; 
     BitBlt(Bmp.Canvas.Handle, 0, 0, Width, Height, Canvas.Handle, 0, 0, 
     SRCCOPY); 
     Bmp.Canvas.Brush.Color := clGreen; 
     R := Bounds(Width div 3, 0, Width div 3 + 1, BarSize + 1); 
     Bmp.Canvas.Rectangle(R); 
     BlendFunc.BlendOp := AC_SRC_OVER; 
     BlendFunc.BlendFlags := 0; 
     BlendFunc.SourceConstantAlpha := 80; 
     BlendFunc.AlphaFormat := 0; 
     Windows.AlphaBlend(Canvas.Handle, 0, 0, Width, Height, Bmp.Canvas.Handle, 
     0, 0, Width, Height, BlendFunc); 
    finally 
     Bmp.Free; 
    end; 
    end; 
end; 

और गंतव्य कैनवास के लिए उपयोग के बिना दौरान ड्राइंग:

procedure GetRemoteBitmap(Bmp: TBitmap; Width, Height: Integer); 
const 
    BarSize = 30; 
var 
    R: TRect; 
begin 
    Bmp.Canvas.Brush.Color := clFuchsia; 
    Bmp.Width := Width; 
    Bmp.Height := Height; 
    Bmp.TransparentColor := clFuchsia; 
    Bmp.Transparent := True; 
    Bmp.Canvas.Brush.Color := clGreen; 
    R := Bounds(Width div 3, 0, Width div 3 + 1, BarSize + 1); 
    Bmp.Canvas.Rectangle(R); 
end; 

procedure TfrmMain.PaintBox1Paint(Sender: TObject); 
var 
    R: TRect; 
    Bmp: TBitmap; 
    Tmp: TBitmap; 
    BlendFunc: TBlendFunction; 
begin 
    with PaintBox1 do 
    begin 
    R := ClientRect; 
    Canvas.Brush.Color := clBlue; 
    Canvas.FillRect(R); 
    Canvas.Brush.Color := clRed; 
    Canvas.Ellipse(R); 
    Bmp := TBitmap.Create; 
    Tmp := TBitmap.Create; 
    try 
     GetRemoteBitmap(Bmp, Width, Height); 
     Tmp.Width := Width; 
     Tmp.Height := Height; 
     BitBlt(Tmp.Canvas.Handle, 0, 0, Width, Height, Canvas.Handle, 0, 0, 
     SRCCOPY); 
     TransparentBlt(Tmp.Canvas.Handle, 0, 0, Width, Height, Bmp.Canvas.Handle, 
     0, 0, Width, Height, ColorToRGB(clFuchsia)); 
     BlendFunc.BlendOp := AC_SRC_OVER; 
     BlendFunc.BlendFlags := 0; 
     BlendFunc.SourceConstantAlpha := 80; 
     BlendFunc.AlphaFormat := 0; 
     Windows.AlphaBlend(Canvas.Handle, 0, 0, Width, Height, Tmp.Canvas.Handle, 
     0, 0, Width, Height, BlendFunc); 
    finally 
     Tmp.Free; 
     Bmp.Free; 
    end; 
    end; 
end; 
+1

मुझे "गंतव्य बिटमैप तक पहुंच के बिना * * का अर्थ नहीं मिलता है, लेकिन मुझे आपका पहला संस्करण पसंद है। :) –

+0

मुझे आश्चर्य है कि पिक्सल चलने से एक 'ब्लैट' तेज है, लेकिन मुझे लगता है कि यह शायद .. –

+1

@Sertac अगर उसे अपना बिटमैप मिलता है उदा। एक webservice ... – NGLN

4

बस पूर्णता के लिए के लिए ("मैं कैसे की गणना करते हैं अल्फा मान? "):

procedure alphaBlendTest(
     const in_target : TCanvas; 
     const in_width : integer; 
     const in_height : integer); 
const 
    BARSIZE = 30; 
var 
    bitmap : TBitmap; 
    r  : TRect; 
    blendFn : BLENDFUNCTION; 
    ret  : Boolean; 

    x, y: Integer; 
    px : PRGBQuad; 
begin 
    blendFn.BlendOp    := AC_SRC_OVER; 
    blendFn.SourceConstantAlpha := $ff; 
    blendFn.BlendFlags   := 0; 
    blendFn.alphaFormat   := AC_SRC_ALPHA; 

    bitmap := TBitmap.Create; 
    try 
    bitmap.Width    := in_width; 
    bitmap.Height    := in_height; 
    bitmap.PixelFormat  := pf32bit; 
    bitmap.Canvas.Brush.Color := clGreen; 

    r := Bounds(
     in_width div 2 - (in_width div 3) div 2, 
     0, 
     (in_width div 3) + 1, 
     BARSIZE   + 1); 

    bitmap.Canvas.Rectangle(r); 

    for y := 0 to bitmap.Height - 1 do begin 
     px := bitmap.ScanLine[y]; 
     for x := 0 to Bitmap.Width - 1 do begin 
     if PtInRect(r, Point(x, y)) then begin 
      px.rgbBlue := MulDiv(px.rgbBlue, $A0, $FF); 
      px.rgbGreen := MulDiv(px.rgbGreen, $A0, $FF); 
      px.rgbRed := MulDiv(px.rgbRed, $A0, $FF); 
      px.rgbReserved := $A0; 
     end else 
      px.rgbReserved := $00; // fully transparent 
     Inc(px); 
     end; 
    end; 
    // done drawing 

    ret := Windows.AlphaBlend(
     in_target.Handle, 
     0, 
     0, 
     in_width, 
     in_height, 
     bitmap.Canvas.Handle, 
     0, 
     0, 
     in_width, 
     in_height, 
     blendFn); 

    ASSERT(ret); 
    finally 
    bitmap.Free; 
    end; 
end; 
संबंधित मुद्दे