2012-04-26 53 views
10

Tổng quanLàm cách nào để vẽ trên Canvas có Độ trong suốt và Độ mờ?

Từ thư viện GR32, Tôi đang sử dụng TImgView32 để render một mạng lưới mà sẽ là nền trong suốt của tôi như vậy:

enter image description here

Được đặt bên trong TImgView32 Tôi có một TImage thường xuyên, nơi tôi sẽ vẽ lên canvas, một cái gì đó như thế này:

enter image description here

Tác vụ

Điều tôi muốn đạt được là khả năng đặt độ mờ của cọ vẽ, cho phép thêm khả năng chỉnh sửa hình ảnh trong chương trình của tôi. Thay vì có một màu phẳng được vẽ, việc đặt độ mờ của bàn chải cho phép các mức độ màu khác nhau, vv ..

Tôi tìm thấy câu hỏi này trước khi tìm kiếm xung quanh: Draw opacity ellipse in Delphi 2010 - Andreas Rejbrand đã cung cấp một vài ví dụ trong câu trả lời của mình câu hỏi.

Tôi đã xem những gì Andreas đã làm, và đã đưa ra nỗ lực đơn giản của riêng tôi nhưng tôi đang mắc kẹt với một vấn đề. Hãy nhìn vào hai hình ảnh tiếp theo này, đầu tiên là với nền trong suốt và lần thứ hai với một nền đen để hiển thị các vấn đề hơn rõ ràng hơn:

enter image description here enter image description here

Như bạn thấy, xung quanh bàn chải (vòng tròn) là một hình vuông thực sự gây phiền nhiễu tôi không thể thoát khỏi. Tất cả những gì nên được nhìn thấy là bàn chải. Đây là mã của tôi sử dụng để tạo ra những kết quả:

procedure DrawOpacityBrush(ACanvasBitmap: TBitmap; X, Y: Integer; 
    AColor: TColor; ASize: Integer; Opacity: Integer); 
var 
    Bmp: TBitmap; 
begin 
    Bmp := TBitmap.Create; 
    try 
    Bmp.SetSize(ASize, ASize); 
    Bmp.Transparent := False; 

    with Bmp.Canvas do 
    begin 
     Pen.Color := AColor; 
     Pen.Style := psSolid; 
     Pen.Width := ASize; 
     MoveTo(ASize div 2, ASize div 2); 
     LineTo(ASize div 2, ASize div 2); 
    end; 

    ACanvasBitmap.Canvas.Draw(X, Y, Bmp, Opacity); 
    finally 
    Bmp.Free; 
    end; 
end; 

procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton; 
    Shift: TShiftState; X, Y: Integer); 
begin 
    DrawOpacityBrush(Image1.Picture.Bitmap, X, Y, clRed, 50, 85); 
end; 

trong đó sản xuất này trên một bitmap thường xuyên:

enter image description here

Ý tưởng tôi đã (dựa trên Andreas cách tạo ra một hình elip với opacity) là để render một brush điển hình trên canvas, gán nó vào một bitmap offscreen sau đó vẽ lại nó vào bitmap chính với opacity. Mà làm việc, ngoại trừ quảng trường gây phiền nhiễu xung quanh các cạnh.

Làm cách nào để hiển thị bàn chải có độ mờ như minh họa trong ảnh chụp màn hình, nhưng không có hình vuông xung quanh vòng tròn cọ vẽ?

Nếu tôi đặt Bmp.Transparent := True thì vẫn còn một hộp màu trắng, nhưng không còn độ mờ. Chỉ cần một hình vuông màu trắng và hình tròn màu đỏ đầy rắn.

Trả lời

13

Tính năng Opacity của TCanvas.Draw() không hỗ trợ những gì bạn đang cố gắng làm, ít nhất không phải cách bạn đang cố gắng sử dụng. Để thực hiện tác động bạn muốn, bạn cần tạo một 322 bit TBitmap 32 bit để bạn có kênh alpha mỗi pixel, sau đó điền vào alpha cho mỗi pixel, đặt alpha thành 0 cho pixel bạn không muốn và đặt alpha đến độ mờ mong muốn cho các pixel bạn muốn. Sau đó, khi gọi số TCanvas.Draw(), hãy đặt độ mờ của nó là 255 để cho nó chỉ sử dụng độ mờ cho mỗi pixel.

procedure DrawOpacityBrush(ACanvas: TCanvas; X, Y: Integer; AColor: TColor; ASize: Integer; Opacity: Byte); 
var 
    Bmp: TBitmap; 
    I, J: Integer; 
    Pixels: PRGBQuad; 
    ColorRgb: Integer; 
    ColorR, ColorG, ColorB: Byte; 
begin 
    Bmp := TBitmap.Create; 
    try 
    Bmp.PixelFormat := pf32Bit; // needed for an alpha channel 
    Bmp.SetSize(ASize, ASize); 

    with Bmp.Canvas do 
    begin 
     Brush.Color := clFuchsia; // background color to mask out 
     ColorRgb := ColorToRGB(Brush.Color); 
     FillRect(Rect(0, 0, ASize, ASize)); 
     Pen.Color := AColor; 
     Pen.Style := psSolid; 
     Pen.Width := ASize; 
     MoveTo(ASize div 2, ASize div 2); 
     LineTo(ASize div 2, ASize div 2); 
    end; 

    ColorR := GetRValue(ColorRgb); 
    ColorG := GetGValue(ColorRgb); 
    ColorB := GetBValue(ColorRgb); 

    for I := 0 to Bmp.Height-1 do 
    begin 
     Pixels := PRGBQuad(Bmp.ScanLine[I]); 
     for J := 0 to Bmp.Width-1 do 
     begin 
     with Pixels^ do 
     begin 
      if (rgbRed = ColorR) and (rgbGreen = ColorG) and (rgbBlue = ColorB) then 
      rgbReserved := 0 
      else 
      rgbReserved := Opacity; 
      // must pre-multiply the pixel with its alpha channel before drawing 
      rgbRed := (rgbRed * rgbReserved) div $FF; 
      rgbGreen := (rgbGreen * rgbReserved) div $FF; 
      rgbBlue := (rgbBlue * rgbReserved) div $FF; 
     end; 
     Inc(Pixels); 
     end; 
    end; 

    ACanvas.Draw(X, Y, Bmp, 255); 
    finally 
    Bmp.Free; 
    end; 
end; 

procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton; 
    Shift: TShiftState; X, Y: Integer); 
begin 
    DrawOpacityBrush(Image1.Picture.Bitmap.Canvas, X, Y, clRed, 50, 85); 
end; 
+0

Câu trả lời tuyệt vời nhờ Remy.Tôi đã nhận thức được bitmap của tôi là pf24Bit, nhưng không biết hoặc xem xét việc đặt nó thành pf32bit. Tôi có thể làm nền của tôi xóa sai là tốt sau đó, bởi vì tôi đang thiết lập màu minh bạch để cố định và giá trị để clBtnFace khi tôi xóa. –

+1

Bạn cũng có thể thấy lớp này hữu ích: http://code.google.com/p/transparent-canvas/. Đó là một trình bao bọc xung quanh bản vẽ 32-bit, mỗi pixel-alpha với một giao diện rất giống với TCanvas. Tạo một, vẽ nó, sau đó vẽ nó vào một khung vẽ, xong. Được cấp phép MPL để bạn có thể sử dụng nó ở mọi nơi. –

Các vấn đề liên quan