Оттенок инвертирует цвета в Swift
Я пробую этот код, чтобы подкрасить цвет UIImage, но кажется, что он инвертирует цвета - окрашивая фон и превращая черный штрих в белый.
Как сделать так, чтобы он закрасил черные линии обводки изображения и оставил белый фон в покое? Вот пример детской площадки, где я пробую одну технику, а также другую, предложенную первым ответом.
Код детской площадки
extension UIImage {
func tint(color: UIColor, blendMode: CGBlendMode = CGBlendMode.Normal) -> UIImage
{
UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale);
let context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0, self.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextSetBlendMode(context, blendMode);
let rect = CGRectMake(0, 0, self.size.width, self.size.height);
CGContextClipToMask(context, rect, self.CGImage);
color.setFill()
CGContextFillRect(context, rect);
let newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
func tint2(color: UIColor, blendMode: CGBlendMode) -> UIImage
{
let drawRect = CGRectMake(0.0, 0.0, size.width, size.height)
UIGraphicsBeginImageContextWithOptions(size, false, scale)
let context = UIGraphicsGetCurrentContext()
CGContextClipToMask(context, drawRect, CGImage)
color.setFill()
UIRectFill(drawRect)
drawInRect(drawRect, blendMode: blendMode, alpha: 1.0)
let tintedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return tintedImage
}
}
let stringUrl = "https://s3.amazonaws.com/neighbor-chat-assets/icons/avatar1000.png"
let url = NSURL(string: stringUrl)
let data = NSData(contentsOfURL: url!)
var originalimage = UIImage(data: data!)
var image = originalimage!.imageWithRenderingMode(.AlwaysTemplate).tint(UIColor.blueColor(), blendMode:.Normal)
var image2 = originalimage!.imageWithRenderingMode(.AlwaysTemplate).tint2(UIColor.blueColor(), blendMode:.Normal)
1 ответ
Это должно работать, я только что проверил с png и прозрачным фоном
func tint(color: UIColor, blendMode: CGBlendMode = CGBlendMode.Normal) -> UIImage
{
UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale);
let context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0, self.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextSetBlendMode(context, blendMode);
let rect = CGRectMake(0, 0, self.size.width, self.size.height);
CGContextClipToMask(context, rect, self.CGImage);
color.setFill()
CGContextFillRect(context, rect);
let newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Также см. Этот пост для получения дополнительной информации. В качестве альтернативы можно заключить ваше изображение в UIImageView в режиме рендеринга UIImageRenderingMode.AlwaysTemplate, а затем установить свойство tintColor.
РЕДАКТИРОВАТЬ
Так что это функция, которую вы можете использовать, чтобы сначала замаскировать определенные цвета, если у вас нет альфа-канала в изображении
func tint(color: UIColor, blendMode: CGBlendMode = CGBlendMode.Normal, colorToMask: UIColor = UIColor.blackColor()) -> UIImage
{
var fRed : CGFloat = 0
var fGreen : CGFloat = 0
var fBlue : CGFloat = 0
var fAlpha: CGFloat = 0
colorToMask.getRed(&fRed, green: &fGreen, blue: &fBlue, alpha: &fAlpha)
let rect = CGRectMake(0, 0, self.size.width, self.size.height);
var colorMasking : [CGFloat] = [fRed,fRed,fGreen,fGreen,fBlue,fBlue]
let newImageRef = CGImageCreateWithMaskingColors(self.CGImage!, &colorMasking)
UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale);
let context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0, self.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextSetBlendMode(context, blendMode);
CGContextClipToMask(context, rect, newImageRef!);
color.setFill()
CGContextFillRect(context, rect);
let newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Эта функция сначала создает маску в зависимости от указанного цвета и обрезает контекст этой маски.
РЕДАКТИРОВАТЬ № 2
Как указано в комментариях, мне также не удалось замаскировать белый цвет, я пробовал значения UInt8 (т.е. 255) и значения с плавающей запятой (то есть 1,0), но это все равно не работало. Поэтому единственное решение, которое я мог придумать, - это инвертировать изображение. Вот функция:
func negativeImage() -> UIImage {
let coreImage = MYImage(CGImage: self.CGImage!)
let filter = CIFilter(name: "CIColorInvert", withInputParameters: ["inputImage" : coreImage])!
let result = filter.outputImage!
let context = CIContext(options:nil)
let cgimg : CGImageRef = context.createCGImage(result, fromRect: result.extent)
let bmpcontext = CGBitmapContextCreate(nil, Int(self.size.width), Int(self.size.height), 8, Int(self.size.width)*4, CGColorSpaceCreateDeviceRGB(),CGImageAlphaInfo.NoneSkipLast.rawValue)
CGContextDrawImage(bmpcontext, CGRectMake(0, 0, self.size.width, self.size.height), cgimg)
let newImgRef = CGBitmapContextCreateImage(bmpcontext)!
return UIImage(CGImage: newImgRef)
}
Вы можете использовать это так
var image : UIImage = ...
image = image.negativeImage()
image = image.tint(UIColor.redColor())
Вот некоторые общие замечания
CGImageCreateWithMaskingColors
требует CGImage без альфа-канала, поэтому я использую флагCGImageAlphaInfo.NoneSkipLast
в функции absoluteImage, чтобы снова удалить альфа-канал- В этом нет абсолютно никакой проверки ошибок, вы должны по крайней мере проверить, есть ли альфа-канал, включенный в функцию оттенка, используя
CGImageGetAlphaInfo
- Вы можете либо сделать замаскированные части (в нашем примере белым) прозрачными (установив false в
UIGraphicsBeginImageContextWithOptions
команда в функции оттенка), или определенный цвет, установив значение true, которое по умолчанию является черным (вам придется рисовать перед обрезкой по маске).