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);
}
}
User contributions licensed under CC BY-SA 3.0