Graphics32图层旋转

时间:2015-04-21 16:34:14

标签: delphi delphi-xe graphics32

我正在尝试将RotationLayer与常规TBitmapLayer结合使用,以便能够使用ImgView32层。

所以我的想法是:

  1. 我有一个TBitmapLayer(我需要它是BitmapLayer,因为我做的不仅仅是旋转)。它加载了BMP图像
  2. 我在我的表单上放置了一个TGaugeBar(就像GR32示例中那样)
  3. 当Gauge上有一个鼠标按下时,我开始进行计算:我创建一个RotationLayer,放置原始BitmapLayer.Bitmap的内容
  4. Gauge的OnChange,我使用在MouseDown中创建的RotLayer对象并给它一个角度,并将Selection选择为TBitmap,RotLayer.Bitmap
  5. 在MouseUp上,我释放了使用的临时RotationLayer对象
  6. 所以基本上:将图像从实际图层移动到临时旋转图层,在那里旋转,然后,完成后,将旋转后的图像移回BitmapLayer ......

    所以最后,我的逻辑似乎有效,除了我需要使用另一个SO问题(链接波纹)中提供的函数手动对BitmapLayer进行实际旋转。因为看起来rotateLayer实际上并没有在它的Bitmap中旋转图像。它似乎只是显示它旋转...

    现在我的问题是:

    1. 我需要能够'调整'原始的TBitmapLayer,以便它不会裁剪旋转的图像以适应旧的BitmapLayer
    2. 当显示rotationLayer时,我使用BitmapCenter在初始BitmapLayer的顶部显示它(我找不到另一种方法将它定位在我想要的位置)。但是,这个BitmapCenter似乎有2个用法:一个是定位图层,另外两个是设置旋转周围的点。如何仍然将旋转图层精确定位在原始BitmapLayer的顶部并且仍然在Bitmap的中间具有BitmapCenter(旋转中心)?
    3. 似乎当我开始旋转时,所以创建了rotationLayer并使用我的Bitmap加载,我认为alphaChannel会发生一些事情,因为我认为每次分配BitmapLayer.Bitmap时图像会变得更暗和半透明到RotationLayer.Bitmap。 我注意到,通过评论MasterAlpha:= 200行,图像不会失去它的亮度,但现在当RotationLayer可见时,图层矩形的空白部分变为黑色。所以它看起来很糟糕......当我执行MouseUP时(所以当我将旋转的Bitmap分配给BitmapLayer.Bitmap时,一些黑线在旋转图像的外部仍然可见,因此在空白区域中)。关于如何保持原始图像清洁的任何建议?
    4. 请协助我解决这3个问题。

      目前的工作代码是:

      procedure TMainForm.myrotMouseDown(Sender: TObject; Button: TMouseButton;
        Shift: TShiftState; X, Y: Integer);
      var
        l,r,t,b:single;
        flrect:TFloatRect;
      begin
          ro:=TRotlayer.Create(imgView.Layers);
          ro.Bitmap:=TBitmap32.Create;
          with ro.Bitmap do
          begin
            BeginUpdate;
            ro.Bitmap.Assign((Selection as TBitmapLayer).Bitmap);
            TLinearResampler.Create(ro.Bitmap);
            //ensure good looking edge, dynamic alternative to SetBorderTransparent
            TCustomResampler(ro.Bitmap.Resampler).PixelAccessMode := pamTransparentEdge;
            ro.BitmapCenter := FloatPoint(-(Selection as TBitmapLayer).Location.Left, -(Selection as TBitmapLayer).Location.Top);
      //      MasterAlpha := 200;
            FrameRectS(BoundsRect, $FFFFFFFF);
            DrawMode := dmBlend;
            EndUpdate;
            Changed;
          end;
          ro.Scaled := True;
          (Selection as TBitmapLayer).Bitmap.Assign(ro.Bitmap);
      end;
      
      procedure TMainForm.myrotChange(Sender: TObject);
      begin
        ro.Angle := myRot.Position;
        (Selection as TBitmapLayer).Bitmap.Assign(ro.Bitmap);
      end;
      
      procedure TMainForm.myrotMouseUp(Sender: TObject; Button: TMouseButton;
        Shift: TShiftState; X, Y: Integer);
      begin
          bmx:=TBitmap32.Create;
          bmx.Assign((Selection as TBitmapLayer).Bitmap);
          RotateBitmap(bmx, -(Round(ro.Angle)), false, clWhite32, true);
          (Selection as TBitmapLayer).Bitmap.Assign(bmx);
          bmx.Free;
          ro.Free;
      end;
      

      从此SO question

      中选取RotateBitmap函数

      旋转透明图像时也会出现问题...使用上面的代码自行测试并加载一些透明的PNG,您就会明白问题。

1 个答案:

答案 0 :(得分:0)

答案(这些问题应该是单独的问题,但由于它们密切相关,我会处理它们。希望我不会被钉死。)

  1. 调整TBitmapLayer的大小以适应旋转的图像。 您可以通过设置TBitmapLayer.Location在MyRotMouseUp过程中执行此操作。旋转的位图具有正确的WidthHeight属性。有关示例,请参阅下面的代码。如图所示设置位置也会将其保持在ImgView

  2. 的中心
  3. 如何将TRotationLayer准确定位在TBitmapLayer的顶部,并将旋转中心放在图像的中心。 TRotationLayer定位Position属性。位图旋转中心使用BitmapCenter属性单独设置 定位TRotLayer与定位其他图层(f.ex。TBitmapLayer)的不同之处在于,它使用Position: TFloatPoint字符与Location: TFloatRect用于其他图层。 Position定义图层的中心点 与其他图层一样,参考坐标系取决于Scaled属性。如果Scaled=False(默认值),则引用TImgView32边界。如果您在TimgView32.Bitmap中加载了较大的图像,并使用滚动条滚动图像,则TRotLayer不随图像移动。另一方面,如果Scaled=True TImgView32.Bitmap引用TRotLayer,则Scaled会在滚动时跟随图像。 要将旋转图层绑定到位图播放器以便它们一起滚动,请将两个图层True属性设置为Location,然后更改设置PositionmyRotMouseDown()的方式。我已经对代码添加了必要的修改。

  4. 在旋转图层和原始位图之间来回分配位图时,图像颜色会发生变化。

  5. 是的,我清楚地看到您对原始代码的意思。这就是为什么我在评论中建议保持原始图像清洁(未旋转)并跟踪角度,以便原始图像可以用于仅显示一个变换。仍然有一些可见的退化,但它并没有堆积到无法使用。

    bmo: TBitmap32:原始图片(代码中的rol: TRotationLayer)被分配给旋转图层(bml: TBitmapLayer)位图。 Visible := False被隐藏(myRotChange())。这里没有分配任何其他位图。

    myRotMouseUp()处:更改旋转图层角度,并使用相同的角度数据更新表格全局变量。这里没有分配任何其他位图。

    bml: TBitmapLayer.Bitmap处:原始图像被分配给位图图层(RotateBitmap()),并使用bml.Location过程使用表单中存储的角度旋转该位图。更新bmx: TBitmap32以适应旋转的图像。此处未分配任何其他位图(不需要bml)。 RotateBitmap()再次可见。

    我还建议不要保存旋转的图像,而只是保存角度。这样,原始图像可以保持不变,并且可以在需要时以保存的角度显示。

    代码 (没有必要更改 private bmo: TBitmap32; // original bitmap bml: TBitmapLayer; // bmx: TBitmap32; rol: TRotLayer; roa: single; // rotation angle 所以我不在此处包括)
    表格字段

    procedure TForm9.FormCreate(Sender: TObject);
    var
      dstr, srcr: TRect;
      png: TPortableNetworkGraphic32;
    begin
      png := TPortableNetworkGraphic32.Create;
      png.LoadFromFile('c:\tmp\imgs\arr-2.png');
      bmo:= TBitmap32.Create;
      bmo.Assign(png);
    //  bmo.LoadFromFile('c:\tmp\imgs\arr.bmp');
      png.Free;
      bml := TBitmapLayer.Create(ImgView.Layers);
      bml.Bitmap.SetSize(bmo.Width, bmo.Height);
      bml.Scaled := True;  // !!! Changed to True for synching with rol !!!
      //bml.Location := FloatRect(
      //  (ImgView.Width  - bml.Bitmap.Width) * 0.5,
      //  (ImgView.Height - bml.Bitmap.Height)* 0.5,
      //  (ImgView.Width  + bml.Bitmap.Width) * 0.5,
      //  (ImgView.Height + bml.Bitmap.Height)* 0.5);
      // !!! Change follows to synch scrolling of bml and rol
      bml.Location := FloatRect(
        (ImgView.Bitmap.Width  - bml.Bitmap.Width) * 0.5,
        (ImgView.Bitmap.Height - bml.Bitmap.Height)* 0.5,
        (ImgView.Bitmap.Width  + bml.Bitmap.Width) * 0.5,
        (ImgView.Bitmap.Height + bml.Bitmap.Height)* 0.5);
      dstr := Rect(0, 0, bmo.Width, bmo.Height);
      srcr := Rect(0, 0, bmo.Width, bmo.Height);
      bml.Bitmap.DrawMode := dmBlend;
      bml.Bitmap.Draw(dstr, srcr, bmo.Handle);
    end;
    
    procedure TForm9.FormDestroy(Sender: TObject);
    begin
      bmo.Free;
    end;
    
    procedure TForm9.myRotChange(Sender: TObject);
    begin
      rol.Angle := myRot.Position * 3.6;
      roa := rol.Angle;
    //  (Selection as TBitmapLayer).Bitmap.Assign(ro.Bitmap);
    end;
    
    procedure TForm9.myRotMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    var
      l, r, t, b: single;
      flrect: TFloatRect;
    begin
      rol := TRotLayer.Create(ImgView.Layers);
      rol.Scaled := True; // !!! Added for synching with bml
      with rol.Bitmap do
      begin
        BeginUpdate;
        Assign(bmo);
        // rol.Position := FloatPoint(ImgView.Width * 0.5, ImgView.Height* 0.5);
        // !!! Change follows to synch scrolling of bml and rol
        rol.Position := FloatPoint(
          (bml.Location.Right  + bml.Location.Left)*0.5,
          (bml.Location.Bottom + bml.Location.Top)*0.5);
    //    rol.Bitmap.Assign((Selection as TBitmapLayer).Bitmap);
        TLinearResampler.Create(rol.Bitmap);
        // ensure good looking edge, dynamic alternative to SetBorderTransparent
        TCustomResampler(rol.Bitmap.Resampler).PixelAccessMode := pamTransparentEdge;
    //    ro.BitmapCenter := FloatPoint(-(Selection as TBitmapLayer).Location.Left,
    //      -(Selection as TBitmapLayer).Location.Top);
        rol.BitmapCenter := FloatPoint(Width * 0.5, Height * 0.5);
        // MasterAlpha := 200;
        FrameRectS(BoundsRect, $FFFFFFFF);
        DrawMode := dmBlend;
        rol.Angle := roa;
        EndUpdate;
        Changed;
      end;
      bml.Visible := False;
    //  (Selection as TBitmapLayer).Bitmap.Assign(ro.Bitmap);
    end;
    
    procedure TForm9.myRotMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    begin
      bml.Bitmap.Assign(bmo);
      RotateBitmap(bml.Bitmap, -(Round(roa)), True, clWhite32, True);
      //bml.Location := FloatRect(
      //  (ImgView.Width  - bml.Bitmap.Width) * 0.5,
      //  (ImgView.Height - bml.Bitmap.Height)* 0.5,
      //  (ImgView.Width  + bml.Bitmap.Width) * 0.5,
      //  (ImgView.Height + bml.Bitmap.Height)* 0.5);
      // !!! Change follows to synch scrolling of bml and rol
      bml.Location := FloatRect(
        (ImgView.Bitmap.Width  - bml.Bitmap.Width) * 0.5,
        (ImgView.Bitmap.Height - bml.Bitmap.Height)* 0.5,
        (ImgView.Bitmap.Width  + bml.Bitmap.Width) * 0.5,
        (ImgView.Bitmap.Height + bml.Bitmap.Height)* 0.5);
      bml.Bitmap.DrawMode := dmBlend;
      rol.Free;
      bml.Visible := True;
    end;
    

    方法

    {{1}}

    最后一些截图:首先,没有旋转图像就好了。第二次旋转,边缘不是像素完美,但合理。

    enter image description here

    enter image description here