ведро с краской для iPhone - PullRequest
1 голос
/ 17 января 2012

Я работаю над внедрением инструмента заливки заливки в приложение для iPhone, и у меня возникли некоторые проблемы с ним. Пользователь может рисовать, и я хотел бы, чтобы ведро с краской позволяло ему коснуться пятна и заполнить все, что связано с этим цветом.

Вот моя идея: 1) Начните с точки, которую выбирает пользователь 2) Сохранение отмеченных точек в NSMutableArray, чтобы они не были перепроверены 3) Если цвет пикселя в текущей точке совпадает с исходной нажатой точкой, сохраните его в массив, который будет изменен позже 4) Если цвет пикселя в текущей точке отличается от исходного, верните. (Граница) 5) После завершения сканирования просмотрите массив пикселей и измените их на новый цвет.

Но пока это не работает. Любая помощь или знание, как это сделать, будет принята с благодарностью! Вот мой код.

-(void)flood:(int)x:(int)y
{

    //NSLog(@"Flood %i  %i", x, y);

    CGPoint point = CGPointMake(x, y);
    NSValue *value = [NSValue valueWithCGPoint:point];

    //Don't repeat checked pixels
    if([self.checkedFloodPixels containsObject:value])
    {
        return;
    }

    else
    {
        //If not checked, mark as checked
        [self.checkedFloodPixels addObject:value];

        //Make sure in bounds
        if([self isOutOfBounds:x:y] || [self reachedStopColor:x:y])
        {
            return;
        }


        //Go to adjacent points
        [self flood:x+1:y];
        [self flood:x-1:y];
        [self flood:x:y+1];
        [self flood:x:y-1];
    }
}

- (BOOL)isOutOfBounds:(int)x:(int)y
{
    BOOL outOfBounds;

    if(y > self.drawImage.frame.origin.y && y < (self.drawImage.frame.origin.y + self.drawImage.frame.size.height))
    {
        if(x > self.drawImage.frame.origin.x && x < (self.drawImage.frame.origin.x + self.drawImage.frame.size.width))
        {
            outOfBounds = NO;
        }

        else
        {
            outOfBounds = YES;
        }
    }

    else
    {
        outOfBounds = YES;
    }

    if(outOfBounds)
        NSLog(@"Out of bounds");

    return outOfBounds;
}

- (BOOL)reachedStopColor:(int)x:(int)y
{
    CFDataRef theData = CGDataProviderCopyData(CGImageGetDataProvider(self.drawImage.image.CGImage));

    const UInt8 *pixelData = CFDataGetBytePtr(theData);

    int red = 0;
    int green = 1;
    int blue = 2;

    //RGB for point being checked
    float newPointR;
    float newPointG;
    float newPointB;

    //RGB for point initially clicked
    float oldPointR;
    float oldPointG;
    float oldPointB;

    int index;
    BOOL reachedStopColor = NO;


    //Format oldPoint RBG - pixels are every 4 bytes so round to 4
    index = lastPoint.x * lastPoint.y;

    if(index % 4 != 0)
    {
        index -= 2;
        index /= 4;
        index *= 4;
    }

    //Get into 0.0 - 1.0 value
    oldPointR = pixelData[index + red];
    oldPointG = pixelData[index + green];
    oldPointB = pixelData[index + blue];

    oldPointR /= 255.0;
    oldPointG /= 255.0;
    oldPointB /= 255.0;

    oldPointR *= 1000;
    oldPointG *= 1000;
    oldPointB *= 1000;

    int oldR = oldPointR;
    int oldG = oldPointG;
    int oldB = oldPointB;

    oldPointR = oldR / 1000.0;
    oldPointG = oldG / 1000.0;
    oldPointB = oldB / 1000.0;

    //Format newPoint RBG
    index = x*y;

    if(index % 4 != 0)
    {
        index -= 2;
        index /= 4;
        index *= 4;
    }

    newPointR = pixelData[index + red];
    newPointG = pixelData[index + green];
    newPointB = pixelData[index + blue];

    newPointR /= 255.0;
    newPointG /= 255.0;
    newPointB /= 255.0;

    newPointR *= 1000;
    newPointG *= 1000;
    newPointB *= 1000;

    int newR = newPointR;
    int newG = newPointG;
    int newB = newPointB;

    newPointR = newR / 1000.0;
    newPointG = newG / 1000.0;
    newPointB = newB / 1000.0;

    //Check if different color
    if(newPointR < (oldPointR - 0.02f) || newPointR > (oldPointR + 0.02f))
    {
        if(newPointG < (oldPointG - 0.02f) || newPointG > (oldPointG + 0.02f))
        {
            if(newPointB < (oldPointB - 0.02f) || newPointB > (oldPointB + 0.02f))
            {
                reachedStopColor = YES;
                NSLog(@"Different Color");
            }

            else
            {
                NSLog(@"Same Color3");

                NSNumber *num = [NSNumber numberWithInt:index];
                [self.pixelsToChange addObject:num];
            }
        }

        else
        {
            NSLog(@"Same Color2");

            NSNumber *num = [NSNumber numberWithInt:index];
            [self.pixelsToChange addObject:num];
        }
    }

    else
    {
        NSLog(@"Same Color1");

        NSNumber *num = [NSNumber numberWithInt:index];
        [self.pixelsToChange addObject:num];
    }

    CFRelease(theData);

    if(reachedStopColor)
        NSLog(@"Reached stop color");

    return reachedStopColor;
}

-(void)fillAll
{
    CGContextRef ctx;
    CGImageRef imageRef = self.drawImage.image.CGImage;
    NSUInteger width = CGImageGetWidth(imageRef);
    NSUInteger height = CGImageGetHeight(imageRef);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    unsigned char *rawData = malloc(height * width * 4);
    NSUInteger bytesPerPixel = 4;
    NSUInteger bytesPerRow = bytesPerPixel * width;
    NSUInteger bitsPerComponent = 8;
    CGContextRef context = CGBitmapContextCreate(rawData, width, height,
                                             bitsPerComponent, bytesPerRow, colorSpace,
                                             kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
    CGColorSpaceRelease(colorSpace);

    CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
    CGContextRelease(context);

    int red = 0;
    int green = 1;
    int blue = 2;

    int index;
    NSNumber *num;

    for(int i = 0; i < [self.pixelsToChange count]; i++)
    {
        num = [self.pixelsToChange objectAtIndex:i];

        index = [num intValue];

        rawData[index + red] = (char)[[GameManager sharedManager] RValue];
        rawData[index + green] = (char)[[GameManager sharedManager] GValue];
        rawData[index + blue] = (char)[[GameManager sharedManager] BValue];
    }

    ctx = CGBitmapContextCreate(rawData,
                            CGImageGetWidth( imageRef ),
                            CGImageGetHeight( imageRef ),
                            8,
                            CGImageGetBytesPerRow( imageRef ),
                            CGImageGetColorSpace( imageRef ),
                            kCGImageAlphaPremultipliedLast ); 

    imageRef = CGBitmapContextCreateImage (ctx);
    UIImage* rawImage = [UIImage imageWithCGImage:imageRef];  

    CGContextRelease(ctx);  

    self.drawImage.image = rawImage;  

    free(rawData);
}

1 Ответ

1 голос
/ 29 ноября 2012

поэтому я нашел это (я знаю, что вопрос сейчас может быть неактуальным, но для людей, которые все еще ищут что-то подобное, это не так):

, чтобы получить цвет в пикселях из контекста (измененный код из здесь ):

- (UIColor*) getPixelColorAtLocation:(CGPoint)point {
UIColor* color;
CGContextRef cgctx = UIGraphicsGetCurrentContext();

unsigned char* data = CGBitmapContextGetData (cgctx);
if (data != NULL) {
    int offset = 4*((ContextWidth*round(point.y))+round(point.x)); //i dont know how to get ContextWidth from current context so i have it as a instance variable in my code
    int alpha =  data[offset];
    int red = data[offset+1];
    int green = data[offset+2];
    int blue = data[offset+3];
    color = [UIColor colorWithRed:(red/255.0f) green:(green/255.0f) blue:(blue/255.0f) alpha:(alpha/255.0f)];
}

if (data) { free(data); }

return color;

}

и алгоритм заполнения: это здесь

Это то, что я использую, ноСамо заполнение довольно медленное по сравнению со стилями рисования CGPath.То есть, если вы делаете рендеринг за кадром и / или вы заполняете его динамически, вот так это выглядит круто:

here

...