iOS开发-修改图片的HSB(HSV)值

HSB是什么?

HSB等于HSV,是一种圆形的颜色空间,H代表色调,S代表饱和度,B(V)代表明度。

修改HSV的值

修改图片的HSB值来改变图片整体颜色效果,解决方案如下:

  1. 遍历图片所有像素,获取每个像素的RGB值
  2. 将RGB值转换为HSB值来做修改
  3. 将HSB值转换为RGB值,赋值
// Category方法
// 3个入参均为偏移量,传0-360之间的正整数,默认传0。
- (UIImage *)changeImageWithHueOffset:(CGFloat)hueOffset saturationOffset:(CGFloat)saturationOffset brightnessOffset:(CGFloat)brightnessOffset {
CGImageRef image = self.CGImage;
size_t width = CGImageGetWidth(image);
size_t height = CGImageGetHeight(image);
unsigned char *data = calloc(width * height * 4, sizeof(unsigned char)); // 取图片首地址
size_t bitsPerComponent = 8; // r g b a 每个component bits数目
size_t bytesPerRow = width * 4; // 一张图片每行字节数目 (每个像素点包含r g b a 四个字节)
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); // 创建rgb颜色空间
CGContextRef context = CGBitmapContextCreate(data,width,height,bitsPerComponent,bytesPerRow,space,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);
for (size_t i = 0; i < height; i++) {
for (size_t j = 0; j < width; j++) {
size_t pixelIndex = i * width * 4 + j * 4;
unsigned char red = data[pixelIndex];
unsigned char green = data[pixelIndex + 1];
unsigned char blue = data[pixelIndex + 2];
unsigned char a = data[pixelIndex + 3];
if (a == 0) { // 不处理透明通道
continue;
}
// 修改颜色
// RGB转HSV
UIColor *color = [[UIColor alloc] initWithRed:red green:green blue:blue alpha:a];
CGFloat hue;
CGFloat saturation;
CGFloat brightness;
CGFloat alpha;
BOOL success = [color getHue:&hue saturation:&saturation brightness:&brightness alpha:&alpha];
if (success) {
// 修改HSV
CGFloat (^block)(CGFloat, CGFloat) = ^(CGFloat value, CGFloat offset) {
if (offset) {
value = value * 360 + offset;
if (value > 360) {
value = value - 360;
}
value = value / 360;
}
return value;
};
hue = block(hue, hueOffset);
saturation = block(saturation, saturationOffset);
brightness = block(brightness, brightnessOffset);

// HSV转RGB
color = [UIColor colorWithHue:hue saturation:saturation brightness:brightness alpha:alpha];
CGFloat red;
CGFloat green;
CGFloat blue;
BOOL success = [color getRed:&red green:&green blue:&blue alpha:&alpha];
if (success) {
data[pixelIndex] = red;
data[pixelIndex + 1] = green;
data[pixelIndex + 2] = blue;
continue;
}
}
data[pixelIndex] = red;
data[pixelIndex + 1] = green;
data[pixelIndex + 2] = blue;
}
}
image = CGBitmapContextCreateImage(context);
return [UIImage imageWithCGImage:image];
}

注意此处3个入参均为偏移量,传0-360之间的正整数,默认传0,通常只需要修改hue的值就可以达到整体换色的目的了。

因为HSV是圆形的颜色空间,所以可以理解为什么是X/360。
此方案可稍作修改即可实现修改像素的RGB值或者其他颜色值。


如果不要求修改HSB,用drawInRect来合成图层就可以简单的实现更换颜色,在这里也做个记录。

- (UIImage *)imageWithTintColor:(UIColor *)tintColor blendMode:(CGBlendMode)blendMode {
UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f);
[tintColor setFill];
CGRect bounds = CGRectMake(0, 0, self.size.width, self.size.height);
UIRectFill(bounds);

// 绘图-合成图片使用kCGBlendModeMultiply
[self drawInRect:bounds blendMode:blendMode alpha:1.0f];

// 去除透明通道
if (blendMode != kCGBlendModeDestinationIn) {
[self drawInRect:bounds blendMode:kCGBlendModeDestinationIn alpha:1.0f];
}

UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return tintedImage;
}

这里使用了两次drawInRect,因为不同的blendMode有着不同的效果,第二次的blendMode使用了kCGBlendModeDestinationIn是为了保留原图的透明图层,我们只需要在第一次使用kCGBlendModeMultiply就可以达到混合图层的目的。还有很多其他的blendMode可以自行去测试显示效果。