2015-04-06 1 views
1

J'ai deux instances de NSImage. Je veux que l'image2 soit placée au-dessus de l'image1, avec un certain niveau d'opacité. Ils sont de dimensions correspondantes. Aucune des images ne doit être visible dans l'interface utilisateur.Fusionner deux NSImages à l'aide de Swift sous OS X

Comment puis-je configurer correctement un contexte graphique et y dessiner des images, l'une avec une opacité complète et l'autre semi-transparente?

J'ai lu plusieurs réponses ici, mais je trouve cela compliqué, d'autant plus que la plupart semblent être soit pour Objective-C ou seulement pour iOS. Tous les pointeurs sont appréciés. Si cela peut être accompli sans avoir besoin d'un CGContext du tout, ce serait encore mieux.

func blendImages(image1: NSImage, image2: NSImage, alpha: CGFloat) -> CGImage { 

    // Create context 
    var ctx: CGContextRef = CGBitmapContextCreate(0, inputImage.size.width, inputImage.size.height, 8, inputImage.size.width*4, NSColorSpace.genericRGBColorSpace(), PremultipliedLast) 
    let area = CGRectMake(0, 0, inputImage.size.width, inputImage.size.height) 
    CGContextScaleCTM(ctx, 1, -1) 

    // Draw image1 in context 

    // Draw image2 with alpha opacity 
    CGContextSetAlpha(ctx, CGFloat(0.5)) 

    // Create CGImage from context 
    let outputImage = CGBitmapContextCreateImage(ctx) 

    return outputImage 
} 

Ailleurs j'ai cette extension pour obtenir CGImages de mes NSImages:

extension NSImage { 
    var CGImage: CGImageRef { 
     get { 
      let imageData = self.TIFFRepresentation 
      let source = CGImageSourceCreateWithData(imageData as! CFDataRef, nil) 
      let maskRef = CGImageSourceCreateImageAtIndex(source, 0, nil) 
      return maskRef 
     } 
    } 
} 
+0

Ceci utilise Swift 1.2 sous OS X 10.10. – Henrik

Répondre

3

j'ai réussi à résoudre ce avec NSGraphicsContext.

func mergeImagesAB(pathA: String, pathB: String, fraction: CGFloat) -> CGImage { 

    guard let imgA = NSImage(byReferencingFile: pathA), 
     let imgB = NSImage(byReferencingFile: pathB), 
     let bitmap = imgA.representations[0] as? NSBitmapImageRep, 
     let ctx = NSGraphicsContext(bitmapImageRep: bitmap) 
     else {fatalError("Failed to load images.")} 

    let rect = NSRect(origin: CGPoint(x: 0, y: 0), size: bitmap.size) 

    NSGraphicsContext.saveGraphicsState() 
    NSGraphicsContext.setCurrentContext(ctx) 
    imgB.drawInRect(rect, fromRect: rect, operation: .CompositeSourceOver, fraction: fraction) 
    NSGraphicsContext.restoreGraphicsState() 

    guard let result = bitmap.CGImage 
     else {fatalError("Failed to create image.")} 

    return result; 
} 
+0

J'ai découvert plus tard que les bandes provenaient des options par défaut pour l'enregistrement des images JPEG. En utilisant une qualité supérieure, les baguages ​​ont pour la plupart disparu. Un contexte 64 bits n'est donc probablement pas nécessaire dans la plupart des cas. – Henrik

0

Merci Henrik, j'avais besoin de ça pour Obj-C. Voici cette version au cas où quelqu'un aurait également besoin:

-(CGImageRef) mergeImage:(NSImage*)a andB:(NSImage*)b fraction:(float)fraction{ 
    NSBitmapImageRep *bitmap = (NSBitmapImageRep*)[[a representations] objectAtIndex:0]; 
    NSGraphicsContext *ctx = [NSGraphicsContext graphicsContextWithBitmapImageRep:bitmap]; 
    [NSGraphicsContext saveGraphicsState]; 
    [NSGraphicsContext setCurrentContext:ctx]; 

    CGRect rect = CGRectMake(0, 0, bitmap.size.width, bitmap.size.height); 
    [NSGraphicsContext saveGraphicsState]; 
    [NSGraphicsContext setCurrentContext:ctx]; 
    [b drawInRect:rect fromRect:rect operation:NSCompositeSourceOver fraction:fraction]; 
    [NSGraphicsContext restoreGraphicsState]; 

    return [bitmap CGImage]; 
}