Używam FontMetrics.getHeight()
do uzyskania wysokości napisu, ale daje mi to złą wartość, odcinając znaki dolne znaków łańcuchowych. Czy istnieje lepsza funkcja, której mogę użyć?Jak uzyskać rzeczywistą wysokość napisów w Javie?
Odpowiedz
Sposób getStringBounds()
poniżej opiera się na GlyphVector
dla bieżącego Graphics2D
czcionki, która działa bardzo dobrze na jeden ciąg wiersza tekstu:
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();
}
});
}
}
Zauważ, że mam zrezygnować z importu dla jasności.
Rezultat:
FontMetrics.getAscent() i FontMetrics.getDescent() może załatwić sprawę.
Co sprawia, że myślisz, że zwraca niewłaściwą wartość? Jest o wiele bardziej prawdopodobne, że twoje oczekiwania co do tego, co powróci nie są zgodne ze specyfikacją. Zauważ, że jest to całkiem w porządku, jeśli niektóre glify w Fontzie przekroczą te wartości.
i getMaxAscent()
powinieneś podać bezwzględne maksymalne wartości tych pól dla dowolnego glifu w Czcionce.
Jeśli chcesz poznać dane konkretnego łańcucha, to z pewnością chcesz zadzwonić pod numer getLineMetrics()
.
getHeight()
nie może odciąć linii brzegowej łańcucha, tylko rysowanie łańcucha może to zrobić. Używasz wysokości zwróconej od getHeight
, aby jakoś narysować strunę i prawdopodobnie niewłaściwie używasz wysokości. Na przykład, jeśli umieścisz punkt początkowy ciągu na dole pola, które jest getHeight() wysokie, wówczas linia bazowa twojego tekstu zostanie umieszczona na dolnej krawędzi pola i bardzo prawdopodobne jest, że obcięcia zostaną obcięte.
Geometria tekstu to skomplikowany temat, przepełniony dziwnymi historycznymi artefaktami. Jak sugerowali inni, użyj getAscent
i getDescent
, aby spróbować prawidłowo ustawić linię bazową w swoim pudełku.
Niedawno napisałem poniższy kod jako potrzebowałem pikseli idealny pomiarów wysokości dla poszczególnych zakresów czcionki (na przykład wszystkie dolne znaki lub wszystkie).
Jeśli potrzebujesz szybszego kodu (moje ma dla pętli), poleciłbym go uruchomić raz przy starcie, aby uzyskać wszystkie wartości (na przykład od 1 do 100) w tablicy, a następnie użyć tablicy.
Kod zasadniczo rysuje wszystkie znaki z łańcucha wejściowego w tym samym miejscu nałożonym na mapę bitową 250x250 (w razie potrzeby zwiększ lub zmniejsz), rozpoczyna wyszukiwanie pikseli od góry, następnie od dołu, następnie zwraca maksymalną wysokość znalezioną . Działa z normalnymi ciągami, nawet jeśli został zaprojektowany dla zakresów znaków. Oznacza to, że istnieje pewien rodzaj nadmiarowości podczas oceniania regularnych ciągów znaków, jak powtarzają niektóre z nich. Więc jeśli twój ciąg znaków przekracza liczbę liter (26), użyj jako 'tRange' imput: "abcd ... z" i innych znaków, które mogą być użyte. To jest szybsze.
Nadzieję, że pomaga.
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;
}
- 1. tokenizer napisów w Javie
- 2. Jak uzyskać rzeczywistą użytkową rozdzielczość
- 3. Jak uzyskać rzeczywistą wysokość wiersza siatki z siatką o wysokości wiersza *
- 4. Jak uzyskać wysokość topLayoutGuide?
- 5. Jak uzyskać rzeczywistą pozycję węzła podrzędnego w SceneKit po obrocie?
- 6. Jak uzyskać wysokość linii przęsła?
- 7. Android: Jak uzyskać dokładną wysokość?
- 8. Jak uzyskać wysokość klawiatury Android?
- 9. Jak uzyskać wysokość ekranu w systemie Android?
- 10. Uzyskać wysokość Actionbar
- 11. Jak wykryć rzeczywistą dostępność sieci?
- 12. Jak uzyskać ostrzeżenia o nieprawidłowym formatowaniu napisów (C++)
- 13. Jak uzyskać nazwę klasy wywołującej w Javie?
- 14. Jak uzyskać tekst przycisku w Javie?
- 15. Jak uzyskać rozmiar klucza RSA w Javie
- 16. Jak uzyskać nazwę użytkownika Windows w Javie?
- 17. Jak poprawnie uzyskać nazwę wątku w Javie?
- 18. Jak uzyskać adres URL nadrzędny w Javie?
- 19. Jak uzyskać wszystkie wartości wyliczeniowe w Javie?
- 20. Jak uzyskać instancję oprzyrządowania w Javie
- 21. Jak uzyskać wzrost x% w px?
- 22. Jak uzyskać szerokość i wysokość obrazu?
- 23. Jak uzyskać wewnętrzną szerokość i wysokość formularza
- 24. javascript/jquery: jak uzyskać wewnętrzną wysokość okna?
- 25. GAE: Jak uzyskać wysokość blob-image
- 26. Jak mogę uzyskać wysokość daszka danego łańcucha?
- 27. Jak uzyskać wysokość tytułu paska tytułu WinForm?
- 28. Toolbar napisów nie pojawiają
- 29. Jak udokumentować podwójną tablicę napisów w JSDoc?
- 30. Jak uniknąć interpolacji napisów w Coffeespptrze
@nierito Świetna odpowiedź i świetne demo też! W oparciu o to, co powiedziałeś, próbowałem skrócić twój kod (zakładając, że zdefiniowałeś 'Font' i otrzymałeś od niego' FontMetrics'). Działa całkiem dobrze. 'czcionka.createGlyphVector (fontMetrics.getFontRenderContext(), text) .getVisualBounds(). getHeight(); ' –
W jaki sposób porównanie GlyphVector.getPixelBounds z Font.getStringBounds i TextLayout.getBounds? Czy bardziej złożony kod ma dużą zaletę? W prostym teście odkryłem, że metoda Czcionka zawyżała wysokość w porównaniu do pozostałych dwóch. Podoba mi się to, a TextLayout nie wymaga punktu X i Y. – jla
to 8 lat, ale kiedy używam g2d.scale (x, x); nie można wyświetlać poprawnie! – yelliver