2011-06-01 11 views
14

जब मैं FontMetric.getAscent() के लिए जावाडोक देखो मैं देख रहा हूँ:जावा: फ़ॉन्टमैट्रिक्स चढ़ाई गलत है?

फ़ॉन्ट चढ़ाई सबसे अक्षरांकीय अक्षर के शीर्ष के लिए फ़ॉन्ट के आधार रेखा से दूरी है। फ़ॉन्ट में कुछ वर्ण फ़ॉन्ट चढ़ाई रेखा से ऊपर हो सकते हैं।

लेकिन मैं एक त्वरित प्रदर्शन कार्यक्रम में लिखा था और मैं इस देखें: enter image description here

जहां पाठ की प्रत्येक पंक्ति के लिए 4 क्षैतिज लाइनों हैं: getDescent()

  • द्वारा कम

    • आधारभूत स्थिति बेसलाइन स्थिति
    • बेसलाइन स्थिति getAscent()
    • द्वारा उठाई गई
    • आधारभूत स्थिति से getHeight()

    सूचना getAscent() लाइन और वर्ण के शीर्ष के बीच की जगह को उठाया। मैंने अधिकांश फोंट और आकारों को देखा है, और हमेशा यह अंतर होता है। (जबकि फ़ॉन्ट वंश सिर्फ सही दिखता है।) क्या देता है?

    package com.example.fonts; 
    
    import java.awt.BorderLayout; 
    import java.awt.Dimension; 
    import java.awt.Font; 
    import java.awt.FontMetrics; 
    import java.awt.Graphics; 
    import java.awt.GraphicsEnvironment; 
    import java.awt.event.ActionEvent; 
    import java.awt.event.ActionListener; 
    import java.util.Arrays; 
    import javax.swing.JComboBox; 
    import javax.swing.JFrame; 
    import javax.swing.JPanel; 
    import javax.swing.JSpinner; 
    import javax.swing.JTextPane; 
    import javax.swing.SpinnerNumberModel; 
    import javax.swing.event.ChangeEvent; 
    import javax.swing.event.ChangeListener; 
    import javax.swing.event.DocumentEvent; 
    import javax.swing.event.DocumentListener; 
    
    public class FontMetricsExample extends JFrame 
    { 
        static final int marg = 10; 
        public FontMetricsExample() 
        { 
         super(FontMetricsExample.class.getSimpleName()); 
    
         JPanel panel = new JPanel(new BorderLayout()); 
         JPanel fontPanel = new JPanel(new BorderLayout()); 
         final JTextPane textSource = new JTextPane(); 
         textSource.setText("ABCDEFGHIJKLMNOPQRSTUVWXYZ\n" 
           +"abcdefghijklmnopqrstuvwxyz\n" 
           +"[email protected]#$%^&*()[]{}"); 
         final SpinnerNumberModel fontSizeModel = 
           new SpinnerNumberModel(18, 4, 32, 1); 
         final String fonts[] = 
           GraphicsEnvironment.getLocalGraphicsEnvironment() 
           .getAvailableFontFamilyNames(); 
         final JComboBox fontFamilyBox = new JComboBox(fonts); 
         fontFamilyBox.setSelectedItem("Arial"); 
    
         final JPanel text = new JPanel() { 
          @Override protected void paintComponent(Graphics g) { 
           super.paintComponent(g); 
           String fontFamilyName = 
             fonts[fontFamilyBox.getSelectedIndex()]; 
           int fontSize = fontSizeModel.getNumber().intValue(); 
           Font f = new Font(fontFamilyName, 0, fontSize); 
           g.setFont(f); 
           FontMetrics fm = g.getFontMetrics(); 
           int lineHeight = fm.getHeight(); 
           String[] s0 = textSource.getText().split("\n"); 
           int x0 = marg; 
           int y0 = getHeight()-marg-(marg+lineHeight)*s0.length; 
           for (int i = 0; i < s0.length; ++i) 
           { 
            y0 += marg+lineHeight; 
            String s = s0[i]; 
            g.drawString(s, x0, y0); 
            int w = fm.stringWidth(s); 
            for (int yofs : Arrays.asList(
              0, // baseline 
              -fm.getHeight(), 
              -fm.getAscent(), 
              fm.getDescent())) 
            { 
             g.drawLine(x0,y0+yofs,x0+w,y0+yofs); 
            } 
           } 
          } 
         }; 
         final JSpinner fontSizeSpinner = new JSpinner(fontSizeModel); 
         fontSizeSpinner.getModel().addChangeListener(
           new ChangeListener() {   
          @Override public void stateChanged(ChangeEvent e) { 
           text.repaint(); 
          } 
         }); 
         text.setMinimumSize(new Dimension(200,100)); 
         text.setPreferredSize(new Dimension(400,150)); 
         ActionListener repainter = new ActionListener() { 
          @Override public void actionPerformed(ActionEvent e) { 
           text.repaint(); 
          }   
         }; 
         textSource.getDocument().addDocumentListener(new DocumentListener() { 
          @Override public void changedUpdate(DocumentEvent e) { 
           text.repaint();    
          } 
          @Override public void insertUpdate(DocumentEvent e) {} 
          @Override public void removeUpdate(DocumentEvent e) {} 
         }); 
         fontFamilyBox.addActionListener(repainter); 
    
         fontPanel.add(fontFamilyBox, BorderLayout.CENTER); 
         fontPanel.add(fontSizeSpinner, BorderLayout.EAST); 
         fontPanel.add(textSource, BorderLayout.SOUTH); 
         panel.add(fontPanel, BorderLayout.NORTH); 
         panel.add(text, BorderLayout.CENTER);  
         setContentPane(panel); 
         pack(); 
         setDefaultCloseOperation(EXIT_ON_CLOSE); 
        } 
    
        public static void main(String[] args) { 
         new FontMetricsExample().setVisible(true); 
        } 
    } 
    
  • +0

    आपके पास 'TextLayout' का उपयोग करके बेहतर भाग्य हो सकता है। –

    +1

    @ एंड्रयू - विस्तृत करने की देखभाल? –

    उत्तर

    10

    एक संभावित कारण यह है कि इस मूल्य diacritics के साथ पत्र खातों में ले जाता है।

    उदाहरण के लिए, umlauts ÄÖÜ जोड़ना दिखाता है कि उनकी ट्रेमा चढ़ाई के करीब है (हालांकि वे अभी भी काफी नहीं पहुंचते हैं)।

    चढ़ाई की एक अधिक सामान्य परिभाषा के लिए खोज रहे मैं the definition in Wikipedia लगता है:

    [..] चढ़ाई आधारभूत और कहा कि आधारभूत से सब से अधिक दूर तक पहुँच जाता है ग्लिफ़ के शीर्ष के बीच की दूरी तक फैली है। चढ़ाई और वंश में उच्चारण या व्याख्यात्मक अंकों द्वारा जोड़ा गया दूरी शामिल हो सकता है या नहीं।

    तो ऐसा लगता है कि टाइपोग्राफी के भीतर भी कोई सटीक, पूर्ण परिभाषा नहीं है।

    +2

    मुझे ऐसा लगता है ... लेकिन * यह * diacritics खाते में क्यों लेना चाहिए? 'getAscent()' कहता है कि यह * अधिकांश * अल्फान्यूमेरिक वर्णों के शीर्ष पर होना चाहिए। यदि आप अधिकतम चढ़ाई चाहते हैं, तो 'getMaxAscent() 'है। –

    +0

    @ जेसन: मैं ज्यादातर अनुमान लगा रहा हूं। लेकिन चूंकि diacritics कई हैं और लगभग सभी अक्षरों पर लागू किया जा सकता है, कोई तर्क दे सकता है कि * अधिकांश * अल्फान्यूमेरिक वर्ण वास्तव में * diacritics है। और यह केवल आंशिक रूप से जीभ-इन-गाल है। –

    +0

    यह सबसे संतोषजनक उत्तर नहीं है, लेकिन मैं स्वीकार करूंगा, क्योंकि इसमें कुछ समझ है। –

    5

    मैं एक ही समस्या में आया और ऐसा लगता है कि एक चरित्र की वास्तविक ऊपरी सीमा GlyphVector कक्षा का उपयोग कर प्राप्त की जा सकती है। आयतों स्ट्रिंग में प्रदर्शित होने के पात्रों में से चढ़ाई द्वारा लौटाए में

    package graphics; 
    
    import java.awt.Font; 
    import java.awt.FontMetrics; 
    import java.awt.Graphics2D; 
    import java.awt.Rectangle; 
    import java.awt.font.GlyphVector; 
    import java.awt.geom.Rectangle2D; 
    import java.awt.image.BufferedImage; 
    import java.io.File; 
    import java.io.IOException; 
    
    import javax.imageio.ImageIO; 
    
    public class FontMetricsTest2 { 
    
        public static void main(String[] args) throws IOException { 
         //Draw the text to measure it with a drawing program 
         BufferedImage img = new BufferedImage(
          500, 300, BufferedImage.TYPE_INT_RGB); 
         Graphics2D graphics = img.createGraphics(); 
         Font font = new Font(Font.SERIF, Font.PLAIN, 150); 
         graphics.setFont(font); 
         String text = "ABCxyz"; 
         graphics.drawString(text, 20, 180); 
         ImageIO.write(img, "PNG", new File("G:\\someDir\\fontMetrics2.png")); 
    
         //Failed attempts to determine ascent with FontMetrics 
         FontMetrics fm = graphics.getFontMetrics(); 
         System.out.println("FM Ascent=" + fm.getAscent() + 
          ", FM descent=" + fm.getDescent()); 
         //returned ascent is too high 
         System.out.println("FM string bounds: " + 
          fm.getStringBounds(text, graphics)); 
         //too high as well 
    
         //The succesful way with glyph vector 
         GlyphVector gv = font.layoutGlyphVector(
          graphics.getFontRenderContext(), text.toCharArray(), 
          0, text.length(), Font.LAYOUT_LEFT_TO_RIGHT); 
         Rectangle pixBounds = gv.getPixelBounds(
          graphics.getFontRenderContext(), 0, 0); 
         System.out.println("GlyphVector - pixelBounds: " + pixBounds); 
         Rectangle2D visBounds = gv.getVisualBounds(); 
         System.out.println("GlyphVector - visualBounds: " + visBounds); 
        } 
    
    } 
    

    y मूल्य का प्रतिनिधित्व किया "पाठ" चर।

    पिक्सेल सीमाओं और दृश्य सीमाओं के बीच मुख्य अंतर यह है कि पिक्सेलबाउंड पूर्णांक हैं और दृश्यबाउंड फ़्लोट हैं। अन्यथा वे लगभग बराबर लगते हैं।

    2

    TrueType Reference Manual कहता है कि फ़ॉन्ट की चढ़ाई 'घी' तालिका में संग्रहीत होती है। हिया राज्यों के लिए प्रलेखन, "चढ़ाई, वंश और रेखागैप के मूल्य किसी भी गणना मूल्य के बजाय फ़ॉन्ट के निर्माता के डिजाइन इरादों का प्रतिनिधित्व करते हैं।" OpenType specification ट्रू टाइप विनिर्देश का एक विस्तार है।यह घी तालिका में आरोही को भी स्टोर करता है और चढ़ाई की ट्रू टाइप परिभाषा को संदर्भित करता है। नीचे की रेखा, चढ़ाई संपत्ति एक गाइड है, पूर्ण नहीं। GlyphLayoutVector पाठ की सीमा प्राप्त करने का सबसे सटीक तरीका है।

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