iphone:将纹理应用到 CGContextStrokePath
Posted
技术标签:
【中文标题】iphone:将纹理应用到 CGContextStrokePath【英文标题】:iphone: Apply a texture to CGContextStrokePath 【发布时间】:2011-07-09 14:22:53 【问题描述】:我在 *** 中搜索了所有问题和答案,但无法得到我想要的结果。我想使用 PNG 文件,在用户触摸和移动时显示为笔画。这是PNG文件:
但是我在 *** 上做了所有的事情,甚至使用了 CGPatternRef,但我没有得到我想要的结果。我得到的结果在这里:
但我想要的结果在这里:
我已经在 OpenGL ES 中完成了这个结果,但在 Core Graphics 中我无法做到。我想我可以在每个点使用 CGContextDrawImage,但这种方式会导致性能不佳,因为我必须在用户触摸的 2 个点之间绘制所有点的图像。我想你以前遇到过这个问题。你认为我可以在 Core Graphics 中应用纹理来绘制这样的笔划吗?非常感谢。
【问题讨论】:
海军士!你有没有解决过这个问题?花了很长时间才回答:) 【参考方案1】:当您使用图案创建线条时,它将看起来像第一个图像,而不是第二个图像。线条只是您提供的纹理图像的平铺,裁剪成线条的形状。它无法知道您打算将圆圈合并在一起以看起来像一条实线。为此,您可能应该只用纯黑色画一条线。
对于任何试图在第一张图片中实现图案线的人,这里有一个很好的教程来解释如何做到这一点: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;
【讨论】:
我很确定你需要 "CGPatternRelease(strokePattern);"即使您使用的是 ARC。它仅适用于 objetive-c 对象,而不适用于 CoreGraphics 之类的直接 C 代码。 我相信这是“单例”示例代码:这是整个互联网上唯一一个简单的图案绘制示例代码 :) 干得好,恭喜...【参考方案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”。
再次,我将 1 行代码替换为该模式的 15 行代码。 (还有一个单独的微不足道的回调函数。)这是整个事情:
-(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);
在代码中包含几个有用的 cmets!
// 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 中,示例代码显示了参数三的 CGAffineTransformIdentity。
通常,您会使用一些照片或其他动态图像。在那种情况下,几乎可以肯定会是......
CGAffineTransformScale(CGAffineTransformIdentity,1,-1),
处理核心图形中的倒置比例。希望对您有所帮助。
【讨论】:
【参考方案3】:感谢您的链接,llama591。
Haisergeant,如果您正在寻找的是使用第一个示例中的纹理的漂亮粗线,那么您需要使用 kPatternWidth 和 kPatternHeight 值,以及您在行 CGContextSetLineWidth(ctx, 4.0);.
我还必须修改我使用的纹理图像以确保其边缘上的空白非常少,因为这会在线条中引入白色间隙,如您的示例所示。
【讨论】:
以上是关于iphone:将纹理应用到 CGContextStrokePath的主要内容,如果未能解决你的问题,请参考以下文章