كيفية الحصول على الحقيقي سلسلة ارتفاع في جافا ؟

StackOverflow https://stackoverflow.com/questions/368295

  •  21-08-2019
  •  | 
  •  

سؤال

أنا باستخدام FontMetrics.getHeight() للحصول على ارتفاع السلسلة ، ولكنه يعطيني خطأ قيمة قطع والأسلة من سلسلة أحرف.هل هناك وظيفة أفضل ؟

هل كانت مفيدة؟

المحلول

وتستند هذه الطريقة getStringBounds() أدناه على GlyphVector للخط Graphics2D الحالي، الذي يعمل بشكل جيد جدا لسلسلة سطر واحد من النص:

public class StringBoundsPanel extends JPanel
{
    public StringBoundsPanel()
    {
        setBackground(Color.white);
        setPreferredSize(new Dimension(400, 247));
    }

    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        Graphics2D g2 = (Graphics2D) g;

        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                            RenderingHints.VALUE_ANTIALIAS_ON);

        // must be called before getStringBounds()
        g2.setFont(getDesiredFont());

        String str = "My Text";
        float x = 140, y = 128;

        Rectangle bounds = getStringBounds(g2, str, x, y);

        g2.setColor(Color.red);
        g2.drawString(str, x, y);

        g2.setColor(Color.blue);
        g2.draw(bounds);

        g2.dispose();
    }

    private Rectangle getStringBounds(Graphics2D g2, String str,
                                      float x, float y)
    {
        FontRenderContext frc = g2.getFontRenderContext();
        GlyphVector gv = g2.getFont().createGlyphVector(frc, str);
        return gv.getPixelBounds(null, x, y);
    }

    private Font getDesiredFont()
    {
        return new Font(Font.SANS_SERIF, Font.BOLD, 28);
    }

    private void startUI()
    {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(this);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) throws Exception
    {
        final StringBoundsPanel tb = new StringBoundsPanel();

        SwingUtilities.invokeAndWait(new Runnable()
        {
            public void run()
            {
                tb.startUI();
            }
        });
    }
}

ملحوظة أنني قد حذفت واردات لوضوح.

والنتيجة:

نصائح أخرى

ما الذي يجعلك تعتقد تقوم بإرجاع قيمة الخطأ؟ انها أكثر احتمالا بكثير أن توقعاتك لما تقوم بإرجاع لا يطابق المواصفات. لاحظ أنه بخير تماما إذا كان بعض رموزا في الخط تذهب فوق أو تحت تلك القيم.

وgetMaxDescent() وgetMaxAscent() ينبغي أن أقول لك القيم القصوى المطلقة من تلك الحقول لأي رسومي في الخط.

إذا كنت تريد أن تعرف المقاييس لسلسلة معينة، فإنك بالتأكيد نريد أن ندعو getLineMetrics().

وكتبت مؤخرا الكود بالأسفل وأنا بحاجة بكسل قياسات الارتفاع مثالية لنطاقات محددة من الخط (على سبيل المثال: كل الحروف أقل، أو كل الأرقام).

إذا كنت بحاجة إلى رمز أسرع (الألغام لديها لحلقات) أوصي تشغيله مرة واحدة في البدء للحصول على كل القيم (على سبيل المثال 1-100) في مجموعة وثم استخدام مجموعة بدلا من ذلك.

والرمز توجه أساسا كافة الأحرف من سلسلة الإدخال في نفس المكان تتداخل على 250x250 نقطية (زيادة أو تقليل إذا لزم الأمر)، فإنه يبدأ يبحث عن بكسل من أعلى، ثم من أسفل، ثم يعود الارتفاع الأقصى لتم العثور عليها. وهي تعمل مع السلاسل العادية حتى لو تم تصميمه لنطاقات الحرف. هذا يعني أن هناك نوعا من التكرار عند تقييم السلاسل العادية وبعض الشخصيات تكرار. حتى إذا تجاوزت سلسلة مدخلك عدد الحروف الأبجدية (26)، كما استخدم "tRange" يمبوت: "ABCD ... ض" وشخصيات أخرى التي يمكن استخدامها. وهو أسرع.

وعلى أمل أن يساعد.

public int getFontPixelHeight(float inSize, Paint sourcePaint, String tRange)
{
    // It is assumed that the font is already set in the sourcePaint

    int bW = 250, bH = 250;                                     // bitmap's width and height
    int firstContact = -1, lastContact = -2;                    // Used when scanning the pixel rows. Initial values are set so that if no pixels found, the returned result is zero.
    int tX = (int)(bW - inSize)/2, tY = (int)(bH - inSize)/2;   // Used for a rough centering of the displayed characters

    int tSum = 0;

    // Preserve the original paint attributes
    float oldSize = sourcePaint.getTextSize();
    int oldColor = sourcePaint.getColor();
    // Set the size/color
    sourcePaint.setTextSize(inSize); sourcePaint.setColor(Color.WHITE);

    // Create the temporary bitmap/canvas
    Bitmap.Config bConf = Bitmap.Config.ARGB_8888;
    Bitmap hld = Bitmap.createBitmap(250, 250, bConf);
    Canvas canv = new Canvas(hld);

    for (int i = 0; i < bH; i++)
    {
        for (int j = 0; j < bW; j++)
        {
            hld.setPixel(j, i, 0); // Zero all pixel values. This might seem redundant, but I am not quite sure that creating a blank bitmap means the pixel color value is indeed zero, and I need them to be zero so the addition performed below is correct.
        }
    }

    // Display all characters overlapping at the same position
    for (int i = 0; i < tRange.length(); i++)
    {
        canv.drawText("" + tRange.charAt(i), tX, tY, sourcePaint);
    }

    for (int i = 0; i < bH; i++)
    {
        for (int j = 0; j < bW; j++)
        {
            tSum = tSum + hld.getPixel(j, i);
        }

        if (tSum > 0) // If we found at least a pixel, save row index and exit loop
        {
            firstContact = i;
            tSum = 0;   // Reset
            break;
        }   
    }

    for (int i = bH - 1; i > 0 ; i--)
    {
        for (int j = 0; j < bW; j++)
        {
            tSum = tSum + hld.getPixel(j, i);
        }

        if (tSum > 0) // If we found at least a pixel, save row index and exit loop
        {
            lastContact = i;
            break;
        }   
    }

    // Restore the initial attributes, just in case the paint was passed byRef somehow
    sourcePaint.setTextSize(oldSize);
    sourcePaint.setColor(oldColor);

    return lastContact - firstContact + 1;
}

وgetHeight() لا يمكن بقطع الأسلة من سلسلة، فقط رسم سلسلة تستطيع أن تفعل ذلك. كنت تستخدم ارتفاع عاد من getHeight لرسم سلسلة بطريقة أو بأخرى، وعلى الأرجح كنت باساءة استخدام الارتفاع. على سبيل المثال، إذا قمت بوضع نقطة بداية السلسلة في الجزء السفلي من المربع الذي هو getHeight () عالية، ثم خط الأساس النص الخاص بك سوف يجلس على الحافة السفلية من مربع، ومن المرجح جدا سيتم قص الأسلة.

وهندسة النص هو موضوع معقد، يملؤه التحف التاريخية الغريبة. كما فعل آخرون قد اقترح، استخدم getAscent وgetDescent في محاولة لوضع الأساس بشكل صحيح ضمن المربع الخاص بك.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top