10

I have already implemented paint / draw using:

- (void) touchesBegan: (NSSet *) touches withEvent: (UIEvent *) event
-(void) touchesMoved: (NSSet *) touches withEvent: (UIEvent *) event
- (void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event

Now issue is that for any line drawn, I want to get that particular line / paint image. I don't want image of entire screen, only area / bounds of line / paint drawn.

Reason is that I want to perform pan gesture / delete functionality on that line / paint drawn.

User can draw multiple lines, so want UIImage for all this lines separately.

Any logic or code snippet will be really helpful

Thanks in advance

P.J
  • 6,547
  • 9
  • 44
  • 74

2 Answers2

1

Depending on your application, particularly how many times you plan on doing this in a row, you may be able to create a different image/layer for each paint line. Your final image would essentially be all the individual lines drawn on top of each other.

It may be more efficient to create a custom view to capture touch events. You could store the list of touch coordinates for each paint line and render them all at once in a custom drawRect. This way you are storing lists of coordinates for each paint line, and can still access each one, instead of a list of images. You could calculate the area/bounds from the coordinates used to render the line.

Additional context and code may be helpful, I'm not sure I completely understand what you're trying to accomplish!

bradkratky
  • 1,577
  • 1
  • 14
  • 28
  • It would be helpful if you posted your paint/draw methods so myself or others may be able to accomplish that more easily. – bradkratky Jul 04 '16 at 18:59
1

I take a look at the MVPaint project. It seems you have an object:

MVPaintDrawing _drawing;

which contains an array of MVPaintTransaction. You can iterate on those MVPaintTransaction to draw an UIImage.

So first you can add a method to get an image from a MVPaintTransaction:

- (UIImage *) imageToDrawWithSize:(CGSize) size xScale:(CGFloat)xScale yScale:(CGFloat)yScale {

    UIGraphicsBeginImageContext(size);
    CGContextScaleCTM(UIGraphicsGetCurrentContext(), xScale, yScale);

    // call the existing draw method    
    [self draw];

    UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return result;
}

Then add a method to get an array of image from the array of MVPaintTransaction in the MVPaintDrawing class:

- (NSArray *) getImagesFromDrawingOnSurface: (UIImageView *) surface xScale: (CGFloat) xScale yScale: (CGFloat) yScale{

    NSMutableArray *imageArray = [NSMutableArray new];
    for (MVPaintTransaction * transaction in _drawing) {
        UIImage *image = [transaction imageToDrawWithSize:surface.frame.size xScale:xScale yScale:yScale];
        [imageArray addObject:image];
    }

    return imageArray;
}

In this way you will have an array of UIImage corresponding to each line you have drawn. If you want those images to have the "minimum" possible size (i mean without extra alpha part), you can apply this method (I added it in the MVPaintTransaction class):

- (UIImage *)trimmedImage:(UIImage *)img {

    CGImageRef inImage = img.CGImage;
    CFDataRef m_DataRef;
    m_DataRef = CGDataProviderCopyData(CGImageGetDataProvider(inImage));

    UInt8 * m_PixelBuf = (UInt8 *) CFDataGetBytePtr(m_DataRef);

    size_t width = CGImageGetWidth(inImage);
    size_t height = CGImageGetHeight(inImage);

    CGPoint top,left,right,bottom;

    BOOL breakOut = NO;
    for (int x = 0;breakOut==NO && x < width; x++) {
        for (int y = 0; y < height; y++) {
            int loc = x + (y * width);
            loc *= 4;
            if (m_PixelBuf[loc + 3] != 0) {
                left = CGPointMake(x, y);
                breakOut = YES;
                break;
            }
        }
    }

    breakOut = NO;
    for (int y = 0;breakOut==NO && y < height; y++) {

        for (int x = 0; x < width; x++) {

            int loc = x + (y * width);
            loc *= 4;
            if (m_PixelBuf[loc + 3] != 0) {
                top = CGPointMake(x, y);
                breakOut = YES;
                break;
            }

        }
    }

    breakOut = NO;
    for (int y = height-1;breakOut==NO && y >= 0; y--) {

        for (int x = width-1; x >= 0; x--) {

            int loc = x + (y * width);
            loc *= 4;
            if (m_PixelBuf[loc + 3] != 0) {
                bottom = CGPointMake(x, y);
                breakOut = YES;
                break;
            }

        }
    }

    breakOut = NO;
    for (int x = width-1;breakOut==NO && x >= 0; x--) {

        for (int y = height-1; y >= 0; y--) {

            int loc = x + (y * width);
            loc *= 4;
            if (m_PixelBuf[loc + 3] != 0) {
                right = CGPointMake(x, y);
                breakOut = YES;
                break;
            }

        }
    }


    CGFloat scale = img.scale;

    CGRect cropRect = CGRectMake(left.x / scale, top.y/scale, (right.x - left.x)/scale, (bottom.y - top.y) / scale);
    UIGraphicsBeginImageContextWithOptions( cropRect.size,
                                           NO,
                                           scale);
    [img drawAtPoint:CGPointMake(-cropRect.origin.x, -cropRect.origin.y)
            blendMode:kCGBlendModeCopy
                alpha:1.];
    UIImage *croppedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    CFRelease(m_DataRef);
    return croppedImage;
}

Then simply replace in the first method:

return result;

by

return [self trimmedImage:result];
Community
  • 1
  • 1
Y.Bonafons
  • 2,329
  • 13
  • 20
  • Well I tried it too before posting and if I call getImagesFromDrawingOnSurface, I get an array of UIImage (each image represent a drawn line which is what you ask for). My code doesnt change the way lines are displayed (to do this you may need to create array of UIImageView for example). – Y.Bonafons Jul 08 '16 at 12:29