【问题标题】:Apply a mask to AVCaptureStillImageOutput对 AVCaptureStillImageOutput 应用蒙版
【发布时间】:2016-04-26 03:36:47
【问题描述】:

我正在处理一个项目,我想遮盖用户刚刚用相机拍摄的照片。蒙版以特定的纵横比创建,以便为照片添加信箱。

我可以成功创建图像、创建蒙版并将两者都保存到相机胶卷,但我无法将蒙版应用于图像。这是我现在的代码

func takePhoto () {
  dispatch_async(self.sessionQueue) { () -> Void in
    if let photoOutput = self.output as? AVCaptureStillImageOutput {
      photoOutput.captureStillImageAsynchronouslyFromConnection(self.outputConnection) { (imageDataSampleBuffer, err) -> Void in
        if err == nil {
          let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer)
          let image = UIImage(data: imageData)

          if let _ = image {
            let maskedImage = self.maskImage(image!)

            print("masked image: \(maskedImage)")

            self.savePhotoToLibrary(maskedImage)
          }
        } else {
          print("Error while capturing the image: \(err)")
        }
      }
    }
  }
}

func maskImage (image: UIImage) -> UIImage {
  let mask = createImageMask(image)

  let maskedImage = CGImageCreateWithMask(image.CGImage, mask!)

  return UIImage(CGImage: maskedImage!)
}

func createImageMask (image: UIImage) -> CGImage? {
  let width = image.size.width
  let height = width / CGFloat(store.state.aspect.rawValue)
  let x = CGFloat(0.0)
  let y = (image.size.height - height) / 2
  let maskRect = CGRectMake(0.0, 0.0, image.size.width, image.size.height)
  let maskContents = CGRectMake(x, y, width, height)

  var color = UIColor(white: 1.0, alpha: 0.0)

  UIGraphicsBeginImageContextWithOptions(CGSizeMake(maskRect.size.width, maskRect.size.height), false, 0.0)

  color.setFill()
  UIRectFill(maskRect)

  color = UIColor(white: 0.0, alpha: 1.0)
  color.setFill()
  UIRectFill(maskContents)

  let maskImage = UIGraphicsGetImageFromCurrentImageContext()

  UIGraphicsEndImageContext()

  print("mask: \(maskImage)")
  savePhotoToLibrary(image)
  savePhotoToLibrary(maskImage)

  let mask = CGImageMaskCreate(
    CGImageGetWidth(maskImage.CGImage),
    CGImageGetHeight(maskImage.CGImage),
    CGImageGetBitsPerComponent(maskImage.CGImage),
    CGImageGetBitsPerPixel(maskImage.CGImage),
    CGImageGetBytesPerRow(maskImage.CGImage),
    CGImageGetDataProvider(maskImage.CGImage),
    nil,
    false)

  return mask
}

据我了解,CGImageCreateWithMask 要求要遮罩的图像具有 Alpha 通道。我已经尝试了我在这里看到的所有东西来为 jpeg 表示添加一个 alpha 通道,但我没有任何运气。任何帮助都会很棒。

【问题讨论】:

    标签: ios swift avfoundation core-graphics


    【解决方案1】:

    这可能是一个错误,也可能只是有点误导。 CGImageCreateWithMask() 实际上并没有修改图像 - 它只是将遮罩数据与图像数据相关联,并在您将图像绘制到上下文(例如在 UIImageView 中)时使用遮罩,但 不是 当您将图像保存到磁盘时。

    有几种方法可以生成蒙版图像的“渲染”版本,但如果我理解您的意图,您并不真正想要“蒙版”......您想要图像的信箱版本.

    这里有一个选项可以有效地在图像的顶部和底部绘制黑条(如果您不想要黑色,条/框颜色是一个可选参数)。然后您可以保存修改后的图像。

    在上面的代码中,替换

      let maskedImage = self.maskImage(image!)
    

      let height = image.size.width / CGFloat(store.state.aspect.rawValue)
      let maskedImage = self.doLetterBox(image!, visibleHeight: height)
    

    并添加此功能:

    func doLetterBox(sourceImage: UIImage, visibleHeight: CGFloat, frameColor: UIColor?=UIColor.blackColor()) -> UIImage! {
    
        // local rect based on sourceImage size
        let imageRect: CGRect = CGRectMake(0.0, 0.0, sourceImage.size.width, sourceImage.size.height)
    
        // rect for "visible" part of letter-boxed image
        let clipRect: CGRect = CGRectMake(0.0, (imageRect.size.height - visibleHeight) / 2.0, imageRect.size.width, visibleHeight)
    
        // setup the image context, using sourceImage size
        UIGraphicsBeginImageContextWithOptions(imageRect.size, true, UIScreen.mainScreen().scale)
    
        let ctx: CGContextRef = UIGraphicsGetCurrentContext()!
        CGContextSaveGState(ctx)
    
        // fill new empty image with frameColor (defaults to black)
        CGContextSetFillColorWithColor(ctx, frameColor?.CGColor)
        CGContextFillRect(ctx, imageRect)
    
        // set Clipping rectangle to allow drawing only in desired area
        UIRectClip(clipRect)
    
        // draw the sourceImage to full-image-size (the letter-boxed portion will be clipped)
        sourceImage.drawInRect(imageRect)
    
        // get new letter-boxed image
        let resultImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
    
        // clean up
        CGContextRestoreGState(ctx)
        UIGraphicsEndImageContext()
    
        return resultImage
    
    }
    

    【讨论】:

    • 这基本上是我最终的结果。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-20
    • 1970-01-01
    • 1970-01-01
    • 2020-03-13
    • 2016-07-14
    • 2017-10-07
    • 2020-05-13
    相关资源
    最近更新 更多