0

I have a UIView where the user can draw various UIBezierPaths.

I need to analyze the drawn BezierPaths to process certain patterns. I have not found any solution to converting UIBezierPaths to a list of coordinates/points, it seems like this is undoable? It's strange as this data must be stored and used someway to draw the actual paths..

So to bypass this problem i decided to draw the BezierPath with a width of 1px:

[path setLineWidth:1];

And convert my UIView to an UIImage:

UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0.0);
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();

Then i can identify pixels by getting the color for a certain pixel position at the image:

- (UIColor *)colorAtPixel:(CGPoint)point {
    CGImageRef imageRef = [self CGImage];
    NSUInteger width = CGImageGetWidth(imageRef);
    NSUInteger height = CGImageGetHeight(imageRef);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    int bytesPerPixel = 4;
    long bytesPerRow = bytesPerPixel * width;
    int bitsPerComponent = 8;

    unsigned char *rawData = (unsigned char*) calloc(height * width * 4, sizeof(unsigned char));

    CGContextRef context = CGBitmapContextCreate(rawData,
                                                 width,
                                                 height,
                                                 bitsPerComponent,
                                                 bytesPerRow,
                                                 colorSpace,
                                                 kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

    CGColorSpaceRelease(colorSpace);
    CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
    CGContextRelease(context);

    // Now your rawData contains the image data in the RGBA8888 pixel format.
    long byteIndex = (bytesPerRow * point.y) + point.x * bytesPerPixel;
    CGFloat red   = (rawData[byteIndex] * 1.0) / 255.0;
    CGFloat green = (rawData[byteIndex + 1] * 1.0) / 255.0 ;
    CGFloat blue  = (rawData[byteIndex + 2] * 1.0) / 255.0 ;
    CGFloat alpha = (rawData[byteIndex + 3] * 1.0) / 255.0;

    byteIndex += 4;
    UIColor *color = [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
    free(rawData);

    return color;
}

Now my issue is that the image generated is blurry, if a draw a straight 1px BezierPath line and convert this to an UIImage, the line has a width of 3x because of it becomming blurry.

How can i solve this? Is there actually no possible way to convert BezierPaths to a list of coordinates?

Lord Vermillion
  • 5,264
  • 20
  • 69
  • 109
  • possible duplicate of [Getting a list of points from a UIBezierPath](http://stackoverflow.com/questions/3051760/getting-a-list-of-points-from-a-uibezierpath) – Mike 'Pomax' Kamermans May 08 '15 at 17:26

2 Answers2

1

This is due to Anti Alias rendering.

See this question on SO for information on how to turn this of.

I believe that you are better of rendering the beziercurve yourself. It will be faster with a very small memory footprint.

Community
  • 1
  • 1
pizzamonster
  • 1,141
  • 10
  • 9
  • Thanks, i'm not sure how to use [data writeToFile:[self screenShotFilename] atomically:YES];. What file is this refering to? – Lord Vermillion May 08 '15 at 12:44
  • That line writes the screenshot to disk. The part I was referring to was to prevent the anti alias rendering your question was about, CGContextSetShouldAntialias(context, NO); -- see the answer from Rufel below as a better alternative to find the points rendered. – pizzamonster May 08 '15 at 18:19
0

You may take a look at this answer from Moritz about using CGPathApply and CGPathApplierFunction.

For each element in the specified path, Quartz calls the applier function, which can examine (but not modify) the element.

That could give you access to the points stored in a UIBezierPath.

Community
  • 1
  • 1
Rufel
  • 2,630
  • 17
  • 15