क्यों UIGraphicsGetCurrentContext UIGraphicsBeginImageContext के बाद शून्य लौटाता है
मैं एक कोड उदाहरण का अनुसरण कर रहा हूं, जो एक धुंधला यूबिलब बनाने के लिए है, 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
जवाब
यहाँ एक बेहतर समाधान है - धुंधली छवि को पुनः प्राप्त करने के बजाय, केवल लेबल को धुंधला होने दें।
जब आपको इसे धुंधला करने की आवश्यकता हो, तो सेट करें 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()
}
}