I have one "room" image.
Now, user will click on any particular color suppose blue color in image.
And also user will select replaced color like "black" color.
So, all "blue" color inside the image will be replaced by "black" color.
Any one have idea for how to achieve this in iPhone?
Help is appreciated.
Wrote a function from memory..errors possible..correct yourself
-(UIImage*)changeColor:(UIImage*)myImage fromColor:(UIColor*)fromColor toColor:(UIColor*)toColor{
CGImageRef originalImage = [myImage CGImage];
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef bitmapContext =
CGBitmapContextCreate(NULL,CGImageGetWidth(originalImage),CGImageGetHeight(originalImage),
8,CGImageGetWidth(originalImage)*4,colorSpace,kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease(colorSpace);
CGContextDrawImage(bitmapContext, CGRectMake(0, 0,
CGBitmapContextGetWidth(bitmapContext),CGBitmapContextGetHeight(bitmapContext)),
originalImage);
UInt8 *data = CGBitmapContextGetData(bitmapContext);
int numComponents = 4;
int bytesInContext = CGBitmapContextGetHeight(bitmapContext) *
CGBitmapContextGetBytesPerRow(bitmapContext);
double redIn, greenIn, blueIn,alphaIn;
CGFloat fromRed,fromGreen,fromBlue,fromAlpha;
CGFloat toRed,toGreen,toBlue,toAlpha;
//Get RGB values of fromColor
int fromCountComponents = CGColorGetNumberOfComponents([fromColor CGColor]);
if (fromCountComponents == 4) {
const CGFloat *_components = CGColorGetComponents([fromColor CGColor]);
fromRed = _components[0];
fromGreen = _components[1];
fromBlue = _components[2];
fromAlpha = _components[3];
}
//Get RGB values for toColor
int toCountComponents = CGColorGetNumberOfComponents([toColor CGColor]);
if (toCountComponents == 4) {
const CGFloat *_components = CGColorGetComponents([toColor CGColor]);
toRed = _components[0];
toGreen = _components[1];
toBlue = _components[2];
toAlpha = _components[3];
}
//Now iterate through each pixel in the image..
for (int i = 0; i < bytesInContext; i += numComponents) {
//rgba value of current pixel..
redIn = (double)data[i]/255.0;
greenIn = (double)data[i+1]/255.0;
blueIn = (double)data[i+2]/255.0;
alphaIn = (double)data[i+3]/255.0;
//now you got current pixel rgb values...check it curresponds with your fromColor
if( redIn == fromRed && greenIn == fromGreen && blueIn == fromBlue ){
//image color matches fromColor, then change current pixel color to toColor
data[i] = toRed;
data[i+1] = toGreen;
data[i+2] = toBlue;
data[i+3] = toAlpha;
}
}
CGImageRef outImage = CGBitmapContextCreateImage(bitmapContext);
myImage = [UIImage imageWithCGImage:outImage];
CGImageRelease(outImage);
return myImage;
}
I hope you are not calling this function every time...It is a bit processor heavy..And if I was your processor, I wouldn't be happy with you..:)
I stumbled in this answer searching for replacing a color with another. Well, since that I need for Swift code, I have had several try and I find a nice solution. Thanks @Rob for its answer.
extension UIImageView {
@discardableResult func replace(color: UIColor, withColor replacingColor: UIColor) -> Bool {
guard let inputCGImage = self.image?.cgImage else {
return false
}
let colorSpace = CGColorSpaceCreateDeviceRGB()
let width = inputCGImage.width
let height = inputCGImage.height
let bytesPerPixel = 4
let bitsPerComponent = 8
let bytesPerRow = bytesPerPixel * width
let bitmapInfo = RGBA32.bitmapInfo
guard let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo) else {
print("unable to create context")
return false
}
context.draw(inputCGImage, in: CGRect(x: 0, y: 0, width: width, height: height))
guard let buffer = context.data else {
return false
}
let pixelBuffer = buffer.bindMemory(to: RGBA32.self, capacity: width * height)
let inColor = RGBA32(color: color)
let outColor = RGBA32(color: replacingColor)
for row in 0 ..< Int(height) {
for column in 0 ..< Int(width) {
let offset = row * width + column
if pixelBuffer[offset] == inColor {
pixelBuffer[offset] = outColor
}
}
}
guard let outputCGImage = context.makeImage() else {
return false
}
self.image = UIImage(cgImage: outputCGImage, scale: self.image!.scale, orientation: self.image!.imageOrientation)
return true
}
}
Where RGBA32 struct is simply:
struct RGBA32: Equatable {
private var color: UInt32
var redComponent: UInt8 {
return UInt8((self.color >> 24) & 255)
}
var greenComponent: UInt8 {
return UInt8((self.color >> 16) & 255)
}
var blueComponent: UInt8 {
return UInt8((self.color >> 8) & 255)
}
var alphaComponent: UInt8 {
return UInt8((self.color >> 0) & 255)
}
init(red: UInt8, green: UInt8, blue: UInt8, alpha: UInt8) {
self.color = (UInt32(red) << 24) | (UInt32(green) << 16) | (UInt32(blue) << 8) | (UInt32(alpha) << 0)
}
init(color: UIColor) {
let components = color.cgColor.components ?? [0.0, 0.0, 0.0, 1.0]
let colors = components.map { UInt8($0 * 255) }
self.init(red: colors[0], green: colors[1], blue: colors[2], alpha: colors[3])
}
static let bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Little.rawValue
static func ==(lhs: RGBA32, rhs: RGBA32) -> Bool {
return lhs.color == rhs.color
}
}
In this way , wherever in your code:
let imageView = UIImageView()
let image = UIImage(color: .red) // (*)
imageView.image = image
imageView.replace(color: .red, withColor: .green)
(*) creating image with color is explained here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With