2011-04-08 11 views
7

मेरे उद्देश्य: मैं एक IDWriteTextFormat के फ़ॉन्ट तो मैं गणना कर सकते हैं कि कैसे पाठ की कई लाइनों एक निश्चित ऊंचाई के IDWriteTextLayout में फिट कर सकते हैं की ऊंचाई प्राप्त करना चाहते हैं।DirectWrite: हो रही है एक फ़ॉन्ट की ऊंचाई

मेरे समस्या: सही अब मैं लाइनों के दृश्य संख्या की गणना करने के लिए इस कोड का उपयोग कर रहा:

inline int kmTextCtrl::GetVisLines() const 
{ 

    /* pTextFormat is an IDWriteTextFormat pointer, dpi_y is the desktop's vertical dpi, 
     and GetHeight() returns the height (in pixels) of the render target. */ 
    float size = (pTextFormat->GetFontSize()/72.0f)*dpi_y; 
    return (int)(GetHeight()/size); 
} 

गणना कुछ फोंट के लिए सही प्रतीत हो रहा है, लेकिन ट्रू टाइप से किसी के लिए नहीं फोंट (उदाहरण: कूरियर न्यू, एरियल, टाइम्स न्यू रोमन)। इन फ़ॉन्ट्स के लिए, दिखाया गया पाठ रेंडर लक्ष्य की निचली लंबवत सीमा से बहुत छोटा है।

कुछ संदर्भ: मैं एक पाठ वापस स्क्रॉल बफर नियंत्रण जो नियंत्रण के लक्ष्य रेंडर करने के लिए पाठ डाल करने के लिए एक IDWriteTextLayout का उपयोग करता है बनाने रहा हूँ। मैं लेआउट में खींचने के लिए गोलाकार बफर (जो लाइन द्वारा std :: तारों में पाठ संग्रहीत करता है) से टेक्स्ट की कितनी पंक्तियां निर्धारित करने के लिए GetVisLines() के परिणाम का उपयोग करता है, और जब भी खिड़की स्क्रॉल या आकार बदलती है, इसे फिर से बनाएं।

यह "मूल" Win32 API C++ का उपयोग करके किया जा रहा है।

उत्तर

6

मुझे answer मिला है। DirectWrite में एक पंक्ति (फ़ॉन्ट ऊंचाई प्लस खाई) की रिक्ति को खोजने के लिए, आप निम्न के लिए कुछ समान कार्य करना होगा:

inline int kmTextCtrl::GetVisLines() const 
{ 

    IDWriteFontCollection* collection; 
    TCHAR name[64]; UINT32 findex; BOOL exists; 
    pTextFormat->GetFontFamilyName(name, 64); 
    pTextFormat->GetFontCollection(&collection); 
    collection->FindFamilyName(name, &findex, &exists); 
    IDWriteFontFamily *ffamily; 
    collection->GetFontFamily(findex, &ffamily); 
    IDWriteFont* font; 
    ffamily->GetFirstMatchingFont(pTextFormat->GetFontWeight(), pTextFormat->GetFontStretch(), pTextFormat->GetFontStyle(), &font); 
    DWRITE_FONT_METRICS metrics; 
    font->GetMetrics(&metrics); 
    float ratio = pTextFormat->GetFontSize()/(float)metrics.designUnitsPerEm; 
    float size = (metrics.ascent + metrics.descent + metrics.lineGap) * ratio; 
    float height = GetHeight(); 
    int retval = static_cast<int>(height/size); 
    ffamily->Release(); 
    collection->Release(); 
    font->Release(); 
    return retval; 
} 
बेशक

, तो आप शायद नहीं सभी है कि हर बार आप क्या करना चाहते हैं अक्सर उपयोग किए जाने वाले इनलाइन फ़ंक्शन को कॉल करने के लिए।

+0

यह निश्चित रूप से एक गलत दृष्टिकोण है। उचित समाधान के लिए ड्वेन की प्रतिक्रिया देखें। – bunglehead

+0

@ बंगलहेड यह गलत क्यों है? –

+0

@DmitriNesteruk, क्योंकि यह बहुत अधिक धारणा करता है। उदाहरण के लिए आप इस बात पर विचार किए बिना लाइनों को मापना शुरू करते हैं कि वास्तविक टेक्स्ट डेटा के आधार पर अलग-अलग फ़ॉन्ट का उपयोग किया जा सकता है। इसके बाद यह लाइन स्पेसिंग मोड को अनदेखा करता है, और मान लेता है कि जिस तरह से लेआउट की गणना स्पेसिंग की गणना करती है (चढ़ाई + वंश + लाइनगैप)। ऊपर दिए गए शीर्ष रेटेड उत्तर को देखें, यह बेहतर बताता है कि यह अविश्वसनीय समाधान क्यों है। – bunglehead

8

सबसे सरल और सबसे मजबूत दृष्टिकोण सिर्फ पाठ मीट्रिक के लिए लेआउट से पूछना है, क्योंकि यह दो चीजों में से एक है जिसे इसे चित्रकारी और माप के लिए डिजाइन किया गया था। आप टेक्स्ट प्रारूप का उपयोग करके IDWriteTextLayout बनायेंगे और DWRITE_TEXT_METRICS::height प्राप्त करने के लिए GetMetrics पर कॉल करें। मुझे लगता है कि आप ID2D1RenderTarget::DrawText का उपयोग कर रहे हैं और एक टेक्स्ट प्रारूप पास कर रहे हैं, इसलिए हो सकता है कि आपने सीधे लेआउट नहीं बनाया हो, लेकिन DrawText पर कॉल करना CreateTextLayout पर कॉल करने जैसा ही DrawTextLayout है।

सावधान रहें कि यह उत्तर पाने के लिए निचली परतों के माध्यम से जाना (IDWriteFontFace और इसी तरह) कुछ मान्यताओं को मानता है कि एक सामान्य दुनिया तैयार पाठ नियंत्रण नहीं मानना ​​चाहिए, जैसे कि बेस फ़ॉन्ट का उपयोग किया जाएगा और सभी लाइनें एक ही ऊंचाई। जब तक सभी वर्ण दिए गए बेस फ़ॉन्ट में मौजूद होते हैं, यह काम करने के लिए होता है (संभावना है कि आप ज्यादातर अंग्रेजी प्रदर्शित कर रहे हैं, यही कारण है कि सभी अच्छी तरह से दिखाई देते हैं), लेकिन कुछ सीजेके या आरटीएल भाषाओं में फेंक दें (जो टाइम्स जैसे आधार फ़ॉन्ट नया रोमन निश्चित रूप से समर्थन नहीं करता है), और लाइन की ऊंचाई प्रतिस्थापित फ़ॉन्ट्स के अनुसार बढ़ेगी या घट जाएगी। जीडीआई प्रतिस्थापित फ़ॉन्ट्स को पुन: सहेजता है जैसे कि वे बेस फ़ॉन्ट की ऊंचाई में फिट होते हैं, लेकिन इससे थाई और तिब्बती जैसी भाषाओं में खराब स्क्रंच किए गए अक्षरों की ओर जाता है, जिन्हें आरोही और वंश के लिए अधिक श्वास कक्ष की आवश्यकता होती है। IDWriteTextLayout और डब्ल्यूपीएफ/वर्ड में जैसे अन्य लेआउट सभी फ़ॉन्ट ग्लाइफ को उसी एम आकार में रखते हैं, जिसका मतलब है कि वे एक दूसरे के समीप होने पर अधिक अच्छी तरह से लाइन करते हैं; लेकिन इसका मतलब यह है कि रेखा ऊंचाई चरणीय है।

यदि आप टेक्स्ट की प्रत्येक पंक्ति को खींचते हैं जैसे कि वे सभी एक ही ऊंचाई पर थे, तो आप ग्लिफ और गैर-वर्दी बेसलाइनों के बीच लाइनों के बीच ओवरलैप देख सकते हैं, या नियंत्रण के ऊपर और नीचे क्लिपिंग कर सकते हैं।तो आदर्श रेखा प्रत्येक पंक्ति की वास्तविक ऊंचाई का उपयोग करना है; लेकिन यदि आपको उन सभी को एक ही ऊंचाई (या यदि यह नियंत्रण को बहुत जटिल बनाता है) की आवश्यकता है, तो SetLineSpacing का उपयोग DWRITE_LINE_SPACING_UNIFORM के साथ मूल फ़ॉन्ट के लिए कम से कम एक स्पष्ट रेखा अंतर निर्धारित करें - इस तरह बेसलाइन समान रूप से दूरी पर हैं।

हालांकि, उत्सुकता के लिए, हाँ, लाइन ऊंचाई वास्तव में फ़ॉन्ट डिज़ाइन मीट्रिक चढ़ाई + वंश का उपयोग करके निर्धारित की जाती है, साथ ही कोई भी लाइन गैप मौजूद होता है (अधिकांश फ़ॉन्ट इसे शून्य पर सेट करते हैं, लेकिन गैब्रिओला का एक अच्छा उदाहरण है बड़ी रेखा अंतराल), एम आकार के समय और प्रति एम इकाइयों द्वारा विभाजित। ध्यान दें कि सभी एम आकार डीआईपी में हैं (जो सामान्य 96DPI पर 1: 1, डीआईपी का बिल्कुल == पिक्सेल) है, अंक नहीं (1/72 इंच)।

संबंधित मुद्दे