I wrote a recursive flood fill method in objective c that I am currently using in an iPad app.
I get the color of the point the user touches in a UIImage via RGBA raw data for the image.
The problem is that it runs for a while then the app crashes with a EXC_BAD_ACCESS while accessing the raw data. My question is why, is this a “stack overflow”? and would anyone be able to suggest a way to fix this / improve upon this approach.
Here is my method (It could be cleaner, I apologize).
-(unsigned char *)floodFill:(unsigned char *)data withImageRef:(CGImageRef)imgRef withColor:(UIColor *)color whereColor:(UIColor *)pixelColor atX:(int)xx andY:(int)yy
{
//create points for top bottom left and right pixel
CGPoint top = CGPointMake(xx, yy-1);
CGPoint bottom = CGPointMake(xx, yy+1);
CGPoint left = CGPointMake(xx-1, yy);
CGPoint right = CGPointMake(xx+1, yy);
//convert new color to rgba values
const CGFloat *rgb = CGColorGetComponents(color.CGColor);
float newRed = rgb[0];
float newGreen = rgb[1];
float newBlue = rgb[2];
float newAlpha = CGColorGetAlpha(color.CGColor);
//convert old color to rgba values
const CGFloat *rgb2 = CGColorGetComponents(pixelColor.CGColor);
float oldRed = rgb2[0];
float oldGreen = rgb2[1];
float oldBlue = rgb2[2];
float oldAlpha = CGColorGetAlpha(pixelColor.CGColor);
NSUInteger width = CGImageGetWidth(imgRef);
NSUInteger bytesPerPixel = 4;
NSUInteger bytesPerRow = bytesPerPixel * width;
int byteIndex = (bytesPerRow * yy) + xx * bytesPerPixel;
//color current pixel
data[byteIndex] = (char)newRed*255;
data[byteIndex+1] = (char)newGreen*255;
data[byteIndex+2] = (char)newBlue*255;
data[byteIndex+3] = (char)newAlpha*255;
CGFloat red, green, blue, alpha;
CGPoint currentPoint;
//check top pixel
currentPoint=top;
if(currentPoint.x>=0 && currentPoint.y>=0)
{
byteIndex = (bytesPerRow * currentPoint.y) + currentPoint.x * bytesPerPixel;
red = (data[byteIndex] * 1.0) / 255.0;
green = (data[byteIndex + 1] * 1.0) / 255.0;
blue = (data[byteIndex + 2] * 1.0) / 255.0;
alpha = (data[byteIndex + 3] * 1.0) / 255.0;
if(red==oldRed&&green==oldGreen&&blue==oldBlue&&alpha==oldAlpha)
data=[self floodFill:data withImageRef:imgRef withColor:color whereColor:pixelColor atX:currentPoint.x andY:currentPoint.y];
}
//check bottom pixel
currentPoint=bottom;
if(currentPoint.x>=0 && currentPoint.y>=0)
{
byteIndex = (bytesPerRow * currentPoint.y) + currentPoint.x * bytesPerPixel;
red = (data[byteIndex] * 1.0) / 255.0;
green = (data[byteIndex + 1] * 1.0) / 255.0;
blue = (data[byteIndex + 2] * 1.0) / 255.0;
alpha = (data[byteIndex + 3] * 1.0) / 255.0;
if(red==oldRed&&green==oldGreen&&blue==oldBlue&&alpha==oldAlpha)
data=[self floodFill:data withImageRef:imgRef withColor:color whereColor:pixelColor atX:currentPoint.x andY:currentPoint.y];
}
//check left pixel
currentPoint=left;
if(currentPoint.x>=0 && currentPoint.y>=0)
{
byteIndex = (bytesPerRow * currentPoint.y) + currentPoint.x * bytesPerPixel;
red = (data[byteIndex] * 1.0) / 255.0;
green = (data[byteIndex + 1] * 1.0) / 255.0;
blue = (data[byteIndex + 2] * 1.0) / 255.0;
alpha = (data[byteIndex + 3] * 1.0) / 255.0;
if(red==oldRed&&green==oldGreen&&blue==oldBlue&&alpha==oldAlpha)
data=[self floodFill:data withImageRef:imgRef withColor:color whereColor:pixelColor atX:currentPoint.x andY:currentPoint.y];
}
//check right pixel
currentPoint=right;
if(currentPoint.x>=0 && currentPoint.y>=0)
{
byteIndex = (bytesPerRow * currentPoint.y) + currentPoint.x * bytesPerPixel;
red = (data[byteIndex] * 1.0) / 255.0;
green = (data[byteIndex + 1] * 1.0) / 255.0;
blue = (data[byteIndex + 2] * 1.0) / 255.0;
alpha = (data[byteIndex + 3] * 1.0) / 255.0;
if(red==oldRed&&green==oldGreen&&blue==oldBlue&&alpha==oldAlpha)
data=[self floodFill:data withImageRef:imgRef withColor:color whereColor:pixelColor atX:currentPoint.x andY:currentPoint.y];
}
return data;
}
Thanks -TJ
Recursive methods are major cause of stack overflow exceptions because every recursive call is pushed onto stack until it reaches end condition, especially in flood fill algorithm this approach is not suitable at all, ipad has limited resources as compared to modern computers, consider using loop based implementation of flood fill algorithm or scan-line algorithm
for more information visit this link Flood Fill algorithms