How to paint on a Canvas with Transparency and Opacity?

后端 未结 1 1556
臣服心动
臣服心动 2021-02-05 22:56

Overview

From the GR32 library, I am using TImgView32 to render a grid which will be my transparent background like so:

相关标签:
1条回答
  • 2021-02-05 23:39

    The Opacity feature of TCanvas.Draw() does not support what you are trying to do, at least not the way you are trying to use it. To accomplish the affect you want, you need to create a 32-bit TBitmap so you have a per-pixel alpha channel, then fill in the alpha for each pixel, setting the alpha to 0 for pixels you don't want, and setting the alpha to the desired opacity for the pixels you do want. Then, when calling TCanvas.Draw(), set its opacity to 255 to tell it to use just the per-pixel opacities.

    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 讨论(0)
提交回复
热议问题