图文/图像处理

iOS图片滤镜、饱和度等处理

2020-07-09  本文已影响0人  左方

1. 照片变黑白(遍历像素)

CGImageRef imageRef = self.imageView.image.CGImage;
    // 一个字节 = 8bit(位) 每行有 17152 个字节,即每行有 17152 * 8 个位   一个像素有 4 个字节
    size_t width = CGImageGetWidth(imageRef);
    size_t height = CGImageGetHeight(imageRef);
    size_t bitsPerComponent = CGImageGetBitsPerComponent(imageRef);
    size_t bytesPerRow = CGImageGetBytesPerRow(imageRef);
    // 颜色空间
    uint32_t bitmapInfo = CGImageGetBitmapInfo(imageRef);
    CGColorSpaceRef space = CGImageGetColorSpace(imageRef);
    
    //获取每个像素的字节数据集合
    CGDataProviderRef dataProviderRef = CGImageGetDataProvider(imageRef);
    CFDataRef dataRef = CGDataProviderCopyData(dataProviderRef);
    UInt8 * bytesPtr = CFDataGetMutableBytePtr((CFMutableDataRef)dataRef);
    NSUInteger length = CFDataGetLength(dataRef);
    
    // 一个像素由四个字节byte组成
    for (int i = 0; i < length; i += 4) {
        UInt8 red = bytesPtr[i];
        UInt8 green = bytesPtr[i + 1];
        UInt8 blue = bytesPtr[i + 2];
        UInt8 average = (red + green + blue) / 3;
        bytesPtr[i] = average;
        bytesPtr[i + 1] = average;
        bytesPtr[i + 2] = average;
    }
    
    CGContextRef imageContextRef = CGBitmapContextCreate(bytesPtr, width, height, bitsPerComponent, bytesPerRow, space, bitmapInfo);
    CGImageRef finalImageRef = CGBitmapContextCreateImage(imageContextRef);
    UIImage * finalImage = [UIImage imageWithCGImage:finalImageRef];
    self.imageView.image = finalImage;
    
    CGImageRelease(finalImageRef);
    CGContextRelease(imageContextRef);
    CFRelease(dataRef);

2. 照片饱和度调整

CIImage *beginImage = [CIImage imageWithCGImage:self.imageView.image.CGImage];
    CIFilter * filter = [CIFilter filterWithName:@"CIColorControls"];
    [filter setValue:beginImage forKey:kCIInputImageKey];
    //饱和度 0---2 默认为1
    [filter setValue:[NSNumber numberWithFloat:self.slider.value*2] forKey:@"inputSaturation"];
    
    // 得到过滤后的图片
    CIImage *outputImage = [filter outputImage];
    // 转换图片, 创建基于GPU的CIContext对象
    CIContext *context = [CIContext contextWithOptions: nil];
    CGImageRef cgimg = [context createCGImage:outputImage fromRect:[outputImage extent]];
    UIImage *newImg = [UIImage imageWithCGImage:cgimg];
    // 显示图片
    [self.imageView setImage:newImg];
    // 释放C对象
    CGImageRelease(cgimg);

3. 照片亮度调整

CIImage *beginImage = [CIImage imageWithCGImage:self.imageView.image.CGImage];
    CIFilter * filter = [CIFilter filterWithName:@"CIColorControls"];
    [filter setValue:beginImage forKey:kCIInputImageKey];
    //亮度 -1---1 默认为0
    [filter setValue:[NSNumber numberWithFloat:(self.slider.value-0.5)*2] forKey:@"inputBrightness"];
    
    // 得到过滤后的图片
    CIImage *outputImage = [filter outputImage];
    // 转换图片, 创建基于GPU的CIContext对象
    CIContext *context = [CIContext contextWithOptions: nil];
    CGImageRef cgimg = [context createCGImage:outputImage fromRect:[outputImage extent]];
    UIImage *newImg = [UIImage imageWithCGImage:cgimg];
    // 显示图片
    [self.imageView setImage:newImg];
    // 释放C对象
    CGImageRelease(cgimg);

4. 照片对比度调整

CIImage *beginImage = [CIImage imageWithCGImage:self.imageView.image.CGImage];
    CIFilter * filter = [CIFilter filterWithName:@"CIColorControls"];
    [filter setValue:beginImage forKey:kCIInputImageKey];
    //对比度 0---4 默认为1
    [filter setValue:[NSNumber numberWithFloat:self.slider.value*4.00f] forKey:@"inputContrast"];
    
    // 得到过滤后的图片
    CIImage *outputImage = [filter outputImage];
    // 转换图片, 创建基于GPU的CIContext对象
    CIContext *context = [CIContext contextWithOptions: nil];
    CGImageRef cgimg = [context createCGImage:outputImage fromRect:[outputImage extent]];
    UIImage *newImg = [UIImage imageWithCGImage:cgimg];
    // 显示图片
    [self.imageView setImage:newImg];
    // 释放C对象
    CGImageRelease(cgimg);

5. 照片添加纯色滤镜

UIGraphicsBeginImageContext(CGSizeMake(self.imageView.image.size.width, self.imageView.image.size.height));
    CGContextRef imageContextRef = UIGraphicsGetCurrentContext();
    [self.imageView.image drawInRect:CGRectMake(0, 0, self.imageView.image.size.width, self.imageView.image.size.height)];
    //红色滤镜
    UIColor *color = [UIColor clearColor];
    switch (self.segmentedControl.selectedSegmentIndex) {
        case 0://红
            color = [UIColor colorWithRed:1 green:0 blue:0 alpha:self.slider.value];
            break;
        case 1://绿
            color = [UIColor colorWithRed:0 green:1 blue:0 alpha:self.slider.value];
            break;
        case 2://蓝
            color = [UIColor colorWithRed:0 green:0 blue:1 alpha:self.slider.value];
            break;
        default:
            break;
    }
    // 给上下文设置颜色
    CGContextSetFillColorWithColor(imageContextRef, color.CGColor);
    // 设置渲染模式
    CGContextSetBlendMode(imageContextRef, kCGBlendModeNormal);
    // 填充上下文
    CGContextFillRect(imageContextRef, CGRectMake(0, 0, self.imageView.image.size.width, self.imageView.image.size.height));
    CGImageRef finalImageRef = CGBitmapContextCreateImage(imageContextRef);
    UIImage * finalImage = [UIImage imageWithCGImage:finalImageRef];
    self.imageView.image = finalImage;
    
    CGImageRelease(finalImageRef);
    CGContextRelease(imageContextRef);

6. 保存照片

// 2、获取PHContentEditingInput对象
    __weak typeof(self) weakSelf = self;
    PHContentEditingInputRequestOptions * requestOptions = [[PHContentEditingInputRequestOptions alloc] init];
    // 该方法只有在已经存在PHAdjustmentData的情况下才会被调用
    requestOptions.canHandleAdjustmentData = ^BOOL(PHAdjustmentData * _Nonnull adjustmentData) {
        NSLog(@"formatIdentifier:%@,formatVersion:%@", adjustmentData.formatIdentifier, adjustmentData.formatVersion);
        return YES;
    };
    [self.imgAsset requestContentEditingInputWithOptions:requestOptions completionHandler:^(PHContentEditingInput * _Nullable contentEditingInput, NSDictionary * _Nonnull info)
     {
        __strong typeof(weakSelf) self = weakSelf;
        // 3、创建PHAdjustmentdata,可以在data参数里设置要做的操作,比如过滤等,可以是一个序列串,但是这里的长度是有限制的
        PHAdjustmentData * adjustData = [[PHAdjustmentData alloc] initWithFormatIdentifier:self.imgAsset.localIdentifier formatVersion:@"1.0" data:[@"ceshi" dataUsingEncoding:NSUTF8StringEncoding]];
        // 4、初始化PHContentEditingOutput对象
        PHContentEditingOutput * output = [[PHContentEditingOutput alloc] initWithContentEditingInput:contentEditingInput];
        output.adjustmentData = adjustData;
        
        //⚠️这里为什么一定要用UIImageJPEGRepresentation才能成功,而UIImagePNGRepresentation会失败,生成的数据是正确的,但是相册相应的资源无法更新???
        // 因为这个和renderedContentURL有关,图片的输出只能是JPEG格式,video只能是.mov格式输出
        // 对于Live Photo,调用saveLivePhotoToOutput:options:completionHandler:方法保存和更新
        BOOL isSuccess = [UIImageJPEGRepresentation(self.imageView.image, 1) writeToURL:output.renderedContentURL atomically:NO];
        if (isSuccess) {
            NSLog(@"写入成功");
        } else {
            NSLog(@"写入失败");
        }
        // 5、赋值更新
        [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
            __strong typeof(weakSelf) self = weakSelf;
            // 使用PHAssetChangeRequest
            PHAssetChangeRequest * changeRequest = [PHAssetChangeRequest changeRequestForAsset: self.imgAsset];
            changeRequest.contentEditingOutput = output;
        } completionHandler:^(BOOL success, NSError * _Nullable error) {
            if (success) {
                NSLog(@"编辑内容成功");
            } else {
                NSLog(@"编辑内容失败:%@", error);
            }
        }];
    }];

1.CIImage

包含了创建图片的所有必要的数据,但其本身没有渲染成图片,它代表的是图像数据或者生成图像数据的流程(如滤镜);
CIImage类用于描述一张图片. CoreImage的图片是不可变的. 通过将CIImage对象与其它Core Image的类(比如CIFilter, CIContext, CIVector, 和CIColor)结合, 实现利用Core Image内建的滤镜来进行图片处理. 根据多种来源提供的数据来创建CIImage对象, 包括Quartz 2D, Core Video图像缓存(CVImageBufferRef), 基于URL的对象, 和NSData对象.
尽管CIImage对象拥有与之关联的图片数据, 但本质上并不是一张图片. 你可以它CIImage对象为一个图片的"配方". CIImage对象拥有生成一张图片所具备的所有信息, 但Core Image并不会真正的去渲染一张图片, 除非被要求这么做. 这种"延迟计算(lzay evaluation)"方式让Core Image的操作尽可能的高效.
Core Image提供了为图片分析常见缺陷并自动调整修复的方法. 提供一系列用来纠正这些不足的滤镜. 通过为滤镜预设相关值, 实现如变更色调, 饱合度, 对比度, 阴影, 去除红眼或其它闪光伪迹, 来提高图片的质量.

2.CGImage

是基于像素的矩阵,每个点都对应了图片中点的像素信息;
CGImageRef是一种基于你所提供的样本数据来表示位图(Bitmap Image)和位图遮罩(Bitmap Image Masks)的具体类型. 位图(样本)是像素的矩形阵列(Rectangular Array), 每个像素表示源图中的每个点的数据或样本.

3.UIImage

管理图片数据,主要用来展现,如 UIImageView 中,控件中等,也可以用来直接在 view 或其他的 context 中绘制。 使用Image对象来表示所有类型图片的数据, UIImage类具有管理相关平台支持的所有格式图片数据的能力. Image对象是不可修改的, 因此你总是通过已经存在的图片数据来创建它, 比如保存在硬件中的图片文件或通过编程创建的图片数据. 一个Image对象包含单个图片或你要用作动画的一系列图片.

4. PHAsset

代表着由 iPhone 相册 app 管理的视频和图片对象。ALAsset 在 iOS9.0 版本已经被弃用,PHAsset 是 ALAsset 的替代。和手机相册(Photos)进行的交互,比如选择图片上传,都会涉及到 ALAsset/PHAsset 相关的概念。
LivePhoto 是在 iPhone6s 及更新的设备上用相机拍摄的一张照片,其特点是包含了照片拍摄时刻之前和之后几秒钟的视频(拍摄 LivePhoto 需要 iPhone6s 及更新的设备;LivePhoto 的操作和播放只需要安装了 iOS9.1 及以上系统版本的 iPhone 即可),LivePhoto 不是一种新文件格式,只是一种特别的 PHAsset。

4.1PHAdjustmentData

当修改了一个asset后,Photos会将PHAdjustmentData对象和修改过的图片或者视频数据一起保存起来,你可以通过这个对象提供的一些数据来修改已经保存的编辑。

4.2PHPhotoLibrary

提供对用户照片库中的照片、视频和相关内容的元数据和图像数据的访问,包括来自摄像机卷、iCloud共享、照片流、从iTunes导入和同步的内容。

参考资料:
https://www.jianshu.com/p/4e6a4ae53e92 iOS 渲染图片 CIFilter
https://www.jianshu.com/p/40f3c6e02061 PHAsset的增删改查
https://www.jianshu.com/p/5f87d40fd42a 离屏渲染及图片压缩、滤镜等原理解析
https://www.jianshu.com/p/aa2557d977ba UIImage, CGImageRef, CIImage
https://www.jianshu.com/p/1b110d0c6946 Photos中常用类(获取展示功能相关)简介

上一篇下一篇

猜你喜欢

热点阅读