如何为显示 CIImage 的 GLKView 实现 contentMode?

How to implement contentMode for GLKView displaying a CIImage?

我创建了一个 GLKView 子类来显示 CIImage,以便更好地显示 CIFilter 链的输出图像。

但是,我似乎需要实施 contentMode 逻辑,以便在 drawRect(rect: CGRect) 调用中为 drawImage(image: CIImage, inRect: CGRect, fromRect: CGRect) 提供正确的 inRect

有人知道如何实现这样的逻辑以符合 UIImageView 的 contentMode 行为吗?

在iOS10.3中contentMode的设置好像没有影响到glkView。 看起来总是bottomLeft模式。

为了使 glkView 以可查看的格式显示 CIImage,这对我有用。

在glkView(_view: GLKView, drawIn rect: CGRect)中传入的rect需要修改view的contentScaleFactor

  1. 此代码假定您已经在 GLKViewController 的 viewDidLoad 方法中初始化了 EAGLContext(我的 glkView 名为 effectView2)

    context = EAGLContext.init(api: EAGLRenderingAPI.openGLES2)
    if context != nil {
    effectView2.context = self.context!
    
    EAGLContext.setCurrent(self.context)
    ciContext = CIContext.init(eaglContext: context!)
    
  2. 设置glkView后设置比例因子

    myScaleFactor = view.contentScaleFactor

  3. 在你的 glkView(_ view: GLKView, drawIn rect: CGRect) 中这样做

    let adjustedRect = CGRect(x: 0.0, y: 0.0, width: rect.width * myScaleFactor, height: rect.height * myScaleFactor )

然后用你的ciContext在adjustedRect中绘制ciImage。像这样使用 ciImage 的范围作为 from 参数:

ciContext!.draw(outputImage, in: adjustedRect , from: (ciSourceImage?.extent)!)
  1. 哦,是的。我假设您已经找到了调整 GLKView 比例因子的技术说明。它在您的 GLKView 子类中调用一行。参见 https://developer.apple.com/library/content/qa/qa1909/_index.html

您很可能需要对这种方法进行一些调整。我目前正在处理不同源 ciImages 的方向更改问题。

我花了很长时间才找到这么多所以我想分享这些发现.. 请 post 您发现的任何改进!

希望对您有所帮助 威尔L-B

使 contentMode 以与 UIView 类似的方式工作。我做了以下 class.

final class ContenModeEnforcer {
    static func rectFor(contentMode: UIViewContentMode, fromRect: CGRect, toRect: CGRect) -> CGRect {
        switch contentMode {
        case .scaleToFill:
            return toRect

        case .scaleAspectFit:
            return aspectFit(fromRect, toRect: toRect)

        case .scaleAspectFill:
            return aspectFill(fromRect, toRect: toRect)

        case .redraw:
            return fromRect

        case .center:
            let origin = CGPoint(
                x: (toRect.size.width - fromRect.size.width) / 2,
                y: (toRect.size.height - fromRect.size.height) / 2)
            return CGRect(origin: origin, size: fromRect.size)

        case .top:
            let origin = CGPoint(
                x: (toRect.size.width - fromRect.size.width) / 2,
                y: 0.0)
            return CGRect(origin: origin, size: fromRect.size)

        case .bottom:
            let origin = CGPoint(
                x: (toRect.size.width - fromRect.size.width) / 2,
                y: toRect.size.height - fromRect.size.height)
            return CGRect(origin: origin, size: fromRect.size)

        case .left:
            let origin = CGPoint(
                x: 0.0,
                y: (toRect.size.height - fromRect.size.height) / 2)
            return CGRect(origin: origin, size: fromRect.size)

        case .right:
            let origin = CGPoint(
                x: toRect.size.width - fromRect.size.width,
                y: (toRect.size.height - fromRect.size.height) / 2)
            return CGRect(origin: origin, size: fromRect.size)


        case .topLeft:
            let origin = CGPoint(
                x: 0.0,
                y: 0.0)
            return CGRect(origin: origin, size: fromRect.size)

        case .topRight:
            let origin = CGPoint(
                x: toRect.size.width - fromRect.size.width,
                y: 0.0)
            return CGRect(origin: origin, size: fromRect.size)

        case .bottomLeft:
            let origin = CGPoint(
                x: 0.0,
                y: toRect.size.height - fromRect.size.height)
            return CGRect(origin: origin, size: fromRect.size)

        case .bottomRight:
            let origin = CGPoint(
                x: toRect.size.width - fromRect.size.width,
                y: toRect.size.height - fromRect.size.height)
            return CGRect(origin: origin, size: fromRect.size)
        }
    }

    static fileprivate func aspectFit(_ fromRect: CGRect, toRect: CGRect) -> CGRect {
        let fromAspectRatio = fromRect.size.width / fromRect.size.height;
        let toAspectRatio = toRect.size.width / toRect.size.height;

        var fitRect = toRect

        if (fromAspectRatio > toAspectRatio) {
            fitRect.size.height = toRect.size.width / fromAspectRatio;
            fitRect.origin.y += (toRect.size.height - fitRect.size.height) * 0.5;
        } else {
            fitRect.size.width = toRect.size.height  * fromAspectRatio;
            fitRect.origin.x += (toRect.size.width - fitRect.size.width) * 0.5;
        }

        return fitRect.integral
    }

    static fileprivate func aspectFill(_ fromRect: CGRect, toRect: CGRect) -> CGRect {
        let fromAspectRatio = fromRect.size.width / fromRect.size.height;
        let toAspectRatio = toRect.size.width / toRect.size.height;

        var fitRect = toRect

        if (fromAspectRatio > toAspectRatio) {
            fitRect.size.width = toRect.size.height  * fromAspectRatio;
            fitRect.origin.x += (toRect.size.width - fitRect.size.width) * 0.5;
        } else {
            fitRect.size.height = toRect.size.width / fromAspectRatio;
            fitRect.origin.y += (toRect.size.height - fitRect.size.height) * 0.5;
        }

        return fitRect.integral
    }
}

在抽奖中(_:CGRect).

let inputBounds = image.extent
let drawableBounds = CGRect(x: 0, y: 0, width: self.drawableWidth, height: self.drawableHeight)
let targetBounds = ContenModeEnforcer.rectFor(contentMode: contentMode, fromRect: inputBounds, toRect: drawableBounds)
ciContext.draw(image, in: targetBounds, from: inputBounds)