代码之家  ›  专栏  ›  技术社区  ›  Alexei

从CALayer或NSView获取图像(swift 3)

  •  14
  • Alexei  · 技术社区  · 8 年前

    我正在寻找一种方法来渲染CALayer或NSView并将NSImage恢复。

    我有一个自定义类,它是NSView的子类。 一开始,我只是做了一个渐变层来覆盖NSView。

    class ContentView: NSView {
    
       override func draw(_ dirtyRect: NSRect) {
          fillGradientLayer()
       }
    
       func fillGradientLayer() {
          gradientLayer = CAGradientLayer()
          gradientLayer.colors = [#colorLiteral(red: 0, green: 0.9909763549, blue: 0.7570167824, alpha: 1),#colorLiteral(red: 0, green: 0.4772562545, blue: 1, alpha: 1)].map({return $0.cgColor})
          gradientLayer.startPoint = CGPoint(x: 0, y: 0.5)
          gradientLayer.endPoint = CGPoint(x: 1, y: 0.5)
          gradientLayer.frame = self.frame.insetBy(dx: margin, dy: margin)
          gradientLayer.zPosition = 2
          gradientLayer.name = "gradientLayer"
          gradientLayer.contentsScale = (NSScreen.main()?.backingScaleFactor)!
          self.layer?.addSublayer(gradientLayer)
       }
    }
    

    在某一点上,我想从 加莱尔 s 我在互联网上找到了一些样本,并将它们转化为:

    extension CALayer {
    
    func getBitmapImage() -> NSImage {
        
        let btmpImgRep = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: Int(self.frame.width), pixelsHigh: Int(self.frame.height), bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: NSDeviceRGBColorSpace, bytesPerRow: 0, bitsPerPixel: 0)
        
        let  image: NSImage = NSImage(size: self.frame.size)
        image.lockFocus()
        let ctx = NSGraphicsContext(bitmapImageRep: btmpImgRep!)
        let cgCtxt = ctx!.cgContext
        
        self.render(in: cgCtxt)
        cgCtxt.draw(layer: CGLayer, in: CGRect)
        
        image.unlockFocus()
        return image
      }
    }
    

    第一个问题是 绘制(图层:CGLayer,输入:CGRect) 方法需要一个CGLayer,而不是CALayer。

    其次,我不知道我最终得到的代码是否会最终渲染我的图层,或者我做了什么错误。

    谢谢你的帮助。


    编辑: 从CALayer获取CGImage的解决方案。

    extension CALayer {
    
    func getBitmapImage() -> NSImage {
        
        let btmpImgRep =
            NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: Int(self.frame.width), pixelsHigh: Int(self.frame.height), bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: NSDeviceRGBColorSpace, bytesPerRow: 0, bitsPerPixel: 32)
    
        let ctx = NSGraphicsContext(bitmapImageRep: btmpImgRep!)
        let cgContext = ctx!.cgContext
        
        self.render(in: cgContext)
        
        let cgImage = cgContext.makeImage()
    
        let nsimage = NSImage(cgImage: cgImage!, size: CGSize(width: self.frame.width, height: self.frame.height))
    
            return nsimage    
      }
    }
    

    如何从NSView获取NSImage的答案如下。

    P、 我不太了解NSBitmapImageRep属性,所以这部分可能是错误的。

    1 回复  |  直到 8 年前
        1
  •  30
  •   Rob    2 年前

    这里有一些 NSView 选项:

    extension NSView {
    
        /// Get `NSImage` representation of the view.
        ///
        /// - Returns: `NSImage` of view
    
        func image() -> NSImage {
            let imageRepresentation = bitmapImageRepForCachingDisplay(in: bounds)!
            cacheDisplay(in: bounds, to: imageRepresentation)
            return NSImage(cgImage: imageRepresentation.cgImage!, size: bounds.size)
        }
    }
    

    extension NSView {
    
        /// Get `Data` representation of the view.
        ///
        /// - Parameters:
        ///   - fileType: The format of file. Defaults to PNG.
        ///   - properties: A dictionary that contains key-value pairs specifying image properties.
        /// - Returns: `Data` for image.
    
        func data(using fileType: NSBitmapImageRep.FileType = .png, properties: [NSBitmapImageRep.PropertyKey: Any] = [:]) -> Data {
            let imageRepresentation = bitmapImageRepForCachingDisplay(in: bounds)!
            cacheDisplay(in: bounds, to: imageRepresentation)
            return imageRepresentation.representation(using: fileType, properties: properties)!
        }
    }
    

    一些 CALayer 选项:

    extension CALayer {
    
        /// Get `NSImage` representation of the layer.
        ///
        /// - Returns: `NSImage` of the layer.
    
        func image() -> NSImage {
            let width = Int(bounds.width * contentsScale)
            let height = Int(bounds.height * contentsScale)
            let imageRepresentation = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: width, pixelsHigh: height, bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: .deviceRGB, bytesPerRow: 0, bitsPerPixel: 0)!
            imageRepresentation.size = bounds.size
    
            let context = NSGraphicsContext(bitmapImageRep: imageRepresentation)!
    
            render(in: context.cgContext)
    
            return NSImage(cgImage: imageRepresentation.cgImage!, size: bounds.size)
        }
    }
    

    extension CALayer {
    
        /// Get `Data` representation of the layer.
        ///
        /// - Parameters:
        ///   - fileType: The format of file. Defaults to PNG.
        ///   - properties: A dictionary that contains key-value pairs specifying image properties.
        ///
        /// - Returns: `Data` for image.
    
        func data(using fileType: NSBitmapImageRep.FileType = .png, properties: [NSBitmapImageRep.PropertyKey: Any] = [:]) -> Data {
            let width = Int(bounds.width * contentsScale)
            let height = Int(bounds.height * contentsScale)
            let imageRepresentation = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: width, pixelsHigh: height, bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: .deviceRGB, bytesPerRow: 0, bitsPerPixel: 0)!
            imageRepresentation.size = bounds.size
    
            let context = NSGraphicsContext(bitmapImageRep: imageRepresentation)!
    
            render(in: context.cgContext)
    
            return imageRepresentation.representation(using: fileType, properties: properties)!
        }
    }