将遮罩应用于AVCaptureStillImageOutput

时间:2016-04-26 03:36:48

标签: ios swift avfoundation core-graphics

我正在开展一个项目,我想要用他们的相机屏蔽用户刚刚拍摄的照片。屏幕以特定的宽高比创建,以将信箱添加到照片中。

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

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通道,但我没有运气。任何帮助都是超级的。

1 个答案:

答案 0 :(得分: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

}