iphone:将纹理应用于CGContext Stroke Path

时间:2011-07-09 14:22:54

标签: iphone ios ipad opengl-es core-graphics

我在StackOverflow中搜索所有问题和答案,但无法获得我想要的结果。我想使用PNG文件,在用户触摸和移动点显示为笔划。这是PNG文件:

enter image description here

但我在StackOverflow上做了所有的方法,即使使用CGPatternRef,但我没有我想要的结果。我的结果是:

enter image description here

但我想要的结果是:

enter image description here

这个结果我在OpenGL ES中完成了,但我不能在Core Graphics中做到这一点。我想我可以在每个点使用CGContextDrawImage,但这种方式导致性能不佳,因为我必须在用户触摸的2点之间绘制所有点的图像。我想你之前遇到过这个问题。你认为我可以在Core Graphics中应用纹理来绘制这样的笔画吗?我非常感激。

3 个答案:

答案 0 :(得分:4)

使用图案创建线条时,它看起来像第一个图像,而不是第二个图像。该线条只是将您提供的纹理图像平铺成线条的形状。没有办法让它知道你想要将圆圈合并在一起看起来像一条实线。为此你应该只用一个纯黑色的线。

对于任何想要在第一张图片中实现图案线条的人来说,有一个很好的教程解释如何在这里执行此操作:http://blog.robertturrall.com/tag/cgcontextsetstrokepattern/

基本上你需要的是:

// first define the pattern width and height
const float kPatternWidth = 8;
const float kPatternHeight = 8;

void DrawPatternCellCallback(void *info, CGContextRef cgContext) 
{
    // Create a CGImage and use CGContextDrawImage() to draw it into the graphics context provided by the callback function.
    UIImage *patternImage = [UIImage imageNamed:@"yourtextureimage.png"];
    CGContextDrawImage(cgContext, CGRectMake(0, 0, kPatternWidth, kPatternHeight), patternImage.CGImage);
}

确保“void”周围没有括号。还要确保DrawPatternCellCallback部分在drawRect之前出现,否则它将无效。

然后你的drawRect需要以下内容:

- (void)drawRect:(CGRect)rect {
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    const CGRect patternBounds = CGRectMake(0, 0, kPatternWidth, kPatternHeight);
    const CGPatternCallbacks kPatternCallbacks = {0, DrawPatternCellCallback, NULL};

    CGAffineTransform patternTransform = CGAffineTransformIdentity;
    CGPatternRef strokePattern = CGPatternCreate(
                                             NULL,
                                             patternBounds,
                                             patternTransform,
                                             kPatternWidth, // horizontal spacing
                                             kPatternHeight, // vertical spacing
                                             kCGPatternTilingNoDistortion,
                                             true,
                                             &kPatternCallbacks);
    CGFloat color1[] = {1.0, 1.0, 1.0, 1.0};

    CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL);
    CGContextSetStrokeColorSpace(ctx, patternSpace);
    CGContextSetStrokePattern(ctx, strokePattern, color1);
    CGContextSetLineWidth(ctx, 4.0);
    CGContextDrawPath(ctx);

    // If you aren't using ARC:
    CGPatternRelease(strokePattern);
    strokePattern = NULL;
    CGColorSpaceRelease(patternSpace);
    patternSpace = NULL;
}

答案 1 :(得分:2)

严重 ......

例如,如果您正在做一个将图像的模糊版本绘制在自身上的常见问题。

您几乎肯定需要这样的代码......

float isf;
isf = [[UIScreen mainScreen] bounds].size.width / wholeImageWidth;

(如果您正在全屏绘图;如果在窗口中绘图,则以明显的方式调整)其中wholeImageWidth是您正在编辑的图像的实际宽度。

然后当你创建笔划模式时,你可以像这样使用

CGAffineTransformScale( CGAffineTransformIdentity, isf, -isf)

但是请注意,你可能不得不为相机和相册重新调整它。所以像.......

if ( self.wasFromCameraNotAlbum )
  {
  strokePattern = CGPatternCreate(
     NULL,
     CGRectMake(0,0,wholeWidth,wholeHeight),

     CGAffineTransformConcat(
         CGAffineTransformScale( CGAffineTransformIdentity, isf, -isf),
         CGAffineTransformRotate( CGAffineTransformIdentity, 90*M_PI/180 )
         ),

     wholeWidth,wholeHeight,
     kCGPatternTilingNoDistortion, true, &kPatternCallbacks);
  }
else
  {
  strokePattern = CGPatternCreate(
     NULL,
     CGRectMake(0,0,wholeWidth,wholeHeight),

     CGAffineTransformScale( CGAffineTransformIdentity, isf, -isf),

     wholeWidth,wholeHeight,
     kCGPatternTilingNoDistortion, true, &kPatternCallbacks);
  }

对于谷歌搜索,这是由于相机,旋转,iPhone 6 +,iOS8,相册。


因为llama591的答案太棒了。这里有一些示例代码可能有一天会帮助某人。这是我可以为模式绘图编写的最简单的代码

这适用于Xcode5 / iOS7(2014年1月):

这是一些非常典型的绘制蓝色线条的绘图代码:

-(void)drawRect:(CGRect)rect
{
[curImage drawAtPoint:CGPointMake(0, 0)];
CGPoint mid1 = midPoint(previousPoint1, previousPoint2); 
CGPoint mid2 = midPoint(currentPoint, previousPoint1);
CGContextRef context = UIGraphicsGetCurrentContext(); 
[self.layer renderInContext:context];
CGContextMoveToPoint(context, mid1.x, mid1.y);
CGContextAddQuadCurveToPoint(context,
  previousPoint1.x, previousPoint1.y, mid2.x, mid2.y); 
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, 20.0);

CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);

CGContextStrokePath(context);            
[super drawRect:rect];
}

注意调用 CGContextSetStrokeColorWithColor ,它只是将该行设置为实线,在本例中为蓝色。

接下来是相同的代码。但是,我们替换了一行代码,用于绘制模式的所有代码。 (并且还有一个新的单独的回调例程,这是微不足道的。)

为清楚起见,这里只有15行代码,它将取代单个简单的StrokeColor代码行:

const CGPatternCallbacks kPatternCallbacks = {0, simplePatternCallback, NULL};
CGFloat color1[] = {1.0, 1.0, 1.0, 1.0};
CGPatternRef strokePattern = CGPatternCreate(
    NULL,
    CGRectMake(0,0,100,100),
    CGAffineTransformIdentity,
    100,100,
    kCGPatternTilingNoDistortion,
    true,
    &kPatternCallbacks);
CGContextSetStrokeColorSpace(UIGraphicsGetCurrentContext(),
        CGColorSpaceCreatePattern(NULL););
CGContextSetStrokePattern(context, strokePattern, color1);
CGPatternRelease(strokePattern);
strokePattern = NULL;

模式应该是项目中的PNG,可以说是100x100像素,这里称为“pattern100100.png”。

同样,我用代码的15行代码替换了1行代码。 (而且还有一个单独的简单回调函数。)以下是整个事情:

-(void)drawRect:(CGRect)rect
{
[curImage drawAtPoint:CGPointMake(0, 0)];
CGPoint mid1 = midPoint(previousPoint1, previousPoint2); 
CGPoint mid2 = midPoint(currentPoint, previousPoint1);
CGContextRef context = UIGraphicsGetCurrentContext(); 
[self.layer renderInContext:context];
CGContextMoveToPoint(context, mid1.x, mid1.y);
CGContextAddQuadCurveToPoint(context,
  previousPoint1.x, previousPoint1.y, mid2.x, mid2.y); 
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, 20.0);

const CGPatternCallbacks kPatternCallbacks = {0, simplePatternCallback, NULL};
CGFloat color1[] = {1.0, 1.0, 1.0, 1.0};
CGPatternRef strokePattern = CGPatternCreate(
    NULL,
    CGRectMake(0,0,100,100),
    CGAffineTransformIdentity,
    100,100,
    kCGPatternTilingNoDistortion,
    true,
    &kPatternCallbacks);
CGContextSetStrokeColorSpace(UIGraphicsGetCurrentContext(),
        CGColorSpaceCreatePattern(NULL););
CGContextSetStrokePattern(context, strokePattern, color1);
CGPatternRelease(strokePattern);
strokePattern = NULL;

CGContextStrokePath(context);            
[super drawRect:rect];
}

void simplePatternCallback(void *info, CGContextRef ctx)
{
UIImage *brushTexture = [UIImage imageNamed:@"pattern100100.png"];
CGContextDrawImage(ctx, CGRectMake(0, 0, 100,100), brushTexture.CGImage);
}

要在代码中包含几条有用的评论!

// re the final argument:
// from Apple doco: "If the specified pattern is a 'colored' pattern,
// pass an alpha value."
// in fact you have to pass in an array of four values.

// note, "stencil patterns" (aka "uncolored patterns") patterns
// are basically masks, rarely used

// re the "true" in CGPatternCreate, that means "coloured pattern"
// (ie not "stencil pattern")

我真的希望它有所帮助。

注意:每当您看到这样的代码示例时(即使在Apple)。他们总是“在drawRect内”完成整个事情。请注意,每次调用drawRect时都会创建“strokePattern”!对我来说,这似乎很疯狂,我总是简单地使用变量或属性“strokePattern”和其他元素。同样地,每次在回调中使用imageNamed都是荒谬的,只需使用您之前准备的属性。

我真的希望它可以帮助某人。干杯


有用的脚注:在CGPaternCreate中,示例代码显示参数3的CGAffineTransformIdentity。

通常,您会使用某些照片或其他动态图像。在那种情况下,几乎肯定会是......

CGAffineTransformScale(CGAffineTransformIdentity,1,-1),

照顾核心图形中的颠倒比例。希望它有所帮助。

答案 2 :(得分:0)

感谢您的链接,llama591。

Haisergeant,如果您正在寻找的是使用第一个示例中的纹理的粗线,那么您将需要使用kPatternWidth和kPatternHeight值,以及您在其中传递的值。 line CGContextSetLineWidth(ctx,4.0);。

我还必须修改我用过的纹理图像,以确保它的边缘上有很少的空白,因为这会在线条中引入白色间隙,如示例所示。