UIImageの色を変更しようとしています。私のコード:
-(UIImage *)coloredImage:(UIImage *)firstImage withColor:(UIColor *)color {
UIGraphicsBeginImageContext(firstImage.size);
CGContextRef context = UIGraphicsGetCurrentContext();
[color setFill];
CGContextTranslateCTM(context, 0, firstImage.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextSetBlendMode(context, kCGBlendModeCopy);
CGRect rect = CGRectMake(0, 0, firstImage.size.width, firstImage.size.height);
CGContextDrawImage(context, rect, firstImage.CGImage);
CGContextClipToMask(context, rect, firstImage.CGImage);
CGContextAddRect(context, rect);
CGContextDrawPath(context,kCGPathElementMoveToPoint);
UIImage *coloredImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return coloredImg;
}
このコードは機能しますが、取得された画像はそれほど良くありません:返された画像の境界ピクセルは断続的であり、最初の画像ほど滑らかではありません。この問題を解決するにはどうすればよいですか?
IOS 7以降、これが最も簡単な方法です。
Objective-C:
theImageView.image = [theImageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[theImageView setTintColor:[UIColor redColor]];
Swift 2.0:
theImageView.image = theImageView.image?.imageWithRenderingMode(.AlwaysTemplate)
theImageView.tintColor = UIColor.magentaColor()
Swift 4.0:
theImageView.image = theImageView.image?.withRenderingMode(.alwaysTemplate)
theImageView.tintColor = .Magenta
ストーリーボード:
最初にアセット内のテンプレート(右のバー-としてレンダリング)として画像を構成します。その場合、画像の色は適用された色合いになります。
これはほとんど上記の答えですが、わずかに短縮されています。これは画像をマスクとしてのみ使用し、実際に画像を「乗算」または色付けしません。
目標C:
UIColor *color = <# UIColor #>;
UIImage *image = <# UIImage #>;// Image to mask with
UIGraphicsBeginImageContextWithOptions(image.size, NO, image.scale);
CGContextRef context = UIGraphicsGetCurrentContext();
[color setFill];
CGContextTranslateCTM(context, 0, image.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextClipToMask(context, CGRectMake(0, 0, image.size.width, image.size.height), [image CGImage]);
CGContextFillRect(context, CGRectMake(0, 0, image.size.width, image.size.height));
UIImage *coloredImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
迅速:
let color: UIColor = <# UIColor #>
let image: UIImage = <# UIImage #> // Image to mask with
UIGraphicsBeginImageContextWithOptions(image.size, false, image.scale)
let context = UIGraphicsGetCurrentContext()
color.setFill()
context?.translateBy(x: 0, y: image.size.height)
context?.scaleBy(x: 1.0, y: -1.0)
context?.clip(to: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height), mask: image.cgImage!)
context?.fill(CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height))
let coloredImg = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
画像に色を付ける別の方法は、単純に一定の色を掛けることです。黒い領域の色の値を「持ち上げない」ため、これが望ましい場合があります。画像内の相対的な強度を同じに保ちます。オーバーレイを色合いとして使用すると、コントラストが平らになる傾向があります。
これは私が使用するコードです:
UIImage *MultiplyImageByConstantColor( UIImage *image, UIColor *color ) {
CGSize backgroundSize = image.size;
UIGraphicsBeginImageContext(backgroundSize);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGRect backgroundRect;
backgroundRect.size = backgroundSize;
backgroundRect.Origin.x = 0;
backgroundRect.Origin.y = 0;
CGFloat r,g,b,a;
[color getRed:&r green:&g blue:&b alpha:&a];
CGContextSetRGBFillColor(ctx, r, g, b, a);
CGContextFillRect(ctx, backgroundRect);
CGRect imageRect;
imageRect.size = image.size;
imageRect.Origin.x = (backgroundSize.width - image.size.width)/2;
imageRect.Origin.y = (backgroundSize.height - image.size.height)/2;
// Unflip the image
CGContextTranslateCTM(ctx, 0, backgroundSize.height);
CGContextScaleCTM(ctx, 1.0, -1.0);
CGContextSetBlendMode(ctx, kCGBlendModeMultiply);
CGContextDrawImage(ctx, imageRect, image.CGImage);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Swiftバージョン
extension UIImage{
static func multiplyImageByConstantColor(image:UIImage,color:UIColor)->UIImage{
let backgroundSize = image.size
UIGraphicsBeginImageContext(backgroundSize)
let ctx = UIGraphicsGetCurrentContext()
var backgroundRect=CGRect()
backgroundRect.size = backgroundSize
backgroundRect.Origin.x = 0
backgroundRect.Origin.y = 0
var r:CGFloat
var g:CGFloat
var b:CGFloat
var a:CGFloat
color.getRed(&r, green: &g, blue: &b, alpha: &a)
CGContextSetRGBFillColor(ctx, r, g, b, a)
CGContextFillRect(ctx, backgroundRect)
var imageRect=CGRect()
imageRect.size = image.size
imageRect.Origin.x = (backgroundSize.width - image.size.width)/2
imageRect.Origin.y = (backgroundSize.height - image.size.height)/2
// Unflip the image
CGContextTranslateCTM(ctx, 0, backgroundSize.height)
CGContextScaleCTM(ctx, 1.0, -1.0)
CGContextSetBlendMode(ctx, .Multiply)
CGContextDrawImage(ctx, imageRect, image.CGImage)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
}
Swift 3.0の場合
imageView.image? = (imageView.image?.withRenderingMode(.alwaysTemplate))!
imageView.tintColor = UIColor.Magenta
In Swift 2.
yourImage.image? = (yourImage.image?.imageWithRenderingMode(.AlwaysTemplate))!
yourImage.tintColor = UIColor.magentaColor()
Swiftパイオニアをお楽しみください
Swift 4.2ソリューション
extension UIImage {
func withColor(_ color: UIColor) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, false, scale)
guard let ctx = UIGraphicsGetCurrentContext(), let cgImage = cgImage else { return self }
color.setFill()
ctx.translateBy(x: 0, y: size.height)
ctx.scaleBy(x: 1.0, y: -1.0)
ctx.clip(to: CGRect(x: 0, y: 0, width: size.width, height: size.height), mask: cgImage)
ctx.fill(CGRect(x: 0, y: 0, width: size.width, height: size.height))
guard let colored = UIGraphicsGetImageFromCurrentImageContext() else { return self }
UIGraphicsEndImageContext()
return colored
}
}
// Usage:
// let redImage = UIImage().withColor(.red)
これが、@ Annaの答えの私の適応です。ここで2つの重要なポイント:
destinationIn
ブレンドモードを使用UIGraphicsBeginImageContextWithOptions(backgroundSize, false, UIScreen.main.scale)
を呼び出して、滑らかな画像を取得しますSwiftのコードイン:
extension UIImage {
static func coloredImage(image: UIImage?, color: UIColor) -> UIImage? {
guard let image = image else {
return nil
}
let backgroundSize = image.size
UIGraphicsBeginImageContextWithOptions(backgroundSize, false, UIScreen.main.scale)
let ctx = UIGraphicsGetCurrentContext()!
var backgroundRect=CGRect()
backgroundRect.size = backgroundSize
backgroundRect.Origin.x = 0
backgroundRect.Origin.y = 0
var r:CGFloat = 0
var g:CGFloat = 0
var b:CGFloat = 0
var a:CGFloat = 0
color.getRed(&r, green: &g, blue: &b, alpha: &a)
ctx.setFillColor(red: r, green: g, blue: b, alpha: a)
ctx.fill(backgroundRect)
var imageRect = CGRect()
imageRect.size = image.size
imageRect.Origin.x = (backgroundSize.width - image.size.width) / 2
imageRect.Origin.y = (backgroundSize.height - image.size.height) / 2
// Unflip the image
ctx.translateBy(x: 0, y: backgroundSize.height)
ctx.scaleBy(x: 1.0, y: -1.0)
ctx.setBlendMode(.destinationIn)
ctx.draw(image.cgImage!, in: imageRect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
}
@Annaの答えに基づいて、Swift 2.2に書き換えて、アルファチャネルを使用して画像を処理します。
static func multiplyImageByConstantColor(image:UIImage,color:UIColor)->UIImage{
let backgroundSize = image.size
UIGraphicsBeginImageContext(backgroundSize)
let ctx = UIGraphicsGetCurrentContext()
var backgroundRect=CGRect()
backgroundRect.size = backgroundSize
backgroundRect.Origin.x = 0
backgroundRect.Origin.y = 0
var r:CGFloat = 0
var g:CGFloat = 0
var b:CGFloat = 0
var a:CGFloat = 0
color.getRed(&r, green: &g, blue: &b, alpha: &a)
CGContextSetRGBFillColor(ctx, r, g, b, a)
// Unflip the image
CGContextTranslateCTM(ctx, 0, backgroundSize.height)
CGContextScaleCTM(ctx, 1.0, -1.0)
CGContextClipToMask(ctx, CGRectMake(0, 0, image.size.width, image.size.height), image.CGImage);
CGContextFillRect(ctx, backgroundRect)
var imageRect=CGRect()
imageRect.size = image.size
imageRect.Origin.x = (backgroundSize.width - image.size.width)/2
imageRect.Origin.y = (backgroundSize.height - image.size.height)/2
CGContextSetBlendMode(ctx, .Multiply)
CGContextDrawImage(ctx, imageRect, image.CGImage)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
アンナの素晴らしいコードのSwift 3.0バージョン:
extension UIImage{
static func multiplyImageByConstantColor(image:UIImage,color:UIColor)-> UIImage {
let backgroundSize = image.size
UIGraphicsBeginImageContext(backgroundSize)
let ctx = UIGraphicsGetCurrentContext()!
var backgroundRect=CGRect()
backgroundRect.size = backgroundSize
backgroundRect.Origin.x = 0
backgroundRect.Origin.y = 0
let myFloatForR = 0
var r = CGFloat(myFloatForR)
let myFloatForG = 0
var g = CGFloat(myFloatForG)
let myFloatForB = 0
var b = CGFloat(myFloatForB)
let myFloatForA = 0
var a = CGFloat(myFloatForA)
color.getRed(&r, green: &g, blue: &b, alpha: &a)
ctx.setFillColor(red: r, green: g, blue: b, alpha: a)
ctx.fill(backgroundRect)
var imageRect=CGRect()
imageRect.size = image.size
imageRect.Origin.x = (backgroundSize.width - image.size.width)/2
imageRect.Origin.y = (backgroundSize.height - image.size.height)/2
// Unflip the image
ctx.translateBy(x: 0, y: backgroundSize.height)
ctx.scaleBy(x: 1.0, y: -1.0)
ctx.setBlendMode(.multiply)
ctx.draw(image.cgImage!, in: imageRect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
}
Annaのコードは、kCGBlendModeMultiplyではなくkCGBlendModeNormalを使用して、色付きの.image背景にUIImage.imageをコピーするのに適しています。たとえば、self.mainImage.image = [self NormalImageByConstantColor: self.mainImage.image withColor: yourColor];
は、mainColor.imageのコンテンツを、yourColorの不透明度を保持しながら、色相yourColorの上に配置します。これにより、カメラロールに保存する画像の背後に不透明度のある背景色を配置するという問題が解決しました。
スウィフト3:
extension UIImage{
static func multiplyImageByConstantColor(image:UIImage,color:UIColor) -> UIImage{
let backgroundSize = image.size
UIGraphicsBeginImageContext(backgroundSize)
guard let ctx = UIGraphicsGetCurrentContext() else {return image}
var backgroundRect=CGRect()
backgroundRect.size = backgroundSize
backgroundRect.Origin.x = 0
backgroundRect.Origin.y = 0
var r:CGFloat = 0
var g:CGFloat = 0
var b:CGFloat = 0
var a:CGFloat = 0
color.getRed(&r, green: &g, blue: &b, alpha: &a)
ctx.setFillColor(red: r, green: g, blue: b, alpha: a)
// Unflip the image
ctx.translateBy(x: 0, y: backgroundSize.height)
ctx.scaleBy(x: 1.0, y: -1.0)
ctx.clip(to: CGRect(0, 0, image.size.width, image.size.height), mask: image.cgImage!)
ctx.fill(backgroundRect)
var imageRect=CGRect()
imageRect.size = image.size
imageRect.Origin.x = (backgroundSize.width - image.size.width)/2
imageRect.Origin.y = (backgroundSize.height - image.size.height)/2
ctx.setBlendMode(.multiply)
ctx.draw(image.cgImage!, in: imageRect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
}
iOS 1から開始して、UIGraphicsImageRenderer
を使用できます。
extension UIImage {
func colored(_ color: UIColor) -> UIImage {
let renderer = UIGraphicsImageRenderer(size: size)
return renderer.image { context in
color.setFill()
self.draw(at: .zero)
context.fill(CGRect(x: 0, y: 0, width: size.width, height: size.height), blendMode: .sourceAtop)
}
}
}