Ios 使用泛光填充在UIImage中填充颜色时出错

Ios 使用泛光填充在UIImage中填充颜色时出错,ios,objective-c,uiimage,flood-fill,Ios,Objective C,Uiimage,Flood Fill,感谢Chintan R Dave的: 我使用以下UIImage类别填充闭合轮廓中的颜色。它使用扫描线洪水填充算法 对于未从设备捕获的图像,它工作正常。对于从设备捕获的图像,它会给我EXC_BAD_访问错误(如问题末尾的屏幕截图所示)。大家都知道,这种错误很难处理。。因此,我非常感谢您就解决方案的起点提供一些建议 代码如下:- UIImage+FloodFill.m @implementation UIImage (FloodFill) /* startPoint : Point from

感谢Chintan R Dave的:

我使用以下UIImage类别填充闭合轮廓中的颜色。它使用扫描线洪水填充算法

对于未从设备捕获的图像,它工作正常。对于从设备捕获的图像,它会给我EXC_BAD_访问错误(如问题末尾的屏幕截图所示)。大家都知道,这种错误很难处理。。因此,我非常感谢您就解决方案的起点提供一些建议

代码如下:-

UIImage+FloodFill.m

@implementation UIImage (FloodFill)
/*
    startPoint : Point from where you want to color. Generaly this is touch point.
                 This is important because color at start point will be replaced with other.

    newColor   : This color will be apply at point where the match on startPoint color found.

    tolerance  : If Tolerance is 0 than it will search for exact match of color 
                 other wise it will take range according to tolerance value.

                 If You dont want to use tolerance and want to incress performance Than you can change
                 compareColor(ocolor, color, tolerance) with just ocolor==color which reduse function call.
*/
- (UIImage *) floodFillFromPoint:(CGPoint)startPoint withColor:(UIColor *)newColor andTolerance:(int)tolerance
{
    return [self floodFillFromPoint:startPoint withColor:newColor andTolerance:tolerance useAntiAlias:YES];
}

- (UIImage *) floodFillFromPoint:(CGPoint)startPoint withColor:(UIColor *)newColor andTolerance:(int)tolerance useAntiAlias:(BOOL)antiAlias
{
    @try
    {
        /*
            First We create rowData from UIImage.
            We require this conversation so that we can use detail at pixel like color at pixel.
        */

        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;

        /*
            We are using stack to store point.
            Stack is implemented by LinkList.
            To incress speed I have used NSMutableData insted of NSMutableArray.
        */

        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];

        /*
            Scanline Floodfill Algorithm With Stack (floodFillScanlineStack)
        */

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

/*
    I have used pure C function because it is said than C function is faster than Objective - C method in call.
    This two function are called most of time so it require that calling this work in speed.
    I have not verified this performance so I like to here comment on this.
*/
/*
    This function extract color from image and convert it to integer represent.
    Converting to integer make comperation easy.
*/
unsigned int getColorCode (unsigned int byteIndex, unsigned char *imageData)
{
    unsigned int red   = imageData[byteIndex];
    unsigned int green = imageData[byteIndex + 1];
    unsigned int blue  = imageData[byteIndex + 2];
    unsigned int alpha = imageData[byteIndex + 3];

    return (red << 24) | (green << 16) | (blue << 8) | alpha;
}

/*
    This function compare two color with counting tolerance value.

    If color is between tolerance rancge than it return true other wise false.
*/
bool compareColor (unsigned int color1, unsigned int color2, int tolorance)
{
    if(color1 == color2)
        return true;

    int red1   = ((0xff000000 & color1) >> 24);
    int green1 = ((0x00ff0000 & color1) >> 16);
    int blue1  = ((0x0000ff00 & color1) >> 8);
    int alpha1 =  (0x000000ff & color1);

    int red2   = ((0xff000000 & color2) >> 24);
    int green2 = ((0x00ff0000 & color2) >> 16);
    int blue2  = ((0x0000ff00 & color2) >> 8);
    int alpha2 =  (0x000000ff & color2);

    int diffRed   = abs(red2   - red1);
    int diffGreen = abs(green2 - green1);
    int diffBlue  = abs(blue2  - blue1);
    int diffAlpha = abs(alpha2 - alpha1);

    if( diffRed   > tolorance ||
        diffGreen > tolorance ||
        diffBlue  > tolorance ||
        diffAlpha > tolorance  )
    {
        return false;
    }

    return true;
}

unsigned int getColorCodeFromUIColor(UIColor *color, CGBitmapInfo orderMask)
{
    //Convert newColor to RGBA value so we can save it to image.
    int newRed, newGreen, newBlue, newAlpha;

    const CGFloat *components = CGColorGetComponents(color.CGColor);

    if(CGColorGetNumberOfComponents(color.CGColor) == 2)
    {
        newRed   = newGreen = newBlue = components[0] * 255;
        newAlpha = components[1] * 255;
    }
    else if (CGColorGetNumberOfComponents(color.CGColor) == 4)
    {
        if (orderMask == 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;
        }
    }
    else
    {
        newRed   = newGreen = newBlue = 0;
        newAlpha = 255;
    }

    unsigned int ncolor = (newRed << 24) | (newGreen << 16) | (newBlue << 8) | newAlpha;

    return ncolor;
}

@end
#import "LinkedListStack.h"

@implementation LinkedListStack

#pragma mark - Initialisation
/*
    A linked List is create with size of <capicity>.
    When you add more element that <capicity> than Lisk List is incressed by size <increment>
    mul is value for H (for H see comment Stack methods)
*/
- (id)init
{
    return [self initWithCapacity:500];
}

- (id)initWithCapacity:(int)capacity
{
    return [self initWithCapacity:capacity incrementSize:500 andMultiplier:1000];
}

- (id)initWithCapacity:(int)capacity incrementSize:(int)increment andMultiplier:(int)mul
{
    self = [super init];

    if(self)
    {
        _cacheSizeIncrements = increment;

        int bytesRequired = capacity * sizeof(PointNode);

        nodeCache = [[NSMutableData alloc] initWithLength:bytesRequired];

        [self initialiseNodesAtOffset:0 count:capacity];

        freeNodeOffset = 0;
        topNodeOffset = FINAL_NODE_OFFSET;

        multiplier = mul;
    }

    return self;
}

#pragma mark - Stack methods
/*
    X and Y are converted in single integer value (P) to push in stack.
    And again that value (P) are converted to X and Y when pop by using following equation:

    P = H * X + Y

    X = P / H;
    Y = P % H;

    H is same for all X and Y and must be grater than Y. So generaly Height is prefered value;
*/
- (void)pushFrontX:(int)x andY:(int)y;
{
    int p = multiplier * x + y;

    PointNode *node = [self getNextFreeNode];

    node->point = p;
    node->nextNodeOffset = topNodeOffset;

    topNodeOffset = [self offsetOfNode:node];
}

- (int)popFront:(int *)x andY:(int *)y;
{
    if(topNodeOffset == FINAL_NODE_OFFSET)
    {
        return INVALID_NODE_CONTENT;
    }

    PointNode *node = [self nodeAtOffset:topNodeOffset];

    int thisNodeOffset = topNodeOffset;

    // Remove this node from the queue
    topNodeOffset = node->nextNodeOffset;
    int value = node->point;

    // Reset it and add it to the free node cache
    node->point = 0;
    node->nextNodeOffset = freeNodeOffset;

    freeNodeOffset = thisNodeOffset;

    *x = value / multiplier;
    *y = value % multiplier;

    return value;
}

#pragma mark - utility functions
- (int)offsetOfNode:(PointNode *)node
{
    return node - (PointNode *)nodeCache.mutableBytes;
}

- (PointNode *)nodeAtOffset:(int)offset
{
    return (PointNode *)nodeCache.mutableBytes + offset;
}

- (PointNode *)getNextFreeNode
{
    if(freeNodeOffset < 0)
    {
        // Need to extend the size of the nodeCache
        int currentSize = nodeCache.length / sizeof(PointNode);
        [nodeCache increaseLengthBy:_cacheSizeIncrements * sizeof(PointNode)];

        // Set these new nodes to be the free ones
        [self initialiseNodesAtOffset:currentSize count:_cacheSizeIncrements];
        freeNodeOffset = currentSize;
    }

    PointNode *node = (PointNode*)nodeCache.mutableBytes + freeNodeOffset;
    freeNodeOffset = node->nextNodeOffset;

    return node;
}

- (void)initialiseNodesAtOffset:(int)offset count:(int)count
{
    PointNode *node = (PointNode *)nodeCache.mutableBytes + offset;

    for (int i=0; i<count - 1; i++)
    {
        node->point = 0;
        node->nextNodeOffset = offset + i + 1;
        node++;
    }

    node->point = 0;

    // Set the next node offset to make sure we don't continue
    node->nextNodeOffset = FINAL_NODE_OFFSET;
}
@UIImage(泛洪填充)
/*
起始点:从您要着色的位置开始的点。通常这是接触点。
这很重要,因为起点处的颜色将替换为其他颜色。
newColor:此颜色将应用于找到startPoint颜色匹配的点。
公差:如果公差为0,它将搜索颜色的精确匹配
另一方面,它将根据公差值取值范围。
如果您不想使用容差,并且希望提高性能,那么您可以改变
将颜色(ocolor,color,tolerance)与reduse函数调用的ocolor==颜色进行比较。
*/
-(UIImage*)floodFillFromPoint:(CGPoint)带有颜色的起始点:(UIColor*)新颜色和公差:(int)公差
{
return[self-floodFillFromPoint:startPoint with-color:newColor and-tolerance:tolerance-useAntiAlias:YES];
}
-(UIImage*)floodFillFromPoint:(CGPoint)带有颜色的起始点:(UIColor*)新颜色和公差:(int)公差使用antiAlias:(BOOL)antiAlias
{
@试一试
{
/*
首先,我们从UIImage创建行数据。
我们需要这个对话,这样我们就可以在像素上使用细节,就像在像素上使用颜色一样。
*/
CGColorSpaceRef colorSpace=CGColorSpaceCreateDeviceRGB();
CGImageRef imageRef=[自CGImage];
NSU整数宽度=CGImageGetWidth(imageRef);
NSU整数高度=CGImageGetHeight(imageRef);
无符号字符*imageData=malloc(高度*宽度*4);
NSUInteger bytesPerPixel=cgmagegetbitsperpixel(imageRef)/8;
NSUInteger bytesPerRow=CGImageGetBytesPerRow(imageRef);
NSUInteger bitsPerComponent=CGImageGetBitsPerComponent(imageRef);
CGBitmapInfo-bitmapInfo=CGImageGetBitmapInfo(imageRef);
如果(kCGImageAlphaLast==(uint32_t)位图信息| | kCGImageAlphaFirst==(uint32_t)位图信息){
bitmapInfo=(uint32_t)kGimageAlphaPremultipledLast;
}
CGContextRef context=CGBitmapContextCreate(imageData,
宽度,
高度,
比特组件,
拜特斯佩罗,
色彩空间,
位图信息);
CGCOLORSPACTERELEASE(色彩空间);
CGContextDrawImage(上下文,CGRectMake(0,0,宽度,高度),imageRef);
//在开始点获得颜色
无符号整数byteIndex=(bytesPerRow*roundf(startPoint.y))+roundf(startPoint.x)*字节/像素;
unsigned int-ocolor=getColorCode(byteIndex,imageData);
if(比较色(ocolor,0,0)){
返回零;
}
//将newColor转换为RGBA值,以便将其保存到图像中。
int新红、新绿、新蓝、新阿尔法;
const CGFloat*components=CGColorGetComponents(newColor.CGColor);
if(CGColorGetNumberOfComponents(newColor.CGColor)==2)
{
newRed=newGreen=newBlue=components[0]*255;
newAlpha=组件[1]*255;
}
else if(CGColorGetNumberOfComponents(newColor.CGColor)==4)
{
if((bitmapInfo&kCGBitmapByteOrderMask)==kCGBitmapByteOrder32Little)
{
newRed=组件[2]*255;
newGreen=组件[1]*255;
newBlue=组件[0]*255;
newAlpha=255;
}
其他的
{
newRed=组件[0]*255;
newGreen=组件[1]*255;
新蓝=组件[2]*255;
newAlpha=255;
}
}
无符号int-ncolor=(newRed=0&!compareColor(ocolor,color,0))
{
[抗锯齿点x:x:y];
}
y++;
span左=右=否;
byteIndex=(bytesPerRow*roundf(y))+roundf(x)*bytesPerPixel;
颜色=getColorCode(byteIndex,imageData);
而(y<高度和对比颜色(O颜色、颜色、公差)&&N颜色!=颜色)
{
//使用新颜色RGBA值更改旧颜色
imageData[byteIndex+0]=新红色;
imageData[byteIndex+1]=新绿色;
imageData[byteIndex+2]=新蓝色;
imageData[byteIndex+3]=新Alpha;
如果(x>0)
{
byteIndex=(bytesPerRow*roundf(y))+roundf(x-1)*bytesperperpixel;
颜色=getColorCode(byteIndex,imageData);
如果(!spanLeft&&x>0&&compareColor(O颜色、颜色、公差))
{
[点x:(x-1)安迪:y];
spanLeft=是;
}
else if(spanLeft&&x>0&&!比较颜色(O颜色、颜色、公差))
{
spanLeft=否;
}
//我们不能向左。在抗锯齿列表中添加点
如果(!spanLeft&&x>0&&!compareColor(ocolor,color,tolerance)&!compareColor(ncolor,color,to
#import "LinkedListStack.h"

@implementation LinkedListStack

#pragma mark - Initialisation
/*
    A linked List is create with size of <capicity>.
    When you add more element that <capicity> than Lisk List is incressed by size <increment>
    mul is value for H (for H see comment Stack methods)
*/
- (id)init
{
    return [self initWithCapacity:500];
}

- (id)initWithCapacity:(int)capacity
{
    return [self initWithCapacity:capacity incrementSize:500 andMultiplier:1000];
}

- (id)initWithCapacity:(int)capacity incrementSize:(int)increment andMultiplier:(int)mul
{
    self = [super init];

    if(self)
    {
        _cacheSizeIncrements = increment;

        int bytesRequired = capacity * sizeof(PointNode);

        nodeCache = [[NSMutableData alloc] initWithLength:bytesRequired];

        [self initialiseNodesAtOffset:0 count:capacity];

        freeNodeOffset = 0;
        topNodeOffset = FINAL_NODE_OFFSET;

        multiplier = mul;
    }

    return self;
}

#pragma mark - Stack methods
/*
    X and Y are converted in single integer value (P) to push in stack.
    And again that value (P) are converted to X and Y when pop by using following equation:

    P = H * X + Y

    X = P / H;
    Y = P % H;

    H is same for all X and Y and must be grater than Y. So generaly Height is prefered value;
*/
- (void)pushFrontX:(int)x andY:(int)y;
{
    int p = multiplier * x + y;

    PointNode *node = [self getNextFreeNode];

    node->point = p;
    node->nextNodeOffset = topNodeOffset;

    topNodeOffset = [self offsetOfNode:node];
}

- (int)popFront:(int *)x andY:(int *)y;
{
    if(topNodeOffset == FINAL_NODE_OFFSET)
    {
        return INVALID_NODE_CONTENT;
    }

    PointNode *node = [self nodeAtOffset:topNodeOffset];

    int thisNodeOffset = topNodeOffset;

    // Remove this node from the queue
    topNodeOffset = node->nextNodeOffset;
    int value = node->point;

    // Reset it and add it to the free node cache
    node->point = 0;
    node->nextNodeOffset = freeNodeOffset;

    freeNodeOffset = thisNodeOffset;

    *x = value / multiplier;
    *y = value % multiplier;

    return value;
}

#pragma mark - utility functions
- (int)offsetOfNode:(PointNode *)node
{
    return node - (PointNode *)nodeCache.mutableBytes;
}

- (PointNode *)nodeAtOffset:(int)offset
{
    return (PointNode *)nodeCache.mutableBytes + offset;
}

- (PointNode *)getNextFreeNode
{
    if(freeNodeOffset < 0)
    {
        // Need to extend the size of the nodeCache
        int currentSize = nodeCache.length / sizeof(PointNode);
        [nodeCache increaseLengthBy:_cacheSizeIncrements * sizeof(PointNode)];

        // Set these new nodes to be the free ones
        [self initialiseNodesAtOffset:currentSize count:_cacheSizeIncrements];
        freeNodeOffset = currentSize;
    }

    PointNode *node = (PointNode*)nodeCache.mutableBytes + freeNodeOffset;
    freeNodeOffset = node->nextNodeOffset;

    return node;
}

- (void)initialiseNodesAtOffset:(int)offset count:(int)count
{
    PointNode *node = (PointNode *)nodeCache.mutableBytes + offset;

    for (int i=0; i<count - 1; i++)
    {
        node->point = 0;
        node->nextNodeOffset = offset + i + 1;
        node++;
    }

    node->point = 0;

    // Set the next node offset to make sure we don't continue
    node->nextNodeOffset = FINAL_NODE_OFFSET;
}
unsigned int getColorCode (unsigned int byteIndex, unsigned char *imageData)
{
    unsigned int red   = imageData[byteIndex];
    unsigned int green = imageData[byteIndex + 1];
    unsigned int blue  = imageData[byteIndex + 2];
    unsigned int alpha = imageData[byteIndex + 3];

    return (red << 24) | (green << 16) | (blue << 8) | alpha;
}
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGImageRef imageRef = [self CGImage];
CGDataProviderRef imgDataProvider = CGDataProviderCreateWithCFData((CFDataRef)UIImagePNGRepresentation(self));

CGImageRef imageRef = CGImageCreateWithPNGDataProvider(imgDataProvider, NULL, true, kCGRenderingIntentDefault);