Question

I am making a military strategy game. When an army in my game takes over a territory, I want to be able to change the color of the territory on the map so that it shows the new controller of that territory. Here is the code I have that changes a territory's image:

I would write this line for example:

UIImage *newImg = [self imageOfTerritoryWithNewArmy:@"japan" AndOldTerritoryImage:[UIImage imageNamed:@"ireland.gif"]];

Here is the rest of the code:

-(UIImage *)createImageWithRGB:(NSArray *)colorData width:(NSInteger)width height:(NSInteger)height{
    unsigned char *rawData = malloc(width*height*4);
    for (int i=0; i<width*height; ++i)
    {
        CGFloat red;
        CGFloat green;
        CGFloat blue;
        CGFloat alpha;
        UIColor *color = colorData[i];
        if ([color respondsToSelector:@selector(getRed:green:blue:alpha:)]) {
            [color getRed:&red green:&green blue:&blue alpha:&alpha];
        } else {
            const CGFloat *components = CGColorGetComponents(color.CGColor);
            red = components[0];
            green = components[1];
            blue = components[2];
            alpha = components[3];
        }
        if(alpha > 0){
            rawData[4*i] = red * 255;
            rawData[4*i+1] = green * 255;
            rawData[4*i+2] = blue * 255;
            rawData[4*i+3] = alpha * 255;
        }
        else{
            rawData[4*i] = 255;
            rawData[4*i+1] = 255;
            rawData[4*i+2] = 255;
            rawData[4*i+3] = 0;
        }
    }

    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL,
                                                          rawData,
                                                          width*height*4,
                                                          NULL);
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
    CGImageRef imageRef = CGImageCreate(width,
                                    height,
                                    8,
                                    32,
                                    4*width,colorSpaceRef,
                                    bitmapInfo,
                                    provider,NULL,NO,renderingIntent);
    UIImage *newImage = [UIImage imageWithCGImage:imageRef];
    return newImage;
}

- (NSArray *)getRGBAsFromImage:(UIImage*)image atX:(int)xx andY:(int)yy count:(int)count{
NSMutableArray *result = [NSMutableArray arrayWithCapacity:count];

// First get the image into your data buffer
CGImageRef imageRef = [image CGImage];
NSUInteger width = CGImageGetWidth(imageRef);
NSUInteger height = CGImageGetHeight(imageRef);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
unsigned char *rawData = (unsigned char*) calloc(height * width * 4, sizeof(unsigned char));
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);

// Now your rawData contains the image data in the RGBA8888 pixel format.
int byteIndex = (bytesPerRow * yy) + xx * bytesPerPixel;
for (int ii = 0 ; ii < count ; ++ii)
{
    CGFloat red   = (rawData[byteIndex]     * 1.0) / 255.0;
    CGFloat green = (rawData[byteIndex + 1] * 1.0) / 255.0;
    CGFloat blue  = (rawData[byteIndex + 2] * 1.0) / 255.0;
    CGFloat alpha = (rawData[byteIndex + 3] * 1.0) / 255.0;
    byteIndex += 4;

    UIColor *acolor = [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
    [result addObject:acolor];
}

free(rawData);

return result;
}

-(UIColor *)colorOfArmy:(NSString *)army{
UIColor *color;
army = [army stringByReplacingOccurrencesOfString:@"\a" withString:@""];
if([army isEqual:@"france"]){
    color = [[UIColor alloc] initWithRed:0.3137254 green:0.3686274 blue:0.9058823 alpha:1];
}
if([army isEqual:@"germany"]){
    color = [[UIColor alloc] initWithRed:0.6352941 green:0.4313725 blue:0.3372549 alpha:1];
}
if([army isEqual:@"uk"]){
    color = [[UIColor alloc] initWithRed:0.8941176 green:0.4235294 blue:0.4941176 alpha:1];
}
if([army isEqual:@"italy"]){
    color = [[UIColor alloc] initWithRed:0.5137254 green:0.1215686 blue:0.4745098 alpha:1];
}
if([army isEqual:@"ussr"]){
    color = [[UIColor alloc] initWithRed:0.3607843 green:0.0823529 blue:0.1215686 alpha:1];
}
if([army isEqual:@"japan"]){
    color = [[UIColor alloc] initWithRed:0.9215686 green:0.6156862 blue:0.3137254 alpha:1];
}
if([army isEqual:@""]){
    color = [[UIColor alloc] initWithRed:0.1215686 green:0.2823529 blue:0.1607843 alpha:1];
}
if(color == nil){
    NSLog(@"the problem was %@", army);
}
return color;
}

-(UIImage *)imageOfTerritoryWithNewArmy:(NSString *)army AndOldTerritoryImage:(UIImage *)oldImg{
CGImageRef image = oldImg.CGImage;
NSInteger width = CGImageGetWidth(image);
NSInteger height = CGImageGetHeight(image);
NSArray *rgba = [self getRGBAsFromImage:oldImg atX:0 andY:0 count:width * height];
NSMutableArray *fixedRGBA = [[NSMutableArray alloc] init];
UIColor *armyColor = [self colorOfArmy:army];
for(UIColor *pixel in rgba){
    CGFloat red;
    CGFloat green;
    CGFloat blue;
    CGFloat alpha;
    if ([pixel respondsToSelector:@selector(getRed:green:blue:alpha:)]) {
        [pixel getRed:&red green:&green blue:&blue alpha:&alpha];
    } else {
        const CGFloat *components = CGColorGetComponents(pixel.CGColor);
        red = components[0];
        green = components[1];
        blue = components[2];
        alpha = components[3];
    }
    red = red * 255;
    green = green * 255;
    blue = blue * 255;
    if(alpha > 0){
        if(red < 50 && green < 50 && blue < 50){
            [fixedRGBA addObject:pixel];
        }
        else{
            [fixedRGBA addObject:armyColor];
        }
    }
    else{
        [fixedRGBA addObject:pixel];
    }
}
return [self createImageWithRGB:fixedRGBA width:width height:height];
}

The problem that I am having is that when the image is drawn again, all of the pixels that used to be blank because they have an alpha value of 0 are displayed as white. How can I get these pixels to still be displayed as clear pixels?

Was it helpful?

Solution

When creating the image, you should specify that it contains an alpha channel. That is, instead of:

CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;

use:

CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaLast;

See the CGImage interface specification for more info.

OTHER TIPS

I believe your else clause here is where you want to set the color to clear

    if(alpha > 0){
        rawData[4*i] = red * 255;
        rawData[4*i+1] = green * 255;
        rawData[4*i+2] = blue * 255;
        rawData[4*i+3] = alpha * 255;
    }
    else{
        rawData[4*i] = 255;
        rawData[4*i+1] = 255;
        rawData[4*i+2] = 255;
        rawData[4*i+3] = 255;
    }

You have to change the last assignment to 0

    if(alpha > 0){
        rawData[4*i] = red * 255;
        rawData[4*i+1] = green * 255;
        rawData[4*i+2] = blue * 255;
        rawData[4*i+3] = alpha * 255;
    }
    else{
        rawData[4*i] = 255;
        rawData[4*i+1] = 255;
        rawData[4*i+2] = 255;
        rawData[4*i+3] = 0;
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top