我想将SpriteKit精灵中的单个指定颜色更改为alpha,让所有其他颜色不受影响。我不认为有一个容易的'这样做的方法,可能需要自定义着色器。
有人知道如何在Swift或Objective-C中执行此操作吗?
这是图像 - 我用黑色背景设计它,因为它更容易看到,但在我的程序中,我希望背景是透明的。
如果我要编辑背景已经设置为alpha的图像,那么我使用的程序包(Pixaki)会将其显示为白色和灰色的检查,所以它看起来像这样:
答案 0 :(得分:0)
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.
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!