将 BezierPath 转换为 SVG 文件
Turn a BezierPath into an SVG file
我有一个从下面的代码生成的 NSBezierPath,我想把这个路径变成一个 svg 文件(见下面的 svg 代码),我可以导入到 Adobe Illustrator 中。任何想法如何做到这一点?
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 使用 [NSBezierPath bezierPath] 指示路径数据的开始,而 svg 使用 d = "path data".
BezierPath 使用 moveToPoint 而 svg 使用 M.
BezierPath 使用 curveToPoint 而 svg 使用 c.
svg 不使用空格,而是使用非常紧凑的形式。
BezierPath使用绝对坐标,而svg使用相对坐标。
对于曲线,BezierPath 使用顺序 "point, controlPoint1, controlPoint2" 而 svg 使用顺序 "controlPoint1, controlPoint2, point".
观察我们将路径嵌入到 svg 中 width="200px" height="200px" 的框中。
使用这些观察结果,我们可以将 BezierPath 描述转换为 svg 描述,如下所示:
- moveToPoint: NSMakePoint(2, 30.41)]
翻译成M2,169.59 (M=MoveToPoint, 2=2, 200-30.41=169.59)
- curveToPoint: NSMakePoint(8.41, 1.91) controlPoint1: NSMakePoint(5.73, 41.21) controlPoint2: NSMakePoint(17.37, 63.33)]
翻译成
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))
等等
我想我可以使用这些观察来制作我自己的翻译,但如果已经有我可以使用的编写代码,那会更好更通用。
这是解决我的问题的一种方法。但它只适用于贝塞尔路径。请注意,我只是在填写路径数据。这必须以下面类型的一些静态文本开头。如果有人有更通用或更好的解决方案,我想听听。
<?xml version="1.0" encoding="utf-8"?>
...
stroke-linejoin="round
还请注意,我使用的 canvas 是 200x200(因此翻转 y 坐标时为 200)。
-(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;
}
我有一个从下面的代码生成的 NSBezierPath,我想把这个路径变成一个 svg 文件(见下面的 svg 代码),我可以导入到 Adobe Illustrator 中。任何想法如何做到这一点?
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 使用 [NSBezierPath bezierPath] 指示路径数据的开始,而 svg 使用 d = "path data".
BezierPath 使用 moveToPoint 而 svg 使用 M.
BezierPath 使用 curveToPoint 而 svg 使用 c.
svg 不使用空格,而是使用非常紧凑的形式。
BezierPath使用绝对坐标,而svg使用相对坐标。
对于曲线,BezierPath 使用顺序 "point, controlPoint1, controlPoint2" 而 svg 使用顺序 "controlPoint1, controlPoint2, point".
观察我们将路径嵌入到 svg 中 width="200px" height="200px" 的框中。
使用这些观察结果,我们可以将 BezierPath 描述转换为 svg 描述,如下所示:
- moveToPoint: NSMakePoint(2, 30.41)]
翻译成M2,169.59 (M=MoveToPoint, 2=2, 200-30.41=169.59)
- curveToPoint: NSMakePoint(8.41, 1.91) controlPoint1: NSMakePoint(5.73, 41.21) controlPoint2: NSMakePoint(17.37, 63.33)]
翻译成
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))
等等
我想我可以使用这些观察来制作我自己的翻译,但如果已经有我可以使用的编写代码,那会更好更通用。
这是解决我的问题的一种方法。但它只适用于贝塞尔路径。请注意,我只是在填写路径数据。这必须以下面类型的一些静态文本开头。如果有人有更通用或更好的解决方案,我想听听。
<?xml version="1.0" encoding="utf-8"?>
...
stroke-linejoin="round
还请注意,我使用的 canvas 是 200x200(因此翻转 y 坐标时为 200)。
-(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;
}