2016-04-26 9 views
0

Ich arbeite an einem Projekt, bei dem ich ein Foto maskieren möchte, das der Benutzer gerade mit seiner Kamera aufgenommen hat. Die Maske wird in einem bestimmten Seitenverhältnis erstellt, um einem Foto Briefkästen hinzuzufügen.Eine Maske auf AVCaptureStillImageOutput anwenden

Ich kann erfolgreich das Bild erstellen, erstellen Sie die Maske und speichern Sie beide in der Kamera roll, aber ich kann nicht die Maske auf das Bild anwenden. Hier ist der Code Ich habe jetzt

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 
} 

Von dem, was ich verstehe, CGImageCreateWithMask erfordert, dass das Bild zu maskierenden hat einen Alpha-Kanal. Ich habe alles versucht, was ich hier gesehen habe, um der JPEG-Darstellung einen Alpha-Kanal hinzuzufügen, aber ich habe kein Glück. Jede Hilfe wäre super.

Antwort

1

Dies kann ein Fehler sein, oder vielleicht ist es nur ein bisschen irreführend. CGImageCreateWithMask() ändert nicht wirklich das Bild - es verbindet nur die Maskendaten mit den Bilddaten und verwendet die Maske, wenn Sie das Bild in einen Kontext (wie in einem UIImageView), aber nicht, wenn Sie das Bild zu speichern Scheibe.

Es gibt ein paar Ansätze zum Generieren einer "gerenderten" Version des maskierten Bildes, aber wenn ich Ihre Absicht verstehe, wollen Sie nicht wirklich eine "Maske" ... Sie wollen eine mit einem Brief versehene Version des Bild.

Hier ist eine Option, die effektiv schwarze Balken am oberen und unteren Rand Ihres Bildes zeichnet (die Balken/Rahmenfarbe ist ein optionaler Parameter, wenn Sie kein Schwarz wünschen). Sie können dann das geänderte Image speichern.

In Ihrem Code oben, ersetzen

let maskedImage = self.maskImage(image!) 

mit

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

und fügen Sie diese Funktion:

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 

} 
+0

Dies resultiert im Wesentlichen ist, was ich am Ende mit. Vielen Dank! – Mike

Verwandte Themen