1

I want to change a single, specified colour in my SpriteKit sprite to alpha, leaving all other colours unaffected. I don't think that there is an 'easy' way to do this and that a custom shader might be required.

Does anyone know how to do this in Swift or Objective-C?

Here's the image - I design it with a black background as it's easier to see but in my program, I want the background to be transparent.

enter image description here

If I ry to edit the image with the background already set as alpha, then the package I'm using (Pixaki) show this as white-and-grey checks, so it looks like this:

enter image description here

4

1 回答 1

0
  1. 你真的不应该在代码中准备那些可以预先处理的资产。

这是您想要的示例代码。

它基于这个答案(基本上只是通过一些修改转换为 Swift)。学分去那里。

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

您可以调整它并创建命令行工具或直接在代码中使用它。

这是示例项目:https ://github.com/andrey-str/soa-replace-a-color-colour-in-a-skspritenode

免责声明:代码可能会泄漏,我是 Swift 的新手。

  1. 这是一种更简单的方法:-)

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

90% - 是一个容差值,结果看起来和上面的代码一样

祝你好运!

于 2016-04-21T21:58:45.903 回答