Pergunta

I'm trying to figure out the best way to accomplish warping a GraphicsPath in .net to a specific shape. The result I'm trying to achieve is warping text to curve up, down, fan left, right, and things like a wave. All of these can be achieved in Adobe Illustrator using the envelope distort feature.

I have considered rolling my own method of doing this using some of predefined grid and point mapping system to transform points. However, it seems like there would be some algorithms or samples as to how to do this already available?

Foi útil?

Solução

Here's a couple of methods from a captcha generator we use that might steer you in the right direction:

    internal static void DrawPhrase(
        this Graphics graphics, 
        int width, 
        int height, 
        string phrase)
    {
        graphics.FillRectangle(
            Brushes.White,
            0,
            0,
            width,
            height);

        using (var gp = new GraphicsPath())
        {
            gp.AddString(phrase,
                         FontFamily.GenericMonospace,
                         (int)FontStyle.Bold,
                         33f,
                         new Point(0,
                                   0),
                         StringFormat.GenericTypographic);

            using (var gpp = gp.Deform(width, height))
            {
                var bounds = gpp.GetBounds();
                var matrix = new Matrix();
                var x = (width - bounds.Width) / 2 - bounds.Left;
                var y = (height - bounds.Height) / 2 - bounds.Top;
                matrix.Translate(x,
                                 y);
                gpp.Transform(matrix);
                graphics.FillPath(Brushes.Black,
                                  gpp);
            }
        }

        graphics.Flush();
    }
    internal static GraphicsPath Deform(
        this GraphicsPath path, 
        int width, 
        int height)
    {
        var WarpFactor = 4;
        var xAmp = WarpFactor * width / 300d;
        var yAmp = WarpFactor * height / 50d;
        var xFreq = 2d * Math.PI / width;
        var yFreq = 2d * Math.PI / height;
        var deformed = new PointF[path.PathPoints.Length];
        var xSeed = rng.NextDouble() * 2 * Math.PI;
        var ySeed = rng.NextDouble() * 2 * Math.PI;
        var i = 0;
        foreach (var original in path.PathPoints)
        {
            var val = xFreq * original.X + yFreq * original.Y;
            var xOffset = (int)(xAmp * Math.Sin(val + xSeed));
            var yOffset = (int)(yAmp * Math.Sin(val + ySeed));
            deformed[i++] = new PointF(original.X + xOffset,
                                     original.Y + yOffset);
        }

        return new GraphicsPath(deformed,
                                path.PathTypes);
    }

Outras dicas

I wanted to follow up to this post I made some time ago. I have had worked out a few other ways to accomplish what I wanted to do originally in this post. First off GraphicsPath has a nice warp() method which performs just that, warping any path into the 4 points of a rectangle. Using this idea you can accomplish this below.

Warping up to the right

Here is the same warp applied to a path with text arched up

Text Arched Up Warp

This is the classic star wars text warp by just setting the 4 points of the rectangle in the warp() method Star Wars Text Warp

The same warp applied to a path that is arched up.

Arched Down with a Star Wars Warp

What I have concluded is a lot of warps can be accomplished by first typing on a path such as an arch or a wave, then applying the warp() method in a GraphicsPath.

Updated

I finally got around to actually coming up with a real solution to this almost 2 years later. I posted an in depth explanation with code on my blog. Read it here

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top