0

I am trying to flood fill a UIImage with gradient. I already implemented this for solid colors. I tried to flood fill with UIColor colorWithPatternImage, but it's filling the image with weird colors. Could someone please point me to the right direction. Here's the method I am using for flood fill

    - (UIImage *) floodFillFromPoint:(CGPoint)startPoint withColor:(UIColor *)newColor andTolerance:(int)tolerance
 {

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    CGImageRef imageRef = [self CGImage];

    NSUInteger width = CGImageGetWidth(imageRef);
    NSUInteger height = CGImageGetHeight(imageRef);

    unsigned char *imageData = malloc(height * width * 4);

    NSUInteger bytesPerPixel = CGImageGetBitsPerPixel(imageRef) / 8;
    NSUInteger bytesPerRow = CGImageGetBytesPerRow(imageRef);
    NSUInteger bitsPerComponent = CGImageGetBitsPerComponent(imageRef);

    CGContextRef context = CGBitmapContextCreate(imageData,
                                                 width,
                                                 height,
                                                 bitsPerComponent,
                                                 bytesPerRow,
                                                 colorSpace,
                                                 CGImageGetBitmapInfo(imageRef));
    CGColorSpaceRelease(colorSpace);

    CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);

    //Get color at start point
    unsigned int byteIndex = (bytesPerRow * startPoint.y) + startPoint.x * bytesPerPixel;

    unsigned int ocolor = getColorCode(byteIndex, imageData);

    //Convert newColor to RGBA value so we can save it to image.
    int newRed, newGreen, newBlue, newAlpha;

    const CGFloat *components = CGColorGetComponents(newColor.CGColor);

    /*
        If you are not getting why I use CGColorGetNumberOfComponents than read following link:
        http://stackoverflow.com/questions/9238743/is-there-an-issue-with-cgcolorgetcomponents
    */

    if(CGColorGetNumberOfComponents(newColor.CGColor) == 2)
    {
        newRed   = newGreen = newBlue = components[0] * 255;
        newAlpha = components[1];
    }
    else if (CGColorGetNumberOfComponents(newColor.CGColor) == 4)
    {
        newRed   = components[0] * 255;
        newGreen = components[1] * 255;
        newBlue  = components[2] * 255;
        newAlpha = 255;
    }

    unsigned int ncolor = (newRed << 24) | (newGreen << 16) | (newBlue << 8) | newAlpha;

    /*
        We are using stack to store point.
        Stack is implemented by LinkList.
        To incress speed I have used NSMutableData insted of NSMutableArray.
        To see Detail Of This implementation visit following leink.
        http://iwantmyreal.name/blog/2012/09/29/a-faster-array-in-objective-c/
    */

    LinkedListStack *points = [[LinkedListStack alloc] initWithCapacity:500 incrementSize:500 andMultiplier:height];

    int x = startPoint.x;
    int y = startPoint.y;

    [points pushFrontX:x andY:y];

    /*
        This algorithem is prety simple though it llook odd in Objective C syntex.
        To get familer with this algorithm visit following link.
        http://lodev.org/cgtutor/floodfill.html
        You can read hole artical for knowledge. 
        If you are familer with flood fill than got to Scanline Floodfill Algorithm With Stack (floodFillScanlineStack)
    */

    unsigned int color;
    BOOL spanLeft,spanRight;

    while ([points popFront:&x andY:&y] != INVALID_NODE_CONTENT)
    {


       /* if (spanRight) {
            newRed = newRed-1;
            newBlue  = newBlue+1;
        }

        if (spanLeft) {
            newBlue = newBlue-1;
            newRed  = newRed+1;
        }*/

        byteIndex = (bytesPerRow * y) + x * bytesPerPixel;

        color = getColorCode(byteIndex, imageData);

        while(y >= 0 && compareColor(ocolor, color, tolerance))
        {
            y--;

            if(y >= 0)
            {
                byteIndex = (bytesPerRow * y) + x * bytesPerPixel;

                color = getColorCode(byteIndex, imageData);
            }
        }

        y++;

        spanLeft = spanRight = NO;

        byteIndex = (bytesPerRow * y) + x * bytesPerPixel;

        color = getColorCode(byteIndex, imageData);

        while (y < height && compareColor(ocolor, color, tolerance) )
        {
           // NSLog(@"compareColor");
            //Change old color with newColor RGBA value
          /*  if (compareColor(ncolor, color, tolerance)) {
                newRed = 255;
                newGreen = 255;
                newBlue = 255;
                newAlpha = 0;
            }*/

            imageData[byteIndex + 0] = newRed;
            imageData[byteIndex + 1] = newGreen;
            imageData[byteIndex + 2] = newBlue;
            imageData[byteIndex + 3] = newAlpha;

            if(x > 0)
            {
                byteIndex = (bytesPerRow * y) + (x - 1) * bytesPerPixel;

                color = getColorCode(byteIndex, imageData);

                if(!spanLeft && x > 0 && compareColor(ocolor, color, tolerance))
                {
                    [points pushFrontX:(x - 1) andY:y];

                    spanLeft = YES;
                }
                else if(spanLeft && x > 0 && !compareColor(ocolor, color, tolerance))
                {
                    spanLeft = NO;
                }
            }

            if(x < width - 1)
            {
                byteIndex = (bytesPerRow * y) + (x + 1) * bytesPerPixel;

                color = getColorCode(byteIndex, imageData);

                if(!spanRight && compareColor(ocolor, color, tolerance))
                {
                    [points pushFrontX:(x + 1) andY:y];

                    spanRight = YES;
                }
                else if(spanRight && !compareColor(ocolor, color, tolerance))
                {
                    spanRight = NO;
                }
            }

            y++;

            if(y < height)
            {
                byteIndex = (bytesPerRow * y) + x * bytesPerPixel;

                color = getColorCode(byteIndex, imageData);
            }
        }
    }

    //Convert Flood filled image row data back to UIImage object.

    CGImageRef newCGImage = CGBitmapContextCreateImage(context);

    UIImage *result = [UIImage imageWithCGImage:newCGImage];

    CGImageRelease(newCGImage);

    CGContextRelease(context);

    free(imageData);

    return result;
}
@catch (NSException *exception)
{
    NSLog(@"Exception : %@", exception);
}

}

This is what I am using for flood fill with gradient

filledImage = [_imageView.image floodFillFromPoint:CGPointMake((touchPoint.x*ScaleFactor)/_zoomScrollview.zoomScale,( touchPoint.y*ScaleFactor)/_zoomScrollview.zoomScale) withColor:[UIColor colorWithPatternImage:[UIImage imageNamed:@"color-book.png"]] andTolerance:5.0 ];

Here is the gradient image I am using:

Here is the gradient image i am using

But showing weird colors like this

Gradient Applied Image

I am working on a coloring book app.so it should look like as it would look on any coloring book app after applying gradient. Can anyone tell me where the problem lies or what can I do to resolve it?

clemens
  • 16,716
  • 11
  • 50
  • 65
  • Plese edit the question with what it should look like and what it actually does look like "filling the image with weird colors". – shallowThought Nov 20 '16 at 11:36
  • I have edited the question, have a look @shallowThought – Asif_partho Nov 20 '16 at 11:59
  • 1
    A gradient is _not_ a pattern so the whole idea is nutty. The usual thing is to make the gradient in a normal rectangular layer and put your shape in front of it as a _mask_. – matt Nov 21 '16 at 03:14
  • But how can i get layer from a uiimage, the only way to retrieve layer from image is to use svg image but it has some performance issues so what should i do ? @matt – Asif_partho Nov 21 '16 at 03:36
  • For how to fill an arbitrary shape with a gradient, see for example my answer here http://stackoverflow.com/a/23202718/341994 – matt Nov 21 '16 at 03:39
  • But i dont have any fixed points to create UIbeizierpath , so it won't come to any good – Asif_partho Nov 21 '16 at 06:03
  • I finally implemented the solution – Asif_partho Dec 05 '16 at 06:02
  • @Asif_partho how did you solve this because I'm facing same problem. Could you please share solution? it would be big help. – dmaulikr Jul 28 '17 at 04:24
  • @Asif_partho: Can you tell me, how you solved that bug ? Because I just encountered same problem and I am not able to solve it. Thanks – Nirav Nov 16 '18 at 10:30
  • you should provide feedback after you find a solution – Erdi İzgi Oct 31 '19 at 08:44
  • @Asif_partho I am also facing the same issues, but. it is with pattern image not with gradient color, can you please share your answer here – Paresh Patel Jan 30 '20 at 05:36

0 Answers0