मैं एक CGContext में आदिम के साथ एकल ग्लिफ़ को आकर्षित करने के लिए CoreGraphics का उपयोग कर रहा हूँ। निम्नलिखित कोड XCode 9.2 में एक तेज खेल के मैदान में काम करता है जब खेल के मैदान में शुरू किया जाता है तो खेल के मैदान में दिए गए निर्देशांक पर दो बार अक्षर A के साथ एक छोटा आयत दिखाई देना चाहिए।

import Cocoa
import PlaygroundSupport

class MyView: NSView {

    init(inFrame: CGRect) {
        super.init(frame: inFrame)
    }

    required init?(coder decoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func draw(_ rect: CGRect) {

        // setup context properties

        let context: CGContext = NSGraphicsContext.current!.cgContext

        context.setStrokeColor(CGColor.black)
        context.setTextDrawingMode(.fill)
        context.setFillColor(CGColor(red: 0.99, green: 0.99, blue: 0.85, alpha: 1))
        context.beginPath()
        context.addRect(rect)
        context.fillPath()
        context.setFillColor(.black)

        // prepare variables and constants

        var font = CTFontCreateWithName("Helvetica" as CFString, 48, nil)
        var glyph = CTFontGetGlyphWithName(font, "A" as CFString)
        var glyph1Position = CGPoint(x: self.frame.minX, y: self.frame.maxY/2)
        var glyph2Position = CGPoint(x: self.frame.minX+150, y: self.frame.maxY/2)

        let text = "Hello"
        var textOrigin = NSPoint(x: self.frame.minX+50, y: self.frame.maxY/2)

        // draw one character

        CTFontDrawGlyphs(font, &glyph, &glyph1Position, 1, context)

        // ***   ***   when the next line is uncommented the bug appears   ***   ***

        // text.draw(at: textOrigin)

        CTFontDrawGlyphs(font, &glyph, &glyph2Position, 1, context)
    }
}

var frameRect = CGRect(x: 0, y: 0, width: 200, height: 100)

PlaygroundPage.current.liveView = MyView(inFrame: frameRect)

अब मैं उसी संदर्भ में नियमित पाठ बनाना चाहता हूं। हालाँकि, जब टेक्स्ट स्ट्रिंग को दो ग्लिफ़ के ड्राइंग के बीच अपनी स्वयं की ड्राइंग विधि के माध्यम से खींचा जाता है, तो वर्तमान संदर्भ गड़बड़ हो जाता है, दूसरा ग्लिफ़ नहीं दिखाएगा। जब दोनों सिंगल ग्लिफ खींचे जाने के बाद टेक्स्ट खींचा जाता है तो सबकुछ ठीक होता है।

तो स्पष्ट रूप से पाठ को चित्रित करने से वर्तमान CGContext पर असर पड़ता है, लेकिन मुझे पता नहीं चल रहा है कि वास्तव में क्या हो रहा है। मैंने स्ट्रिंग को चित्रित करने और बाद में पुनर्स्थापित करने के लिए saveGstate() विधि की कोशिश की, लेकिन सफलता के बिना।

मैंने CTFramesetterCreateWithAttributedString के साथ एक जिम्मेदार स्ट्रिंग बनाने के लिए CoreText विधियों का उपयोग करने का भी प्रयास किया और इसे CTFramesetterCreateFrame के साथ दिखाया, यह भी काम नहीं करता है, यहां फ्रेमसेटर के निर्माण के बाद संदर्भ गड़बड़ हो गया है।

मेरा वास्तविक खेल का मैदान अधिक जटिल है, वहाँ ग्लिफ़ पूरी तरह से गायब नहीं होते हैं, लेकिन एक गलत ऊर्ध्वाधर स्थिति में दिखाए जाते हैं, लेकिन मूल समस्या - और प्रश्न समान है:

पृष्ठभूमि में किए जा रहे संदर्भ में कोई अन्य परिवर्तन किए बिना मैं टेक्स्ट को वर्तमान कॉन्टेक्स्ट में कैसे आकर्षित कर सकता हूं?

2
MassMover 29 अक्टूबर 2018, 16:57

1 उत्तर

सबसे बढ़िया उत्तर

आपको टेक्स्ट मैट्रिक्स (टेक्स्ट ड्रॉइंग पर लागू ट्रांसफॉर्म) सेट करने की आवश्यकता है। आपको टेक्स्ट ड्राइंग करने से पहले इसे हमेशा सेट करना चाहिए, क्योंकि यह ग्राफिक्स स्थिति का हिस्सा नहीं है और अन्य ड्राइंग कोड जैसे ऐपकिट के स्ट्रिंग ड्राइंग एक्सटेंशन द्वारा ट्रैश किया जा सकता है।

CTFontDrawGlyphs पर कॉल करने से पहले निम्नलिखित को जोड़ें:

    context.textMatrix = .identity

इसे संदर्भ के प्रारंभिक सेटअप में कहा जाना चाहिए क्योंकि इस बात का कोई वादा नहीं है कि drawRect को कॉल करने से पहले टेक्स्ट मैट्रिक्स की पहचान होगी। फिर, जब भी आप किसी ऐसी चीज़ पर कॉल करते हैं जो टेक्स्ट मैट्रिक्स को संशोधित करती है, तो आपको इसे अपनी इच्छित चीज़ों पर वापस सेट करने की आवश्यकता होगी (इस मामले में पहचान, लेकिन यह कुछ और हो सकता है यदि आप एक फैंसी तरीके से आकर्षित करना चाहते हैं)।

यह हमेशा स्पष्ट नहीं होता है कि टेक्स्ट मैट्रिक्स को क्या संशोधित करेगा। ऐपकिट ड्राइंग फ़ंक्शन लगभग हमेशा करते हैं (हालांकि मुझे यह इंगित करने वाले किसी भी दस्तावेज से अवगत नहीं है)। कोर टेक्स्ट फ़ंक्शंस जो संदर्भ को संशोधित करते हैं, जैसे CTFrameDraw और CTLineDraw, आम तौर पर इस तथ्य को एक बयान के साथ दस्तावेज करेंगे जैसे:

यह कॉल किसी भी स्थिति में संदर्भ छोड़ सकती है और ड्रॉ ऑपरेशन के बाद इसे फ्लश नहीं करती है।

इसी तरह CTFontDrawGlyphs चेतावनी देते हैं:

यदि ये विशेषताएँ फ़ॉन्ट में निर्दिष्ट हैं, तो यह फ़ंक्शन फ़ॉन्ट, टेक्स्ट आकार और टेक्स्ट मैट्रिक्स सहित ग्राफ़िक्स स्थिति को संशोधित करता है। इन विशेषताओं को पुनर्स्थापित नहीं किया गया है।

एक नियम के रूप में मैं टेक्स्ट ड्रॉइंग सिस्टम को मिलाने को हतोत्साहित करता हूं। ऐपकिट या कोर टेक्स्ट का प्रयोग करें, लेकिन उन्हें मिलाएं नहीं। यदि आप किसी एक को चुनते हैं और उससे चिपके रहते हैं, तो यह आम तौर पर कोई समस्या नहीं है (जब तक आप drawRect के शीर्ष पर मैट्रिक्स को एक बार इनिशियलाइज़ करते हैं)। उदाहरण के लिए, यदि आपने सभी आरेखण CTFontDrawGlyphs के साथ किए हैं, तो आपको हर बार मैट्रिक्स को रीसेट करने की आवश्यकता नहीं होगी; आप कोर टेक्स्ट मैट्रिक्स में बने रहेंगे और यह ठीक रहेगा (यही कारण है कि जब आप draw(at:) कॉल पर टिप्पणी करते हैं तो यह काम करता है)।

3
Rob Napier 29 अक्टूबर 2018, 20:10