【问题标题】:How to make part of an image transparent?如何使图像的一部分透明?
【发布时间】:2017-08-09 22:37:41
【问题描述】:

在delphi(Firmonkey)下,如果重要的话,在android下,我需要使位图的特定部分透明,即位图的圆角,如下图所示:

位图是通过Control.MakeScreenShot 生成的。

我尝试用透明像素替换所有左上角的红色像素,如下所示:

    if fScreenShot.Map(TMapAccess.ReadWrite, M) then
    try

      //make the top left corner transparent
      for x := 0 to fScreenShot.Width - 1 do begin
        aContinue := False;
        for y := 0 to fScreenShot.Height - 1 do begin
          if M.GetPixel(X,Y) = _FrameBGColor then begin
            aContinue := True;
            M.SetPixel(X,Y,TalphaColorRec.Null);
          end
          else break;
        end;
        if not aContinue then break;
      end;

    finally
      fScreenShot.Unmap(M);
    end;

但是指令 fScreenShot.Map(TMapAccess.ReadWrite, M) 非常慢(大约 200 毫秒)所以我不能这样做:( 有没有其他方法可以用透明替换这种红色颜色?

注意:现在(我只关注 android/ios,所以关注 OpenGL)我发现在画布中清除区域的唯一方法是执行

Canvas.SaveState;
Canvas.IntersectClipRect(TRectF.create());
Canvas.Clear(TalphaColorRec.Null);
canvas.RestoreState

但是这仅适用于矩形区域,不能应用于我的问题:(

注意 2 我接近找到使用 blending := False 的可行解决方案:

Canvas.blending := False;
Canvas.Fill.Color := $00000000;
Canvas.Fill.Kind := TbrushKind.Solid;
canvas.FillRect(TRectF.create(100,100,200,200), //const ARect: TRectF;
                0, 0, //const XRadius, YRadius: Single;
                [], //const ACorners: TCorners;
                1, // const AOpacity: Single;
                TCornerType.round);
Canvas.blending := true;

这段代码实际上清除了矩形。看起来不错,这就是我想对角落做的事情。所以我尝试用fillpath 替换FillRect,但我很不幸,它不适用于fillpath :( 任何想法?它适用于fillEllipseFillRect 等,但仅适用于fillpath不工作:(

【问题讨论】:

  • 我想知道那 200 毫秒。我什至无法测量一毫秒。那么如何衡量呢?
  • @TomBrunberg:这怎么可能?你是在windows下做的吗?我在 android 下完成并用 TstopWatch 测量它
  • 啊,好的。也许你应该添加Android标签。是的,我在 Windows 中测试过
  • 好吧,我补充说,我什至不知道这很重要,但是作为 windows 与 GDI 和 android 与 openGL 的接缝它们有些不同......这个问题让我发疯,它看起来很琐碎但找不到方法
  • 这可能是一个非常愚蠢的问题,但是这些红色像素最初是如何出现的呢?调用MakeScreenshot() 似乎为我生成了一个带有透明胶片的有效位图,至少在西雅图 10 号带有TRoundedRectangle

标签: android delphi opengl-es firemonkey


【解决方案1】:

如果有人找到这个并想要解决方案,我最终就是这样做的。最后我可以说,做这样一个微不足道的想法是非常复杂的:(

{************************************}
{$IF defined(IOS) or defined(android)}
type
  _TcustomCanvasGPUProtectedAccess = class(TcustomCanvasGPU);
{$ENDIF}

{************************************}
{$IF defined(IOS) or defined(android)}
procedure ClearRoundCorner(const aCanvas: Tcanvas; const ARect: TRectF; const ACorner: TCorner);

const
  MinFlatDistance = 4;

var
  Vertices: TCanvasHelper.TVertexArray;
  Colors: TCanvasHelper.TAlphaColorArray;
  Indices: TCanvasHelper.TIndexArray;
  Index, SubdivCount, VertexCount: Integer;
  Offset: integer;
  Angle: Single;
  Radius: TPointF;
  Center, CurPt, OriPt: TPointF;

begin
  Radius.X := ARect.Width;
  Radius.Y := ARect.Height;

  SubdivCount := (Max(Ceil(2 * Pi * Max(Radius.X, Radius.Y) / MinFlatDistance), 40) div 4) * 4; // https://quality.embarcadero.com/browse/RSP-15206
  VertexCount := (SubdivCount div 4) + 1;

  case ACorner of
    TCorner.BottomRight: begin
                           Offset := 0;
                           Center.X := ARect.left;
                           Center.Y := ARect.top;
                           OriPt.X := ARect.left + aRect.width;
                           OriPt.Y := ARect.bottom + aRect.height;
                         end;
    TCorner.BottomLeft: begin
                          Offset := (SubdivCount div 4);
                          Center.X := ARect.Right;
                          Center.Y := ARect.top;
                          OriPt.X := ARect.left - aRect.width;
                          OriPt.Y := ARect.bottom + aRect.height;
                        end;
    TCorner.TopLeft: begin
                       Offset := (SubdivCount div 4) * 2;
                       Center.X := ARect.right;
                       Center.Y := ARect.bottom;
                       OriPt.X := ARect.left - ARect.width;
                       OriPt.Y := ARect.top - aRect.height;
                     end;
    TCorner.TopRight: begin
                        Offset := (SubdivCount div 4) * 3;
                        Center.X := ARect.left;
                        Center.Y := ARect.Bottom;
                        OriPt.X := ARect.right + aRect.width;
                        OriPt.Y := ARect.top - aRect.height;
                      end;
  end;

  SetLength(Vertices, 1 + VertexCount);
  SetLength(Colors, 1 + VertexCount);
  SetLength(Indices, VertexCount * 3);

  CurPt := OriPt;

  //if Assigned(TransformCallback) then
  //  TransformCallback(CurPt);
  CurPt := _TcustomCanvasGPUProtectedAccess(aCanvas).TransformPoint(CurPt);
  //if FAlignToPixels then
  //  AlignToPixel(Result);

  Vertices[0] := CurPt;
  Colors[0] := TalphaColorRec.null;

  for Index := 0 to VertexCount - 1 do
  begin

    if index = VertexCount - 1 then CurPt := OriPt
    else begin

      Angle := (Offset + Index) * 2 * Pi / SubdivCount;

      CurPt.X := Cos(Angle) * Radius.X;
      CurPt.Y := Sin(Angle) * Radius.Y;

      CurPt.Offset(Center);

    end;

    //if Assigned(TransformCallback) then
    //  TransformCallback(CurPt);
    CurPt := _TcustomCanvasGPUProtectedAccess(aCanvas).TransformPoint(CurPt);
    //if FAlignToPixels then
    //  AlignToPixel(Result);

    Vertices[1 + Index] := CurPt;
    Colors[1 + Index] := TalphaColorRec.null;

    Indices[(Index * 3) + 0] := 0;
    Indices[(Index * 3) + 1] := 1 + Index;
    Indices[(Index * 3) + 2] := 1 + ((1 + Index) mod VertexCount);
  end;

  CanvasHelper.FillTriangles(Vertices, Colors, Indices, Length(Vertices), VertexCount);
end;
{$ENDIF}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-31
    • 2012-02-24
    • 2014-01-25
    • 1970-01-01
    • 2022-08-09
    • 2019-09-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多