क्यों UIGraphicsGetCurrentContext UIGraphicsBeginImageContext के बाद शून्य लौटाता है

Oct 04 2020

मैं एक कोड उदाहरण का अनुसरण कर रहा हूं, जो एक धुंधला यूबिलब बनाने के लिए है, https://stackoverflow.com/a/62224908/2226315।

मेरी आवश्यकता blurरनटाइम पर विधि को कॉल करने के बजाय लेबल इनिशियलाइज़ेशन के बाद ब्लर पर लेबल बनाने की है। हालाँकि, जब मैं blurलेबल के बाद कॉल करने की कोशिश करता हूं तो इनिशियलाइज्ड वैल्यू लौटा दी जाती UIGraphicsGetCurrentContextहै, nilइसलिए एक "घातक त्रुटि: एक वैकल्पिक मूल्य को उजागर करते समय अनपेक्षित रूप से पाया गया शून्य" होता है

UIGraphicsBeginImageContext(bounds.size)
print("DEBUG: bounds.size", bounds.size)
self.layer.render(in: UIGraphicsGetCurrentContext()!) // <- return nil
var image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
print("DEBUG: image image", image)

मैंने व्यक्तिगत रूप से सभी निम्नलिखित स्थानों में कोड जोड़ने की कोशिश की, संदर्भ अब प्राप्त किया जा सकता है, हालांकि यह अपेक्षा के अनुरूप धब्बा प्रभाव उत्पन्न नहीं करता है।

override func layoutSubviews() {
    super.layoutSubviews()
    self.blur()
}

// OR
    
override func draw(_ rect: CGRect) {
    super.draw(rect)
    self.blur()
}

पूर्ण कोड स्निपेट,

class BlurredLabel: UILabel {

    func blur(_ blurRadius: Double = 2.5) {        
        let blurredImage = getBlurryImage(blurRadius)
        let blurredImageView = UIImageView(image: blurredImage)
        blurredImageView.translatesAutoresizingMaskIntoConstraints = false
        blurredImageView.tag = 100
        blurredImageView.contentMode = .center
        blurredImageView.backgroundColor = .white
        addSubview(blurredImageView)
        NSLayoutConstraint.activate([
            blurredImageView.centerXAnchor.constraint(equalTo: centerXAnchor),
            blurredImageView.centerYAnchor.constraint(equalTo: centerYAnchor)
        ])
    }

    func unblur() {
        subviews.forEach { subview in
            if subview.tag == 100 {
                subview.removeFromSuperview()
            }
        }
    }

    private func getBlurryImage(_ blurRadius: Double = 2.5) -> UIImage? {
        UIGraphicsBeginImageContext(bounds.size)
        layer.render(in: UIGraphicsGetCurrentContext()!)
        guard let image = UIGraphicsGetImageFromCurrentImageContext(),
            let blurFilter = CIFilter(name: "CIGaussianBlur") else {
            UIGraphicsEndImageContext()
            return nil
        }
        UIGraphicsEndImageContext()

        blurFilter.setDefaults()

        blurFilter.setValue(CIImage(image: image), forKey: kCIInputImageKey)
        blurFilter.setValue(blurRadius, forKey: kCIInputRadiusKey)

        var convertedImage: UIImage?
        let context = CIContext(options: nil)
        if let blurOutputImage = blurFilter.outputImage,
            let cgImage = context.createCGImage(blurOutputImage, from: blurOutputImage.extent) {
            convertedImage = UIImage(cgImage: cgImage)
        }

        return convertedImage
    }
}

संदर्भ

  • लेबल में धुंधला दृश्य जोड़ें?
  • UILabel टेक्स्ट को कैसे ब्लर करें

अपडेट करें

"यूजीन डुडनेक" उत्तर के आधार पर उपयोग


definitionLabel = BlurredLabel()
definitionLabel.numberOfLines = 0
definitionLabel.lineBreakMode = .byWordWrapping
definitionLabel.textColor = UIColor(named: "text")
definitionLabel.text = "Lorem Ipsum is simply dummy text"
definitionLabel.clipsToBounds = false
definitionLabel.isBluring = true

जवाब

2 EugeneDudnyk Oct 05 2020 at 03:16

यहाँ एक बेहतर समाधान है - धुंधली छवि को पुनः प्राप्त करने के बजाय, केवल लेबल को धुंधला होने दें।

जब आपको इसे धुंधला करने की आवश्यकता हो, तो सेट करें label.isBluring = true। साथ ही, यह समाधान प्रदर्शन के लिए बेहतर है, क्योंकि यह समान संदर्भ का पुन: उपयोग करता है और छवि को देखने की आवश्यकता नहीं है।

class BlurredLabel: UILabel {
    
    var isBlurring = false {
        didSet {
            setNeedsDisplay()
        }
    }

    var blurRadius: Double = 2.5 {
        didSet {
            blurFilter?.setValue(blurRadius, forKey: kCIInputRadiusKey)
        }
    }

    lazy var blurFilter: CIFilter? = {
        let blurFilter = CIFilter(name: "CIGaussianBlur")
        blurFilter?.setDefaults()
        blurFilter?.setValue(blurRadius, forKey: kCIInputRadiusKey)
        return blurFilter
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        layer.isOpaque = false
        layer.needsDisplayOnBoundsChange = true
        layer.contentsScale = UIScreen.main.scale
        layer.contentsGravity = .center
        isOpaque = false
        isUserInteractionEnabled = false
        contentMode = .redraw
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func display(_ layer: CALayer) {
        let bounds = layer.bounds
        guard !bounds.isEmpty && bounds.size.width < CGFloat(UINT16_MAX) else {
            layer.contents = nil
            return
        }
        UIGraphicsBeginImageContextWithOptions(layer.bounds.size, layer.isOpaque, layer.contentsScale)
        if let ctx = UIGraphicsGetCurrentContext() {
            self.layer.draw(in: ctx)
        
            var image = UIGraphicsGetImageFromCurrentImageContext()?.cgImage
            if isBlurring, let cgImage = image {
                blurFilter?.setValue(CIImage(cgImage: cgImage), forKey: kCIInputImageKey)
                let ciContext = CIContext(cgContext: ctx, options: nil)
                if let blurOutputImage = blurFilter?.outputImage,
                   let cgImage = ciContext.createCGImage(blurOutputImage, from: blurOutputImage.extent) {
                    image = cgImage
                }
            }
            layer.contents = image
        }
        UIGraphicsEndImageContext()
    }
}