我真正想要的是在封闭的轮廓中填充渐变。我到达了可以使用泛洪填充算法在轮廓中填充纯色的点。但我怎么能填充渐变。我是否必须尝试另一种完全不同的方法。如果是,那么我的其他选择是什么?
我在UIImage类别中使用以下代码
其中" startPoint"是用户触及UIImageView
的CGPoint- (UIImage *) floodFillFromPoint:(CGPoint)startPoint withColor:(UIColor *)newColor andTolerance:(int)tolerance useAntiAlias:(BOOL)antiAlias
{
@try
{
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);
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
unsigned int byteIndex = (bytesPerRow * roundf(startPoint.y)) + roundf(startPoint.x) * bytesPerPixel;
unsigned int ocolor = getColorCode(byteIndex, imageData);
if (compareColor(ocolor, 0, 0)) {
return nil;
}
//Convert newColor to RGBA value so we can save it to image.
int newRed, newGreen, newBlue, newAlpha;
const CGFloat *components = CGColorGetComponents(newColor.CGColor);
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;
}
}
unsigned int ncolor = (newRed << 24) | (newGreen << 16) | (newBlue << 8) | newAlpha;
LinkedListStack *points = [[LinkedListStack alloc] initWithCapacity:500 incrementSize:500 andMultiplier:height];
LinkedListStack *antiAliasingPoints = [[LinkedListStack alloc] initWithCapacity:500 incrementSize:500 andMultiplier:height];
int x = roundf(startPoint.x);
int y = roundf(startPoint.y);
[points pushFrontX:x andY:y];
unsigned int 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
unsigned int antialiasColor = getColorCodeFromUIColor(newColor,bitmapInfo&kCGBitmapByteOrderMask );
int red1 = ((0xff000000 & antialiasColor) >> 24);
int green1 = ((0x00ff0000 & antialiasColor) >> 16);
int blue1 = ((0x0000ff00 & antialiasColor) >> 8);
int 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))
{
int red2 = ((0xff000000 & color) >> 24);
int green2 = ((0x00ff0000 & color) >> 16);
int blue2 = ((0x0000ff00 & color) >> 8);
int 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))
{
int red2 = ((0xff000000 & color) >> 24);
int green2 = ((0x00ff0000 & color) >> 16);
int blue2 = ((0x0000ff00 & color) >> 8);
int 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)) + roundf(x + 1) * bytesPerPixel;
color = getColorCode(byteIndex, imageData);
if (!compareColor(ncolor, color, 0))
{
int red2 = ((0xff000000 & color) >> 24);
int green2 = ((0x00ff0000 & color) >> 16);
int blue2 = ((0x0000ff00 & color) >> 8);
int 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))
{
int red2 = ((0xff000000 & color) >> 24);
int green2 = ((0x00ff0000 & color) >> 16);
int blue2 = ((0x0000ff00 & color) >> 8);
int 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 * roundf(y + 1)) + roundf(x) * bytesPerPixel;
color = getColorCode(byteIndex, imageData);
if (!compareColor(ncolor, color, 0))
{
int red2 = ((0xff000000 & color) >> 24);
int green2 = ((0x00ff0000 & color) >> 16);
int blue2 = ((0x0000ff00 & color) >> 8);
int 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.
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);
}
}