Iphone 如何更改UIImage的饱和度?
我有一张UIImage,想把它的饱和度调整到+10%左右。有没有标准的方法或函数可以用于此目的?没有那么简单的。最简单的解决方案可能是使用已知像素格式创建内存中的CGContext,将图像绘制到该上下文中,然后读取/修改已知格式缓冲区中的像素 我认为CG不支持带有独立饱和度通道的颜色空间,因此您必须将RGB转换为HSV或HSL,或者直接在RGB空间中进行计算Iphone 如何更改UIImage的饱和度?,iphone,cocoa-touch,uikit,core-graphics,Iphone,Cocoa Touch,Uikit,Core Graphics,我有一张UIImage,想把它的饱和度调整到+10%左右。有没有标准的方法或函数可以用于此目的?没有那么简单的。最简单的解决方案可能是使用已知像素格式创建内存中的CGContext,将图像绘制到该上下文中,然后读取/修改已知格式缓冲区中的像素 我认为CG不支持带有独立饱和度通道的颜色空间,因此您必须将RGB转换为HSV或HSL,或者直接在RGB空间中进行计算 直接在RGB中进行计算的一种方法可能如下所示: average = (R + G + B) / 3; red_delta = (R -
直接在RGB中进行计算的一种方法可能如下所示:
average = (R + G + B) / 3;
red_delta = (R - average) * 11 / 10;
green_delta = (G - average) * 11 / 10;
blue_delta = (B - average) * 11 / 10;
R = average + red_delta;
G = average + green_delta;
B = average + blue_delta;
// clip R,G,B to be in 0-255 range
这将使远离平均值的通道进一步移动约10%。这几乎就像增加饱和度一样,尽管它会使某些颜色的色调发生变化 从基于视图的应用程序模板开始,创建UIView的新子类,如下所示:
// header file
@interface DesatView : UIView {
UIImage *image;
float saturation;
}
@property (nonatomic, retain) UIImage *image;
@property (nonatomic) float desaturation;
@end
// implementation file
#import "DesatView.h"
@implementation DesatView
@synthesize image, desaturation;
-(void)setSaturation:(float)sat;
{
saturation = sat;
[self setNeedsDisplay];
}
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.backgroundColor = [UIColor clearColor]; // else background is black
desaturation = 0.0; // default is no effect
}
return self;
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0.0, self.bounds.size.height); // flip image right side up
CGContextScaleCTM(context, 1.0, -1.0);
CGContextDrawImage(context, rect, self.image.CGImage);
CGContextSetBlendMode(context, kCGBlendModeSaturation);
CGContextClipToMask(context, self.bounds, image.CGImage); // restricts drawing to within alpha channel
CGContextSetRGBFillColor(context, 0.0, 0.0, 0.0, desaturation);
CGContextFillRect(context, rect);
CGContextRestoreGState(context); // restore state to reset blend mode
}
@end
现在,在视图控制器的viewDidLoad方法中,将视图置于屏幕上,并按如下方式设置其饱和度:
- (void)viewDidLoad {
[super viewDidLoad];
DesatView *dv = [[DesatView alloc] initWithFrame:CGRectZero];
dv.image = [UIImage imageNamed:@"someImage.png"];
dv.frame = CGRectMake(0, 0, dv.image.size.width, dv.image.size.height);
dv.center = CGPointMake(160, 240); // put it mid-screen
dv.desaturation = 0.2; // desaturate by 20%,
[self.view addSubview:dv]; // put it on screen
}
dv.saturation = 0.8; // desaturate by 80%
按如下方式更改饱和度:
- (void)viewDidLoad {
[super viewDidLoad];
DesatView *dv = [[DesatView alloc] initWithFrame:CGRectZero];
dv.image = [UIImage imageNamed:@"someImage.png"];
dv.frame = CGRectMake(0, 0, dv.image.size.width, dv.image.size.height);
dv.center = CGPointMake(160, 240); // put it mid-screen
dv.desaturation = 0.2; // desaturate by 20%,
[self.view addSubview:dv]; // put it on screen
}
dv.saturation = 0.8; // desaturate by 80%
显然,如果您想在单个方法之外使用它,那么应该将dv设置为视图控制器的ivar。希望这能有所帮助。这里是Bessey hack的一个实现(将此代码放入UIImage类别中)。它的速度不快,而且它肯定会改变颜色,但它有点有效
+ (CGFloat) clamp:(CGFloat)pixel
{
if(pixel > 255) return 255;
else if(pixel < 0) return 0;
return pixel;
}
- (UIImage*) saturation:(CGFloat)s
{
CGImageRef inImage = self.CGImage;
CFDataRef ref = CGDataProviderCopyData(CGImageGetDataProvider(inImage));
UInt8 * buf = (UInt8 *) CFDataGetBytePtr(ref);
int length = CFDataGetLength(ref);
for(int i=0; i<length; i+=4)
{
int r = buf[i];
int g = buf[i+1];
int b = buf[i+2];
CGFloat avg = (r + g + b) / 3.0;
buf[i] = [UIImage clamp:(r - avg) * s + avg];
buf[i+1] = [UIImage clamp:(g - avg) * s + avg];
buf[i+2] = [UIImage clamp:(b - avg) * s + avg];
}
CGContextRef ctx = CGBitmapContextCreate(buf,
CGImageGetWidth(inImage),
CGImageGetHeight(inImage),
CGImageGetBitsPerComponent(inImage),
CGImageGetBytesPerRow(inImage),
CGImageGetColorSpace(inImage),
CGImageGetAlphaInfo(inImage));
CGImageRef img = CGBitmapContextCreateImage(ctx);
CFRelease(ref);
CGContextRelease(ctx);
return [UIImage imageWithCGImage:img];
}
这有一个CoreImage过滤器<代码>颜色控制 只需将
inputstation
设置为<1.0以降低饱和度,或设置为>1.0以增加饱和度
下面是我在UIImage
的一个类别中添加的一个方法,用于对图像进行去饱和
-(UIImage*) imageDesaturated {
CIContext *context = [CIContext contextWithOptions:nil];
CIImage *ciimage = [CIImage imageWithCGImage:self.CGImage];
CIFilter *filter = [CIFilter filterWithName:@"CIColorControls"];
[filter setValue:ciimage forKey:kCIInputImageKey];
[filter setValue:@0.0f forKey:kCIInputSaturationKey];
CIImage *result = [filter valueForKey:kCIOutputImageKey];
CGImageRef cgImage = [context createCGImage:result fromRect:[result extent]];
UIImage *image = [UIImage imageWithCGImage:cgImage];
CGImageRelease(cgImage);
return image;
}
我刚刚测试了Mike Pollard的方法,它是正确的 这是swift 3的版本
let ciimage = CIImage.init(cgImage: self.givenImage.cgImage)
let filter = CIFilter.init(name: "CIColorControls")
filter?.setValue(ciimage, forKey: kCIInputImageKey)
filter?.setValue(0.0, forKey: kCIInputSaturationKey)
let result = filter?.value(forKey: kCIOutputImageKey) as! CIImage
let cgimage = CIContext.init(options: nil).createCGImage(result, from: result.extent)
let image = UIImage.init(cgImage: cgimage!)
斯威夫特5
为什么不直接调用setter中的[self setNeedsDisplay]进行去饱和呢?我的大脑出于某种未知的原因避免覆盖合成setter,但你是对的。我会改变答案。这会降低饱和度,你会怎样增加饱和度?+1。我认为这可能会泄漏
cgImage
,尽管插入了CFAutorelease(cgImage)在返回之前
应该解决这个问题。您还可以使用kCIInputImageKey
和kciinputstationkey
而不是@“inputImage”和@“inputstation”
,以及@0.0f
而不是[NSNumber numberWithFloat:0.0f]
。迈克,我建议您使用UIImage*image=[UIImage imageWithCGImage:cgImage比例:self.scale方向:self.imageOrientation]
因为它可以确保保持原始图像的比例和方向,这在处理视网膜设备时尤为重要。虽然这样做有效,但实际上需要大量处理!确保在调度线程上执行此操作。这对jpg图像很好,但对png图像不起作用。请不要发布相同的答案。相反,旗为duplicate@Jean-弗朗索瓦·法布仔细看,它并不完全相同