Ale*_*one 8 iphone curve objective-c area ios
我有一条任意形状的曲线,包围着一些区域.我想估计曲线在iPhone/iPad屏幕上的像素数.我怎么能这样做?

我想用某种方式用颜色填充闭合曲线,然后在屏幕截图中计算这种颜色的像素数.这意味着我需要知道如何以编程方式用颜色填充闭合曲线.
还有其他一些我没想过的方法吗?
谢谢!
让我们通过创建一个包围曲线的Quartz路径来实现这一点.然后我们将创建一个位图上下文并填充该上下文中的路径.然后我们可以检查位图并计算填充的像素.我们将这一切都包含在一个方便的功能中:
static double areaOfCurveWithPoints(const CGPoint *points, size_t count) {
Run Code Online (Sandbox Code Playgroud)
首先,我们需要创建路径:
CGPathRef path = createClosedPathWithPoints(points, count);
Run Code Online (Sandbox Code Playgroud)
然后我们需要得到路径的边界框. CGPoint坐标不必是整数,但位图必须具有整数尺寸,因此我们将得到一个至少与路径边界框一样大的整数边界框:
CGRect frame = integralFrameForPath(path);
Run Code Online (Sandbox Code Playgroud)
我们还需要确定制作位图的宽度(以字节为单位):
size_t bytesPerRow = bytesPerRowForWidth(frame.size.width);
Run Code Online (Sandbox Code Playgroud)
现在我们可以创建位图:
CGContextRef gc = createBitmapContextWithFrame(frame, bytesPerRow);
Run Code Online (Sandbox Code Playgroud)
位图在创建时用黑色填充.我们将填充白色的道路:
CGContextSetFillColorWithColor(gc, [UIColor whiteColor].CGColor);
CGContextAddPath(gc, path);
CGContextFillPath(gc);
Run Code Online (Sandbox Code Playgroud)
现在我们已经完成了路径,所以我们可以释放它:
CGPathRelease(path);
Run Code Online (Sandbox Code Playgroud)
接下来我们将计算填充的区域:
double area = areaFilledInBitmapContext(gc);
Run Code Online (Sandbox Code Playgroud)
现在我们已经完成了位图上下文,所以我们可以发布它:
CGContextRelease(gc);
Run Code Online (Sandbox Code Playgroud)
最后,我们可以返回我们计算的区域:
return area;
}
Run Code Online (Sandbox Code Playgroud)
嗯,这很容易!但我们必须编写所有这些辅助函数.让我们从顶部开始吧.创建路径是微不足道的:
static CGPathRef createClosedPathWithPoints(const CGPoint *points, size_t count) {
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddLines(path, NULL, points, count);
CGPathCloseSubpath(path);
return path;
}
Run Code Online (Sandbox Code Playgroud)
获取路径的整数边界框也很简单:
static CGRect integralFrameForPath(CGPathRef path) {
CGRect frame = CGPathGetBoundingBox(path);
return CGRectIntegral(frame);
}
Run Code Online (Sandbox Code Playgroud)
要选择位图的每行字节数,我们可以使用路径边界框的宽度.但我认为Quartz喜欢将位图设置为两倍的强大倍数.我没有对此做过任何测试,所以你可能想要试验一下.现在,我们将宽度四舍五入为64的下一个最小倍数:
static size_t bytesPerRowForWidth(CGFloat width) {
static const size_t kFactor = 64;
// Round up to a multiple of kFactor, which must be a power of 2.
return ((size_t)width + (kFactor - 1)) & ~(kFactor - 1);
}
Run Code Online (Sandbox Code Playgroud)
我们使用计算的大小创建位图上下文.我们还需要翻译坐标系的原点.为什么?因为路径边界框的原点可能不在(0,0).
static CGContextRef createBitmapContextWithFrame(CGRect frame, size_t bytesPerRow) {
CGColorSpaceRef grayscale = CGColorSpaceCreateDeviceGray();
CGContextRef gc = CGBitmapContextCreate(NULL, frame.size.width, frame.size.height, 8, bytesPerRow, grayscale, kCGImageAlphaNone);
CGColorSpaceRelease(grayscale);
CGContextTranslateCTM(gc, -frame.origin.x, -frame.origin.x);
return gc;
}
Run Code Online (Sandbox Code Playgroud)
最后,我们需要编写实际计算填充像素的辅助对象.我们必须决定我们想要计算像素的方式.每个像素由一个无符号的8位整数表示.黑色像素为0.白色像素为255.中间的数字为灰色阴影.当使用灰色像素填充它时,Quartz会对路径边缘进行反锯齿处理.所以我们必须决定如何计算这些灰色像素.
一种方法是定义阈值,如128.任何等于或高于阈值的像素都计为填充; 其余的数量为未填充.
另一种方法是将灰色像素计数为部分填充,并将该部分填充加起来.因此,两个完全半填充的像素被组合并计为单个完全填充的像素.我们这样做:
static double areaFilledInBitmapContext(gc) {
size_t width = CGBitmapContextGetWidth(gc);
size_t height = CGBitmapContextGetHeight(gc);
size_t stride = CGBitmapContextGetBytesPerRow(gc);
uint8_t *pixels = CGBitmapContextGetData(gc);
uint64_t coverage = 0;
for (size_t y = 0; y < height; ++y) {
for (size_t x = 0; x < width; ++x) {
coverage += pixels[y * stride + x];
}
}
return (double)coverage / UINT8_MAX;
}
Run Code Online (Sandbox Code Playgroud)
你可以找到这个要点中捆绑的所有代码.
| 归档时间: |
|
| 查看次数: |
3063 次 |
| 最近记录: |