使用Xamarin iOS - 缩放图像后在其上绘制

3

我有一个应用程序,用户可以在加载的图像上自由绘制。他选择铅笔颜色,然后开始在图像上绘制。

除此之外,他可以使用手指将图像缩小和放大,这就是我遇到问题的地方。

缩放后,在图像上绘制时会变得模糊,并且奇怪地收缩...

缩放代码:

void ScaleImage (UIPinchGestureRecognizer gestureRecognizer)
        {
            AdjustAnchorPoint (gestureRecognizer);
            if (gestureRecognizer.State == UIGestureRecognizerState.Began || gestureRecognizer.State == UIGestureRecognizerState.Changed) {
                gestureRecognizer.View.Transform *= CGAffineTransform.MakeScale (gestureRecognizer.Scale, gestureRecognizer.Scale);
                gestureRecognizer.Scale = 1;
            }
        }

绘图代码:

public override void TouchesBegan (NSSet touches, UIEvent evt)
            {
                base.TouchesBegan (touches, evt);

                if (!canDraw)
                    return;

                UITouch touch = (UITouch)touches.AnyObject;
                lastPoint = touch.LocationInView (MyImageView);
            }

public override void TouchesMoved (NSSet touches, UIEvent evt)
        {
            base.TouchesMoved (touches, evt);

            if (!canDraw)
                return;

            UITouch touch       = (UITouch)touches.AnyObject;
            PointF currentPoint = touch.LocationInView (MyImageView);

            UIGraphics.BeginImageContext (MyImageView.Frame.Size);

            MyImageView.Image.Draw (new RectangleF (
                0, 0,
                MyImageView.Frame.Size.Width,
                MyImageView.Frame.Size.Height));

            CGContext ctx = UIGraphics.GetCurrentContext ();
            ctx.SetLineCap (CGLineCap.Round);
            ctx.SetLineWidth (5.0f);
            ctx.SetRGBStrokeColor (red, green, blue, 1);

            CGPath path = new CGPath ();
            path.MoveToPoint(MyImageView.Transform, lastPoint.X, lastPoint.Y);
            path.AddLineToPoint (MyImageView.Transform, currentPoint.X, currentPoint.Y);
            ctx.AddPath (path);
            ctx.DrawPath (CGPathDrawingMode.Stroke);

            MyImageView.Image = UIGraphics.GetImageFromCurrentImageContext ();
            UIGraphics.EndImageContext ();

            lastPoint = currentPoint;
        }

提前感谢您!

1个回答

3

我使用贝塞尔路径而不是核心图形使其工作。

您可以在此处找到有关Bezier Paths的一些背景信息: https://developer.apple.com/library/ios/documentation/2ddrawing/conceptual/drawingprintingios/BezierPaths/BezierPaths.html

由于我想要实现撤销按钮,所以我创建了一个类来存储线条的颜色以及相应的路径:

public class VESLine{
public UIBezierPath Path {
    get;
    set;
}

public UIColor Color {
    get;
    set;
}

public byte Index {
    get;
    set;
}
}

“TouchesBegan”事件相应地进行了修改,以创建一个新的UIBezierPath对象,并将其与其颜色和索引一起存储在数组中,同时存储触摸位置。”
public override void TouchesBegan (MonoTouch.Foundation.NSSet touches, UIEvent evt)
{
    IndexCount++;

    UIBezierPath path   = new UIBezierPath ();
    path.LineWidth      = 5.0f;

    UITouch touch   = (UITouch)touches.AnyObject;
    previousPoint1  = touch.PreviousLocationInView (this);

    PointF p = touch.LocationInView (this);
    path.MoveTo (p);

    InvokeOnMainThread (() => {
        this.SetNeedsDisplay ();
    });

    currentPath = path;

    VESLine line = new VESLine () {
        Path    = currentPath, 
        Color   = StrokeColor,
        Index   = IndexCount 
    };
    lines.Add(line);
}

TouchesMoved事件也进行了修改,通过使用QuadCurve而不是常规线条创建平滑的线条路径。我还调用了SetNeedsDisplay方法来强制视图绘制:

public override void TouchesMoved (MonoTouch.Foundation.NSSet touches, UIEvent evt)
{
    UITouch touch   = (UITouch)touches.AnyObject;
    PointF p        = touch.LocationInView (this);

    if (Math.Abs (p.X - previousPoint1.X) >= 4 ||
        Math.Abs (p.Y - previousPoint1.Y) >= 4) {

        PointF cP = new PointF ((p.X + previousPoint1.X) / 2, (p.Y + previousPoint1.Y) / 2);

        currentPath.AddQuadCurveToPoint (cP, previousPoint1);
        previousPoint1 = p;
    }
    else
        currentPath.AddLineTo (p);

    InvokeOnMainThread (() => {
        this.SetNeedsDisplay ();
    });
}

TouchesEndedTouchesCancelled 会重新绘制视图:

public override void TouchesEnded (MonoTouch.Foundation.NSSet touches, UIEvent evt)
{
    InvokeOnMainThread (() => {
        this.SetNeedsDisplay ();
    });
}

public override void TouchesCancelled (MonoTouch.Foundation.NSSet touches, UIEvent evt)
{
    InvokeOnMainThread (() => {
        this.SetNeedsDisplay ();
    });
}

最后,Draw方法被重写为迭代路径数组,使用相应的颜色绘制每个路径:
public override void Draw (System.Drawing.RectangleF rect)
{
    foreach (VESLine p in lines) {
        p.Color.SetStroke ();
        p.Path.Stroke ();
    }
}

1
非常感谢您的回答。它确实帮助了我。我还想补充一下,我在绘制的线条中遇到了一些看起来很奇怪的尖峰,但是我通过在TouchesBegan中的UIBezierPath对象中包含以下属性来解决了这个问题:UIBezierPath path = new UIBezierPath { LineJoinStyle = CGLineJoin.Round, LineCapStyle = CGLineCap.Round }; - hvaughan3
我并不怀疑你,但根据Bezier路径文档,它只是标准CGPath相关功能的包装器,那么它能做什么,你不能用CGPath已经做到了呢? - Trevor Hart

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接