【问题标题】:How to Fill a path with a pattern in Quartz如何在 Quartz 中用图案填充路径
【发布时间】:2013-04-26 18:44:43
【问题描述】:

我创建了一个视图,并在我的 draw rect 方法中创建了路径,具体取决于用户对滑块的操作。使用标准颜色,一切正常,看起来非常漂亮。我正在尝试遵循来自苹果的代码 sn-p,该代码显示了如何在此链接上将模式绘制到矩形中: Apple Drawing Guide

该示例展示了如何创建一个具有所需模式的函数回调,然后调用一个额外的方法来绘制矩形。如果我按照我的 rect 编写的代码调用代码,它将按照我的预期绘制我的模式,但是,我不想填充我的 rect ,我想填充 rect 中的指定路径。如果我将绘图方法中的调用从 CGContextFillRect 更改为 CGContextFillPath,它就不起作用。我确定我忽略了一些东西来修改此代码以使其执行我想要的操作。

我的回调模式是一个简单的棋盘:

代码:

// Call Back function for Graphics Pattern

#define PATTERN_SIZE 10

void patternSpec(void *info , CGContextRef pContext){

    NSLog(@"patternSpec Callback Called");
    CGFloat subUnit = PATTERN_SIZE / 2;

    CGRect square1 = {{0,0}, {subUnit, subUnit}},
    square2 = {{subUnit, subUnit}, {subUnit, subUnit}},
    square3 = {{0 , subUnit}, {subUnit, subUnit}},
    square4 = {{subUnit , 0}, {subUnit, subUnit}};


    CGContextSetRGBFillColor(pContext, 1.0, 0.0, 0.0, 1.0 );
    CGContextFillRect(pContext, square1);

    CGContextSetRGBFillColor(pContext, 1.0, 0.0, 0.0, 1.0 );
    CGContextFillRect(pContext, square2);

    CGContextSetRGBFillColor(pContext, 0.0, 0.0, 0.0, 1.0 );
    CGContextFillRect(pContext, square3);

    CGContextSetRGBFillColor(pContext, 0.0, 0.0, 0.0, 1.0 );
    CGContextFillRect(pContext, square4);

}

// Method that draws the pattern

static void drawPattern (CGContextRef myContext)
{
    NSLog(@"drawPattern Called ");
    CGPatternRef    pattern;
    CGColorSpaceRef patternSpace;
    CGFloat         alpha = 1.0;
    //width, height;

    static const CGPatternCallbacks callbacks = {0, &patternSpec, NULL};

    CGContextSaveGState (myContext);
    patternSpace = CGColorSpaceCreatePattern (NULL);// 6
    CGContextSetFillColorSpace (myContext, patternSpace);// 7
    CGColorSpaceRelease (patternSpace);// 8

    pattern = CGPatternCreate (NULL,CGRectMake (0, 0, PATTERN_SIZE, PATTERN_SIZE),
    CGAffineTransformIdentity, PATTERN_SIZE, PATTERN_SIZE,
    kCGPatternTilingConstantSpacing true, &callbacks);

    CGContextSetFillPattern (myContext, pattern, &alpha);// 17
    CGPatternRelease (pattern);// 18
    //CGContextFillRect(myContext, rect);
    CGContextDrawPath(myContext, kCGPathFill);
    CGContextRestoreGState (myContext);

}

这是我要调用例程的代码的 sn-p:

CGContextSetLineWidth(context, .7);
CGContextSetRGBStrokeColor(context, 0.0, 0.0, 0.0, 1.0);


// Standard non-inverted view scenario.
CGContextBeginPath(context);

CGContextMoveToPoint(context, 0.00 , bMargin);      
CGContextAddLineToPoint(context, highPX - curveSP , bMargin);
[self addCurve:context startX:highPX startY:bMargin radius:bo curveSp:curveSP curveDir:FL_BL];

CGContextAddLineToPoint(context, highPX, ((h - tMargin) - curveSP) );
[self addCurve:context startX:highPX startY: (h - tMargin) radius:bo curveSp:curveSP curveDir:FL_TL];


CGContextAddLineToPoint(context, (lowPX - curveSP), (h - tMargin) );
[self addCurve:context startX: lowPX  startY: (h - tMargin) radius:bo curveSp:curveSP curveDir:FL_TR];

CGContextAddLineToPoint(context, lowPX, (bMargin + curveSP) );      
[self addCurve:context startX:lowPX startY: bMargin  radius:bo curveSp:curveSP curveDir:FL_BR];

CGContextAddLineToPoint(context, w, bMargin);

//CGContextDrawPath(context, nonInvertedView);

CGContextDrawPath(context, kCGPathStroke);
// fill with pattern
drawPattern(context);

实际的苹果示例还在绘图方法中包含一个 NSRect 参数,但由于我不想填充矩形,我想我可以省略它。不过不确定。

谢谢

【问题讨论】:

    标签: cocoa design-patterns quartz-graphics graphics2d


    【解决方案1】:

    CGContextDrawPath 重置当前路径。 (他们曾经在某个地方提到过,但我在快速搜索中找不到。)

    在描边之前保存图形状态,然后在填充图案之前恢复。

    (我假设您特别想通过抚摸然后填充一半以上来获得外部笔划。如果您想要或可以接受居中的笔划,kCGPathFillStroke 将通过一个 CGContextDrawPath 调用来完成这项工作.)

    【讨论】:

    • 感谢您的意见。请查看我的自我回答和评论。为了回答你的问题,我试图在路径上保持一个简单的黑色笔触,并使用图案作为填充。抚摸路径不是问题,它正在用具有挑战性的图案替换标准颜色填充。我一直在调用代码中使用绘制路径。
    • @Miek:kCGPathFillStroke 会这样做。两者都不使用相同的颜色;它使用描边颜色/图案进行描边,使用填充颜色/图案进行填充。
    • 是的,你是对的,我在整个应用程序中一直在这样做。这更像是一个 setFill 或 setPattern 问题。如果您试图暗示我可以将 drawPath 放入 drawPattern 方法并取得成功,那么我确定我尝试过但没有运气。
    • @Miek:不,我根本不想暗示这一点。我明确表示。如果从问题中的代码开始,把后面代码中的kCGPathStroke去掉,把drawPattern改成kCGPathFillStroke,就可以了。 (我自己用一个简单的圆圈进行了测试。)
    • 是的。你是绝对正确的。当我应该将它用作绘图方法时,我试图将它用作填充方法。现在我可以正确地实现它了。非常感谢!
    【解决方案2】:

    所以这里有一个更新:我不完全理解发生了什么,但是如果我将 drawPattern 方法中的代码放到一个带有空矩形的测试应用程序中,它会像它应该的那样绘制。如果我将代码放入用于将路径绘制到视图中的方法中,我会得到非常奇怪的行为;它甚至试图重绘它不应该知道的视图控制器部分。

    我一删除 CGContextSaveGState() 、 CGColorSpaceRelease() 、 CGPatternRelease() 和 CGContextRestoreGState() ,代码就开始做我想做的事了。我将方法修改为:

    static void drawPattern(CGContextRef *pContext){
    
        static CGPatternRef    pattern;
        static CGColorSpaceRef patternSpace;
        static CGFloat         alpha = 1.0;
    
    
    static const CGPatternCallbacks callbacks = {0, &patternSpec, NULL};
    
        patternSpace = CGColorSpaceCreatePattern (NULL);
        CGContextSetFillColorSpace (pContext, patternSpace);
    
        pattern = CGPatternCreate (NULL, 
                   CGRectMake (0, 0, PATTERN_SIZE, PATTERN_SIZE),
                   CGAffineTransformIdentity,
                   PATTERN_SIZE, 
                   PATTERN_SIZE, 
                   kCGPatternTilingConstantSpacing,
                   true, &callbacks);
    
    
         CGContextSetFillPattern (pContext, pattern, &alpha);   
    
    }
    

    现在我可以调用定义的图案,或者设置定义的填充颜色:

    CGContextSetFillColor(context);
    or:    
    drawPattern(context);
    

    我希望能就此提供意见,因为我想知道省略其中一些 saveState 或 Release 方法是否会导致内存泄漏等问题。

    谢谢

    【讨论】:

    • 是的,不发布你拥有的东西就是你泄露它们的方式。保存和恢复 gstate 不是内存问题;这是一个正确性问题。我认为不需要围绕模式回调的全部内容进行 gsave 和 grestore。
    猜你喜欢
    • 2013-04-16
    • 1970-01-01
    • 2019-07-14
    • 2019-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-30
    • 2011-02-28
    相关资源
    最近更新 更多