我可以使用scanline Flood Fill算法在UIImage中应用渐变吗?

时间:2016-03-02 08:25:04

标签: ios objective-c algorithm uiimage flood-fill

我真正想要的是在封闭的轮廓中填充渐变。我到达了可以使用泛洪填充算法在轮廓中填充纯色的点。但我怎么能填充渐变。我是否必须尝试另一种完全不同的方法。如果是,那么我的其他选择是什么?

我在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);
    }
}

0 个答案:

没有答案