应用CIFilter后设置UIImageView的内容模式

12
感谢您的关注。
这是我的代码。
 CIImage *result = _vignette.outputImage;
self.mainImageView.image = nil;
//self.mainImageView.contentMode = UIViewContentModeScaleAspectFit;
self.mainImageView.image = [UIImage imageWithCIImage:result];
self.mainImageView.contentMode = UIViewContentModeScaleAspectFit;

这里的_vignette正确设置了过滤器,图像效果也正确应用到了图像上。

我正在使用分辨率为500x375的源图像。我的imageView几乎具有iPhone屏幕的分辨率。因此,为了避免拉伸,我使用AspectFit。

但是,在应用效果后,当我将结果图像重新分配回我的imageView时,它会被拉伸。无论我使用哪种UIViewContentMode都不起作用。似乎它总是使用ScaleToFill,而不考虑我给出的滤镜。

为什么会发生这种情况?任何建议都将不胜感激。


基本上是复制了https://dev59.com/fWox5IYBdhLWcg3wnVey的内容。 - matt
3个回答

24

(1) Aspect Fit会拉伸图像以适应尺寸。如果您不想使图像被拉伸,可以使用Center。

(2) 使用imageWithCIImage会得到一个非常奇怪的UIImage,它不是基于CGImage的,因此不受正常图层显示规则的影响。 它实际上只是CIImage的一个薄包装器,这不是你想要的。 您必须通过CGImage将CIFilter输出转换(渲染)为UIImage,从而为您提供实际具有一些位(CGImage,位图)的UIImage。 我在这里的讨论提供了演示代码:

http://www.apeth.com/iOSBook/ch15.html#_cifilter_and_ciimage

换句话说,在某个时刻,您必须调用CIContext createCGImage:fromRect:从您的CIFilter输出中生成一个CGImageRef,并将其传递给UIImage。 在执行此操作之前,您没有真正的UIImage作为滤镜操作的输出。

或者,您可以将从imageWithCIImage获取的图像绘制到图形上下文中。 例如,您可以将其绘制到图像图形上下文中,然后使用图像。

不能直接显示从imageWithCIImage获取的图像。那是因为它不是一个图像! 它没有底层位图(CGImage)。 没有实际内容。 它只是一组CIFilter指令,用于派生图像。


2
我一直在告诉你,但你似乎不相信我。将图像视图的图像设置为使用“imageWithCIImage:”创建的UIImage是行不通的。 - matt
你是对的 :) 我刚刚用你提到的方法测试了一下,非常顺利。非常感谢! - Rukshan
从CIImage转换为CGImage的代码行是:CGImageRef cgimageref = [[CIContext contextWithOptions:nil] createCGImage:ciimage fromRect:[ciimage extent]]; - Wex
有人听到苹果关于initWithCIImage:的解决方法的消息吗?这很令人困惑。 - Krzysztof Przygoda
没有什么需要解决的,@KrzysztofPrzygoda - 它正如预期的那样工作。 - matt
显示剩余3条评论

2

这是一个关于Swift的回答,灵感来自于这个问题用户user1951992提供的解决方案

let imageView = UIImageView(frame: CGRect(x: 100, y: 200, width: 100, height: 50))
imageView.contentMode = .scaleAspectFit

//just an example for a CIFilter
//NOTE: we're using implicit unwrapping here because we're sure there is a filter
//(and an image) named exactly this
let filter = CIFilter(name: "CISepiaTone")!
let image = UIImage(named: "image")!
filter.setValue(CIImage(image: image), forKey: kCIInputImageKey)
filter.setValue(0.5, forKey: kCIInputIntensityKey)

guard let outputCGImage = filter?.outputImage,
    let outputImage = CIContext().createCGImage(outputCGImage, from: outputCGImage.extent) else {
        return
}

imageView.image = UIImage(cgImage: outputImage)

1
我刚刚花了一整天的时间在这个问题上。我遇到了方向问题,导致输出质量很差。
在使用相机拍摄图像后,我执行以下操作。
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
                UIImage *image = [[UIImage alloc] initWithData:imageData];

这导致了旋转问题,因此我需要对其进行调整。
UIImage *scaleAndRotateImage(UIImage *image)
{
    int kMaxResolution = image.size.height; // Or whatever

    CGImageRef imgRef = image.CGImage;

    CGFloat width = CGImageGetWidth(imgRef);
    CGFloat height = CGImageGetHeight(imgRef);

    CGAffineTransform transform = CGAffineTransformIdentity;
    CGRect bounds = CGRectMake(0, 0, width, height);
    if (width > kMaxResolution || height > kMaxResolution) {
        CGFloat ratio = width/height;
        if (ratio > 1) {
            bounds.size.width = kMaxResolution;
            bounds.size.height = bounds.size.width / ratio;
        }
        else {
            bounds.size.height = kMaxResolution;
            bounds.size.width = bounds.size.height * ratio;
        }
    }

    CGFloat scaleRatio = bounds.size.width / width;
    CGSize imageSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef));
    CGFloat boundHeight;
    UIImageOrientation orient = image.imageOrientation;
    switch(orient) {

        case UIImageOrientationUp: //EXIF = 1
            transform = CGAffineTransformIdentity;
            break;

        case UIImageOrientationUpMirrored: //EXIF = 2
            transform = CGAffineTransformMakeTranslation(imageSize.width, 0.0);
            transform = CGAffineTransformScale(transform, -1.0, 1.0);
            break;

        case UIImageOrientationDown: //EXIF = 3
            transform = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height);
            transform = CGAffineTransformRotate(transform, M_PI);
            break;

        case UIImageOrientationDownMirrored: //EXIF = 4
            transform = CGAffineTransformMakeTranslation(0.0, imageSize.height);
            transform = CGAffineTransformScale(transform, 1.0, -1.0);
            break;

        case UIImageOrientationLeftMirrored: //EXIF = 5
            boundHeight = bounds.size.height;
            bounds.size.height = bounds.size.width;
            bounds.size.width = boundHeight;
            transform = CGAffineTransformMakeTranslation(imageSize.height, imageSize.width);
            transform = CGAffineTransformScale(transform, -1.0, 1.0);
            transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
            break;

        case UIImageOrientationLeft: //EXIF = 6
            boundHeight = bounds.size.height;
            bounds.size.height = bounds.size.width;
            bounds.size.width = boundHeight;
            transform = CGAffineTransformMakeTranslation(0.0, imageSize.width);
            transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
            break;

        case UIImageOrientationRightMirrored: //EXIF = 7
            boundHeight = bounds.size.height;
            bounds.size.height = bounds.size.width;
            bounds.size.width = boundHeight;
            transform = CGAffineTransformMakeScale(-1.0, 1.0);
            transform = CGAffineTransformRotate(transform, M_PI / 2.0);
            break;

        case UIImageOrientationRight: //EXIF = 8
            boundHeight = bounds.size.height;
            bounds.size.height = bounds.size.width;
            bounds.size.width = boundHeight;
            transform = CGAffineTransformMakeTranslation(imageSize.height, 0.0);
            transform = CGAffineTransformRotate(transform, M_PI / 2.0);
            break;

        default:
            [NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"];

    }

    UIGraphicsBeginImageContext(bounds.size);

    CGContextRef context = UIGraphicsGetCurrentContext();

    if (orient == UIImageOrientationRight || orient == UIImageOrientationLeft) {
        CGContextScaleCTM(context, -scaleRatio, scaleRatio);
        CGContextTranslateCTM(context, -height, 0);
    }
    else {
        CGContextScaleCTM(context, scaleRatio, -scaleRatio);
        CGContextTranslateCTM(context, 0, -height);
    }

    CGContextConcatCTM(context, transform);

    CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, width, height), imgRef);
    UIImage *imageCopy = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();  

    return imageCopy;  
}

然后当我应用我的过滤器时,我会这样做(特别感谢这个帖子 - 特别是matt和Wex)

    -(UIImage*)processImage:(UIImage*)image {

            CIImage *inImage = [CIImage imageWithCGImage:image.CGImage];

            CIFilter *filter = [CIFilter filterWithName:@"CIColorControls" keysAndValues:
                        kCIInputImageKey, inImage,
                        @"inputContrast", [NSNumber numberWithFloat:1.0],
                        nil];

    UIImage *outImage = [filter outputImage];

//Juicy bit
            CGImageRef cgimageref = [[CIContext contextWithOptions:nil] createCGImage:outImage fromRect:[outImage extent]];

            return [UIImage imageWithCGImage:cgimageref];
        }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接