Turn a BezierPath into an SVG file

久未见 提交于 2019-12-25 00:59:51

问题


I have a NSBezierPath produced from code below, and I want to turn this path into a svg file (see the svg code below) that I can import into Adobe Illustrator. Any ideas how to do this?

BezierPath description

NSColor* color0 = [NSColor colorWithCalibratedRed: 0 green: 0 blue: 0 alpha: 1];

{
    //// Bezier Drawing
    NSBezierPath* bezierPath = [NSBezierPath bezierPath];
    [bezierPath moveToPoint: NSMakePoint(2, 30.41)];
    [bezierPath curveToPoint: NSMakePoint(8.41, 1.91) controlPoint1: NSMakePoint(5.73, 41.21) controlPoint2: NSMakePoint(17.37, 63.33)];
    [bezierPath curveToPoint: NSMakePoint(49.79, 1.53) controlPoint1: NSMakePoint(45.32, 94.95) controlPoint2: NSMakePoint(41.89, 1.26)];
    [bezierPath setMiterLimit: 4];
    [bezierPath setLineCapStyle: NSRoundLineCapStyle];
    [bezierPath setLineJoinStyle: NSRoundLineJoinStyle];
    [color0 setStroke];
    [bezierPath setLineWidth: 3];
    [bezierPath stroke];
}

svg description

<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
     width="200px" height="200px" viewBox="0 0 200 200" enable-background="new 0 0 200 200" xml:space="preserve">
<g id="n1">
    <path fill="none" stroke="#000000" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" d="M2,169.585
        c3.73-10.794,15.369-32.913,6.406,28.508c36.91-93.04,33.489,0.644,41.384,0.381"/>
</g>
</svg>

Some observations

BezierPath uses [NSBezierPath bezierPath] to indicate start of path data while svg use d = "path data".

BezierPath uses moveToPoint while svg uses M.

BezierPath uses curveToPoint while svg uses c.

svg does not use spaces, but instead uses a very compact form.

BezierPath uses absolute coordinates while svg uses relative coordinates.

For curves BezierPath uses the order "point, controlPoint1, controlPoint2" while svg uses the order "controlPoint1, controlPoint2, point".

Observe that we are embedding the path into a box of width="200px" height="200px" in svg.

Using these observations we could translate BezierPath description into svg description as follows:

  1. moveToPoint: NSMakePoint(2, 30.41)]

is translated into M2,169.59 (M=MoveToPoint, 2=2, 200-30.41=169.59)

  1. curveToPoint: NSMakePoint(8.41, 1.91) controlPoint1: NSMakePoint(5.73, 41.21) controlPoint2: NSMakePoint(17.37, 63.33)]

is translated into

c3.73-10.794,15.369-32.913,6.406,28.508

(c=curveToPoint, 3.73=5.73-2, -10.8=30.41-41.21, 15.37=17.37-2, 32.89=63.3-30.41, 6.41=8.41-2, 28.5=30.41-1.91))

and so on

I guess I could use these observations to make my own translations, but it would be nicer and more general if there was already written code that I could use.


回答1:


Here is one solution that solves my problem. But it only works for Bezier paths. Observe that I am only filling out the path data. This has to be preceded with some static text of type below. If anybody has a more general or nicer solution, I would like to hear it.

<?xml version="1.0" encoding="utf-8"?>
 ...
stroke-linejoin="round

Observe also that I am using a canvas which is 200x200 (hence 200 when flipping y coordinates).

-(NSString *)svgFromBezierPath:(NSBezierPath *)path {
    int numElements = (int) [path elementCount];
    if (numElements == 0) {
        return nil;
    }

    NSString *result = @"d=\"";
    NSPoint points[3];
    NSString *xStr;
    NSString *yStr;
    NSString *xCp1;
    NSString *yCp1;
    NSString *xCp2;
    NSString *yCp2;
    NSString *temp;
    double yValue;

    for (int i=0; i < numElements; i++)
    {
        switch ([path elementAtIndex:i associatedPoints:points])
        {
            case NSMoveToBezierPathElement:
                xStr = [NSString stringWithFormat:@"%0.2f", points[0].x];
                yValue = 200 - points[0].y;
                yStr = [NSString stringWithFormat:@"%0.2f", yValue];

                temp = [NSString stringWithFormat:@"M%@,%@,",xStr, yStr];
                result = [result stringByAppendingString:temp];
                break;

            case NSLineToBezierPathElement:
                xStr = [NSString stringWithFormat:@"%0.2f", points[0].x];
                yValue = 200 - points[0].y;
                yStr = [NSString stringWithFormat:@"%0.2f", yValue];

                temp = [NSString stringWithFormat:@"L%@,%@,",xStr, yStr];
                result = [result stringByAppendingString:temp];
                break;

            case NSCurveToBezierPathElement:
                xStr = [NSString stringWithFormat:@"%0.2f", points[0].x];
                yValue = 200 - points[0].y;
                yStr = [NSString stringWithFormat:@"%0.2f", yValue];

                xCp1 = [NSString stringWithFormat:@"%0.2f", points[1].x];
                yValue = 200 - points[1].y;
                yCp1= [NSString stringWithFormat:@"%0.2f", yValue];

                xCp2 = [NSString stringWithFormat:@"%0.2f", points[2].x];
                yValue = 200 - points[2].y;
                yCp2= [NSString stringWithFormat:@"%0.2f", yValue];

                temp = [NSString stringWithFormat:@"C%@,%@,%@,%@,%@,%@,", xStr, yStr, xCp1, yCp1,xCp2, yCp2];
                result = [result stringByAppendingString:temp];
                break;

            case NSClosePathBezierPathElement:
                result = [result stringByAppendingString:@"z,"];
                break;
        }
    }

    result = [result substringToIndex:result.length-1]; // delete the trailing comma
    result = [result stringByAppendingString:@"\"/></svg>"];
    return result;
}


来源:https://stackoverflow.com/questions/52334815/turn-a-bezierpath-into-an-svg-file

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!