Scanline flood fill replace with another image

-1

I have this example https://github.com/Chintan-Dave/UIImageScanlineFloodfill and read this post. But not getting result!!

I have one image. In this image when we touch any portion of that image fill that portion with another image instead of colour.

so if anybody have any idea or example than please help me.

I tried using

imageView.newcolor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"d.png"]];

but image fill with black color.

In this portion we have to change to image

- (UIImage *) floodFillFromPoint:(CGPoint)startPoint withColor:(UIColor *)newColor andTolerance:(NSInteger)tolerance useAntiAlias:(BOOL)antiAlias
{

    NSLog(@"%f",startPoint.x);
     NSLog(@"%f",startPoint.y);
    @try
    {
        /*
            First We create rowData from UIImage.
            We require this conversation so that we can use detail at pixel like color at pixel.
            You can get some discussion about this topic here:
            http://stackoverflow.com/questions/448125/how-to-get-pixel-data-from-a-uiimage-cocoa-touch-or-cgimage-core-graphics
        */

        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

        CGImageRef imageRef = [self CGImage];

        NSUInteger width = CGImageGetWidth(imageRef);
        NSUInteger height = CGImageGetHeight(imageRef);
        NSLog(@"%lu",(unsigned long)width);
        NSUInteger bytesPerPixel = CGImageGetBitsPerPixel(imageRef) / 8;
        NSUInteger bytesPerRow = CGImageGetBytesPerRow(imageRef);
        NSUInteger bitsPerComponent = CGImageGetBitsPerComponent(imageRef);

        unsigned char *imageData = malloc(height * width * bytesPerPixel);
     //   NSLog(@"%@",imageData)

        CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);

        if (kCGImageAlphaLast == (uint32_t)bitmapInfo ||
            kCGImageAlphaFirst == (uint32_t)bitmapInfo)
        {
            bitmapInfo = (uint32_t)kCGImageAlphaPremultipliedLast;
        }

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

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

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

        NSUInteger ocolor = getColorCode(byteIndex, imageData);

        if (compareColor(ocolor, 0, 0))
        {
            return nil;
        }

        //Convert newColor to RGBA value so we can save it to image.
        NSInteger 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] * 255;
        }
        else if (CGColorGetNumberOfComponents(newColor.CGColor) == 4)
        {
            if ((bitmapInfo&kCGBitmapByteOrderMask) == kCGBitmapByteOrder32Little)
            {
                newRed   = components[2] * 255;
                newGreen = components[1] * 255;
                newBlue  = components[0] * 255;
                newAlpha = 255;
            }
            else
            {
                newRed   = components[0] * 255;
                newGreen = components[1] * 255;
                newBlue  = components[2] * 255;
                newAlpha = 255;
            }
        }

        NSUInteger 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];
        LinkedListStack *antiAliasingPoints = [[LinkedListStack alloc] initWithCapacity:500 incrementSize:500 andMultiplier:height];

        NSInteger x = roundf(startPoint.x);
        NSInteger y = roundf(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)
        */

        NSUInteger color;
        BOOL spanLeft,spanRight;

        while ([points popFront:&x andY:&y] != INVALID_NODE_CONTENT)
        {
            byteIndex = (bytesPerRow * roundf(y)) + roundf(x) * bytesPerPixel;

            color = getColorCode(byteIndex, imageData);

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

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

                    color = getColorCode(byteIndex, imageData);
                }
            }

            // Add the top most point on the antialiasing list
            if(y >= 0 && !compareColor(ocolor, color, 0))
            {
                [antiAliasingPoints pushFrontX:x andY:y];
            }

            y++;

            spanLeft = spanRight = NO;

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

            color = getColorCode(byteIndex, imageData);

            while (y < height && compareColor(ocolor, color, tolerance) && ncolor != color)
            {
                //Change old color with newColor RGBA value
                imageData[byteIndex + 0] = newRed;
                imageData[byteIndex + 1] = newGreen;
                imageData[byteIndex + 2] = newBlue;
                imageData[byteIndex + 3] = newAlpha;

                if(x > 0)
                {
                    byteIndex = (bytesPerRow * roundf(y)) + roundf(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;
                    }

                    // we can't go left. Add the point on the antialiasing list
                    if(!spanLeft && x > 0 && !compareColor(ocolor, color, tolerance) && !compareColor(ncolor, color, tolerance))
                    {
                        [antiAliasingPoints pushFrontX:(x - 1) andY:y];
                    }
                }

                if(x < width - 1)
                {
                    byteIndex = (bytesPerRow * roundf(y)) + roundf(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;
                    }

                    // we can't go right. Add the point on the antialiasing list
                    if(!spanRight && !compareColor(ocolor, color, tolerance) && !compareColor(ncolor, color, tolerance))
                    {
                        [antiAliasingPoints pushFrontX:(x + 1) andY:y];
                    }
                }

                y++;

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

                    color = getColorCode(byteIndex, imageData);
                }
            }

            if (y<height)
            {
                byteIndex = (bytesPerRow * roundf(y)) + roundf(x) * bytesPerPixel;
                color = getColorCode(byteIndex, imageData);

                // Add the bottom point on the antialiasing list
                if (!compareColor(ocolor, color, 0))
                    [antiAliasingPoints pushFrontX:x andY:y];
            }
        }

        // For each point marked
        // perform antialiasing on the same pixel, plus the top,left,bottom and right pixel
        NSUInteger antialiasColor = getColorCodeFromUIColor(newColor,bitmapInfo&kCGBitmapByteOrderMask );
        NSInteger red1   = ((0xff000000 & antialiasColor) >> 24);
        NSInteger green1 = ((0x00ff0000 & antialiasColor) >> 16);
        NSInteger blue1  = ((0x0000ff00 & antialiasColor) >> 8);
        NSInteger alpha1 =  (0x000000ff & antialiasColor);

        while ([antiAliasingPoints popFront:&x andY:&y] != INVALID_NODE_CONTENT)
        {
            byteIndex = (bytesPerRow * roundf(y)) + roundf(x) * bytesPerPixel;
            color = getColorCode(byteIndex, imageData);

            if (!compareColor(ncolor, color, 0))
            {
                NSInteger red2   = ((0xff000000 & color) >> 24);
                NSInteger green2 = ((0x00ff0000 & color) >> 16);
                NSInteger blue2 = ((0x0000ff00 & color) >> 8);
                NSInteger alpha2 =  (0x000000ff & color);

                if (antiAlias)
                {
                    imageData[byteIndex + 0] = (red1 + red2) / 2;
                    imageData[byteIndex + 1] = (green1 + green2) / 2;
                    imageData[byteIndex + 2] = (blue1 + blue2) / 2;
                    imageData[byteIndex + 3] = (alpha1 + alpha2) / 2;
                }
                else
                {
                    imageData[byteIndex + 0] = red2;
                    imageData[byteIndex + 1] = green2;
                    imageData[byteIndex + 2] = blue2;
                    imageData[byteIndex + 3] = alpha2;
                }

#if DEBUG_ANTIALIASING
                imageData[byteIndex + 0] = 0;
                imageData[byteIndex + 1] = 0;
                imageData[byteIndex + 2] = 255;
                imageData[byteIndex + 3] = 255;
#endif
            }

            // left
            if (x>0)
            {
                byteIndex = (bytesPerRow * roundf(y)) + roundf(x - 1) * bytesPerPixel;
                color = getColorCode(byteIndex, imageData);

                if (!compareColor(ncolor, color, 0))
                {
                    NSInteger red2   = ((0xff000000 & color) >> 24);
                    NSInteger green2 = ((0x00ff0000 & color) >> 16);
                    NSInteger blue2 = ((0x0000ff00 & color) >> 8);
                    NSInteger alpha2 =  (0x000000ff & color);

                    if (antiAlias) {
                        imageData[byteIndex + 0] = (red1 + red2) / 2;
                        imageData[byteIndex + 1] = (green1 + green2) / 2;
                        imageData[byteIndex + 2] = (blue1 + blue2) / 2;
                        imageData[byteIndex + 3] = (alpha1 + alpha2) / 2;
                    } else {
                        imageData[byteIndex + 0] = red2;
                        imageData[byteIndex + 1] = green2;
                        imageData[byteIndex + 2] = blue2;
                        imageData[byteIndex + 3] = alpha2;
                    }

#if DEBUG_ANTIALIASING
                    imageData[byteIndex + 0] = 0;
                    imageData[byteIndex + 1] = 0;
                    imageData[byteIndex + 2] = 255;
                    imageData[byteIndex + 3] = 255;
#endif
                }
            }

            if (x<width)
            {
                byteIndex = (bytesPerRow * roundf(y)) + MIN(width,roundf(x + 1)) * bytesPerPixel;
                color = getColorCode(byteIndex, imageData);

                if (!compareColor(ncolor, color, 0))
                {
                    NSInteger red2   = ((0xff000000 & color) >> 24);
                    NSInteger green2 = ((0x00ff0000 & color) >> 16);
                    NSInteger blue2 = ((0x0000ff00 & color) >> 8);
                    NSInteger alpha2 =  (0x000000ff & color);

                    if (antiAlias)
                    {
                        imageData[byteIndex + 0] = (red1 + red2) / 2;
                        imageData[byteIndex + 1] = (green1 + green2) / 2;
                        imageData[byteIndex + 2] = (blue1 + blue2) / 2;
                        imageData[byteIndex + 3] = (alpha1 + alpha2) / 2;
                    }
                    else
                    {
                        imageData[byteIndex + 0] = red2;
                        imageData[byteIndex + 1] = green2;
                        imageData[byteIndex + 2] = blue2;
                        imageData[byteIndex + 3] = alpha2;
                    }

#if DEBUG_ANTIALIASING
                    imageData[byteIndex + 0] = 0;
                    imageData[byteIndex + 1] = 0;
                    imageData[byteIndex + 2] = 255;
                    imageData[byteIndex + 3] = 255;
#endif
                }
            }

            if (y>0)
            {
                byteIndex = (bytesPerRow * roundf(y - 1)) + roundf(x) * bytesPerPixel;
                color = getColorCode(byteIndex, imageData);

                if (!compareColor(ncolor, color, 0))
                {
                    NSInteger red2   = ((0xff000000 & color) >> 24);
                    NSInteger green2 = ((0x00ff0000 & color) >> 16);
                    NSInteger blue2 = ((0x0000ff00 & color) >> 8);
                    NSInteger alpha2 =  (0x000000ff & color);

                    if (antiAlias)
                    {
                        imageData[byteIndex + 0] = (red1 + red2) / 2;
                        imageData[byteIndex + 1] = (green1 + green2) / 2;
                        imageData[byteIndex + 2] = (blue1 + blue2) / 2;
                        imageData[byteIndex + 3] = (alpha1 + alpha2) / 2;
                    }
                    else
                    {
                        imageData[byteIndex + 0] = red2;
                        imageData[byteIndex + 1] = green2;
                        imageData[byteIndex + 2] = blue2;
                        imageData[byteIndex + 3] = alpha2;
                    }

#if DEBUG_ANTIALIASING
                    imageData[byteIndex + 0] = 0;
                    imageData[byteIndex + 1] = 0;
                    imageData[byteIndex + 2] = 255;
                    imageData[byteIndex + 3] = 255;
#endif
                }
            }

            if (y<height)
            {
                byteIndex = (bytesPerRow * MIN(height,roundf(y + 1))) + roundf(x) * bytesPerPixel;
                color = getColorCode(byteIndex, imageData);

                if (!compareColor(ncolor, color, 0))
                {
                    NSInteger red2   = ((0xff000000 & color) >> 24);
                    NSInteger green2 = ((0x00ff0000 & color) >> 16);
                    NSInteger blue2 = ((0x0000ff00 & color) >> 8);
                    NSInteger alpha2 =  (0x000000ff & color);

                    if (antiAlias)
                    {
                        imageData[byteIndex + 0] = (red1 + red2) / 2;
                        imageData[byteIndex + 1] = (green1 + green2) / 2;
                        imageData[byteIndex + 2] = (blue1 + blue2) / 2;
                        imageData[byteIndex + 3] = (alpha1 + alpha2) / 2;
                    }
                    else
                    {
                        imageData[byteIndex + 0] = red2;
                        imageData[byteIndex + 1] = green2;
                        imageData[byteIndex + 2] = blue2;
                        imageData[byteIndex + 3] = alpha2;
                    }

#if DEBUG_ANTIALIASING
                    imageData[byteIndex + 0] = 0;
                    imageData[byteIndex + 1] = 0;
                    imageData[byteIndex + 2] = 255;
                    imageData[byteIndex + 3] = 255;
#endif
                }

            }
        }

        //Convert Flood filled image row data back to UIImage object.
        UIImage *img = [UIImage imageNamed:@"d.png"];
        CGImageRef newCGImage = CGBitmapContextCreateImage(context);

        UIImage *result = [UIImage imageWithCGImage:newCGImage scale:[self scale] orientation:UIImageOrientationUp];

        CGImageRelease(newCGImage);

        CGContextRelease(context);

        free(imageData);

        return result;
    }
    @catch (NSException *exception)
    {
        NSLog(@"Exception : %@", exception);
    }
}
ios
objective-c
swift
asked on Stack Overflow Oct 12, 2019 by user3651677

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0