替换SKSpriteNode中的颜色/颜色

时间:2016-04-21 13:08:16

标签: sprite-kit skspritenode sktexture

我想将SpriteKit精灵中的单个指定颜色更改为alpha,让所有其他颜色不受影响。我不认为有一个容易的'这样做的方法,可能需要自定义着色器。

有人知道如何在Swift或Objective-C中执行此操作吗?

这是图像 - 我用黑色背景设计它,因为它更容易看到,但在我的程序中,我希望背景是透明的。

enter image description here

如果我要编辑背景已经设置为alpha的图像,那么我使用的程序包(Pixaki)会将其显示为白色和灰色的检查,所以它看起来像这样:

enter image description here

1 个答案:

答案 0 :(得分:0)

  1. You really should not perform preparing in code those assets which can be processed beforehand.

Here is sample code which does what you want though.

It is based on this answer(bascially just converted to Swift with some modifications). Credits go there.

// color - source color, which is must be replaced
// withColor - target color
// tolerance - value in range from 0 to 1
func replaceColor(color:SKColor, withColor:SKColor, image:UIImage, tolerance:CGFloat) -> UIImage{

    // This function expects to get source color(color which is supposed to be replaced) 
    // and target color in RGBA color space, hence we expect to get 4 color components: r, g, b, a
    assert(CGColorGetNumberOfComponents(color.CGColor) == 4 && CGColorGetNumberOfComponents(withColor.CGColor) == 4,
           "Must be RGBA colorspace")

    // Allocate bitmap in memory with the same width and size as source image
    let imageRef = image.CGImage
    let width = CGImageGetWidth(imageRef)
    let height = CGImageGetHeight(imageRef)

    let colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB)!

    let bytesPerPixel = 4
    let bytesPerRow = bytesPerPixel * width;
    let bitsPerComponent = 8
    let bitmapByteCount = bytesPerRow * height

    let rawData = UnsafeMutablePointer<UInt8>.alloc(bitmapByteCount)

    let context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace,
                                        CGImageAlphaInfo.PremultipliedLast.rawValue | CGBitmapInfo.ByteOrder32Big.rawValue)


    let rc = CGRect(x: 0, y: 0, width: width, height: height)

    // Draw source image on created context
    CGContextDrawImage(context, rc, imageRef)


    // Get color components from replacement color
    let withColorComponents = CGColorGetComponents(withColor.CGColor)
    let r2 = UInt8(withColorComponents[0] * 255)
    let g2 = UInt8(withColorComponents[1] * 255)
    let b2 = UInt8(withColorComponents[2] * 255)
    let a2 = UInt8(withColorComponents[3] * 255)

    // Prepare to iterate over image pixels
    var byteIndex = 0

    while byteIndex < bitmapByteCount {

        // Get color of current pixel
        let red:CGFloat = CGFloat(rawData[byteIndex + 0])/255
        let green:CGFloat = CGFloat(rawData[byteIndex + 1])/255
        let blue:CGFloat = CGFloat(rawData[byteIndex + 2])/255
        let alpha:CGFloat = CGFloat(rawData[byteIndex + 3])/255

        let currentColor = SKColor(red: red, green: green, blue: blue, alpha: alpha);

        // Compare two colors using given tolerance value
        if compareColor(color, withColor: currentColor , withTolerance: tolerance) {

            // If the're 'similar', then replace pixel color with given target color
            rawData[byteIndex + 0] = r2
            rawData[byteIndex + 1] = g2
            rawData[byteIndex + 2] = b2
            rawData[byteIndex + 3] = a2
        }

        byteIndex = byteIndex + 4;
    }

    // Retrieve image from memory context
    let imgref = CGBitmapContextCreateImage(context)
    let result = UIImage(CGImage: imgref!)

    // Clean up a bit
    rawData.destroy()

    return result
}

func compareColor(color:SKColor, withColor:SKColor, withTolerance:CGFloat) -> Bool {

    var r1: CGFloat = 0.0, g1: CGFloat = 0.0, b1: CGFloat = 0.0, a1: CGFloat = 0.0;
    var r2: CGFloat = 0.0, g2: CGFloat = 0.0, b2: CGFloat = 0.0, a2: CGFloat = 0.0;

    color.getRed(&r1, green: &g1, blue: &b1, alpha: &a1);
    withColor.getRed(&r2, green: &g2, blue: &b2, alpha: &a2);

    return fabs(r1 - r2) <= withTolerance &&
        fabs(g1 - g2) <= withTolerance &&
        fabs(b1 - b2) <= withTolerance &&
        fabs(a1 - a2) <= withTolerance;
}

You can adjust it and create command line tool or use it directly in your code.

Here is sample project: https://github.com/andrey-str/soa-replace-a-color-colour-in-a-skspritenode

Disclaimer: code may leaking, I'm newbie in Swift.

  1. And here is a simpler way :-)

    $ brew install imagemagick
    $ convert B2CkX.png -fuzz 90% -transparent black result.png
    

90% - is a tolerance value, result looks the same as with code above

Good luck!