我对drawString函数的质量有疑问,目前我有这个图片: example http://img541.imageshack.us/img541/4529/tcg4.jpg
基本上你在底部中间看到的是一张以125%大小绘制的卡片。背景中的卡片相对50%和25%。
但是我注意到,描述框中文本的质量不如它应该的那么好。我同意字体大小不是那么大,但为了适应所有文本,我需要提出一些解决方案,这似乎是现在最好的。
卡类:
package gui;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.font.GlyphVector;
import java.awt.font.LineMetrics;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;
import model.cards.Card;
/**
*
* @author Frank
*/
public class CardPanel extends JPanel {
private static final Dimension CARD_DIMENSION = new Dimension(250, 350);
private final Card card;
private final double scale;
private final boolean defaultOrientation;
private BufferedImage bufferedImage;
private BufferedImage scaledImage;
private BufferedImage backBufferedImage;
private BufferedImage backScaledImage;
public CardPanel(final Card card, final double scale) {
this(card, scale, true);
}
public CardPanel(final Card card, final double scale, final boolean defaultOrientation) {
this.card = card;
this.scale = scale;
this.defaultOrientation = defaultOrientation;
createImage();
scaleImage();
createBackImage();
scaleBackImage();
this.setPreferredSize(new Dimension(scaledImage.getWidth(), scaledImage.getHeight()));
}
public Card getCard() {
return card;
}
public double getScale() {
return scale;
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g.create();
//Graphics quality
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setComposite(AlphaComposite.Clear);
g2d.clearRect(0, 0, scaledImage.getWidth(), scaledImage.getHeight());
g2d.setComposite(AlphaComposite.SrcOver);
if (card.getFlipped()) {
g2d.drawImage(scaledImage, 0, 0, null);
}
else {
g2d.drawImage(backScaledImage, 0, 0, null);
}
g2d.dispose();
}
public BufferedImage getImage() {
if (card.getFlipped()) {
return scaledImage;
}
else {
return backScaledImage;
}
}
private void scaleImage() {
scaledImage = new BufferedImage((int)Math.floor(scale * CARD_DIMENSION.width), (int)Math.floor(scale * CARD_DIMENSION.height), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = (Graphics2D)scaledImage.getGraphics();
//Graphics quality
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.scale(scale, scale);
g2d.drawImage(bufferedImage, 0, 0, null);
g2d.dispose();
}
private void scaleBackImage() {
backScaledImage = new BufferedImage((int)Math.floor(scale * CARD_DIMENSION.width), (int)Math.floor(scale * CARD_DIMENSION.height), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = (Graphics2D)backScaledImage.getGraphics();
//Graphics quality
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.scale(scale, scale);
g2d.drawImage(backBufferedImage, 0, 0, null);
g2d.dispose();
}
private void createImage() {
bufferedImage = new BufferedImage(CARD_DIMENSION.width, CARD_DIMENSION.height, BufferedImage.TYPE_INT_ARGB);
final Graphics2D g2d = (Graphics2D)bufferedImage.createGraphics();
//Graphics quality
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
if (!defaultOrientation) {
g2d.rotate(Math.toRadians(180), bufferedImage.getWidth() / 2, bufferedImage.getHeight() / 2);
}
final int red = card.getColor().getRed();
final int green = card.getColor().getGreen();
final int blue = card.getColor().getBlue();
final Color color = new Color(red, green, blue);
new CustomRectangle(bufferedImage, CARD_DIMENSION.width, CARD_DIMENSION.height, 0, 0, 5, defaultOrientation) {
@Override
public void inBorder(final int dx, final int dy) {
setColor(new Color(red, green, blue, 255 - Math.min(dx, dy)));
}
@Override
public void outBorder(final int dx, final int dy) {
setColor(new Color(red, green, blue, 192 - Math.min(dx, dy)));
}
}.draw();
//Element
g2d.setColor(color);
g2d.fillPolygon(createPolygon(30, 30, 20, 20, 6));
g2d.setColor(Color.GRAY);
g2d.fillPolygon(createPolygon(30, 30, 15, 15, 6));
//Name
new CustomRectangle(bufferedImage, 140, 40, 55, 10, 5, defaultOrientation) {
@Override
public void inBorder(final int dx, final int dy) {
setColor(new Color(red, green, blue, 255 - Math.min(dx, dy)));
}
@Override
public void outBorder(final int dx, final int dy) {
setColor(new Color(red, green, blue, 128 - Math.min(dx, dy)));
}
}.draw();
//Display name
double nameStringX = 55 + (140 / 2);
double nameStringY = 10 + (40 / 2);
drawString(g2d, card.getName(), nameStringX, nameStringY, 40, Font.PLAIN, false, 0, 0);
//HP
g2d.setColor(color);
g2d.fillPolygon(createPolygon(220, 30, 20, 20, 6));
g2d.setColor(Color.GRAY);
g2d.fillPolygon(createPolygon(220, 30, 15, 15, 6));
//Display hp
double hpStringX = 220;
double hpStringY = 30;
drawString(g2d, card.getHitpoints() + "", hpStringX, hpStringY, 30, Font.PLAIN, false, 0, 0);
//Image
new CustomRectangle(bufferedImage, 220, 185, 15, 55, 5, defaultOrientation) {
@Override
public void inBorder(final int dx, final int dy) {
setColor(new Color(red, green, blue, 255 - Math.min(dx, dy)));
}
@Override
public void outBorder(final int dx, final int dy) {
setColor(Color.GRAY);
}
}.draw();
//Description
new CustomRectangle(bufferedImage, 220, 90, 15, 245, 5, defaultOrientation) {
@Override
public void inBorder(final int dx, final int dy) {
setColor(new Color(red, green, blue, 255 - Math.min(dx, dy)));
}
@Override
public void outBorder(final int dx, final int dy) {
setColor(new Color(red, green, blue, 128 - Math.min(dx, dy)));
}
}.draw();
//Display description
double descriptionStringX = 15 + 5 + 5;
double descriptionStringY = 245 + 5;
drawString(g2d, card.getDescription(), descriptionStringX, descriptionStringY, 18, Font.PLAIN, true, 220 - (2 * (5 + 5)), 30);
//Atk
g2d.setColor(color);
g2d.fillPolygon(createPolygon(30, 320, 20, 20, 6));
g2d.setColor(Color.GRAY);
g2d.fillPolygon(createPolygon(30, 320, 15, 15, 6));
//Display atk
double atkStringX = 30;
double atkStringY = 320;
drawString(g2d, card.getAttack() + "", atkStringX, atkStringY, 30, Font.PLAIN, false, 0, 0);
//Def
g2d.setColor(color);
g2d.fillPolygon(createPolygon(220, 320, 20, 20, 6));
g2d.setColor(Color.GRAY);
g2d.fillPolygon(createPolygon(220, 320, 15, 15, 6));
//Display def
double defStringX = 220;
double defStringY = 320;
drawString(g2d, card.getDefence() + "", defStringX, defStringY, 30, Font.PLAIN, false, 0, 0);
g2d.dispose();
}
private void createBackImage() {
backBufferedImage = new BufferedImage(CARD_DIMENSION.width, CARD_DIMENSION.height, BufferedImage.TYPE_INT_ARGB);
final Graphics2D g2d = (Graphics2D)backBufferedImage.createGraphics();
//Graphics quality
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
if (!defaultOrientation) {
g2d.rotate(Math.toRadians(180), backBufferedImage.getWidth() / 2, backBufferedImage.getHeight() / 2);
}
final int red = 150;
final int green = 75;
final int blue = 0;
new CustomRectangle(backBufferedImage, CARD_DIMENSION.width, CARD_DIMENSION.height, 0, 0, 5, defaultOrientation) {
@Override
public void inBorder(final int dx, final int dy) {
setColor(new Color(red, green, blue, 255 - Math.min(dx, dy)));
}
@Override
public void outBorder(final int dx, final int dy) {
setColor(new Color(red, green, blue, 192 - Math.min(dx, dy)));
}
}.draw();
g2d.dispose();
}
private Polygon createPolygon(final int xOffset, final int yOffset, final int xDiameter, final int yDiameter, final int sides) {
Polygon polygon = new Polygon();
for (int i = 0; i < sides; i++) {
int px = (int)Math.round(xOffset + (xDiameter * Math.cos(i * 2 * Math.PI / sides)));
int py = (int)Math.round(yOffset + (yDiameter * Math.sin(i * 2 * Math.PI / sides)));
polygon.addPoint(px, py);
}
return polygon;
}
private void drawString(final Graphics2D g2d, final String string, final double xOffset, final double yOffset, final double size, final int style, final boolean description, double descriptionWidth, final double usedWidth) {
double stringX = xOffset;
double stringY = yOffset;
g2d.setFont(new Font("SansSerif"/*g2d.getFont().getFamily()*/, style, (int)Math.round(size * 0.9 * 0.5)));
FontMetrics fontMetrics = g2d.getFontMetrics();
LineMetrics lineMetrics = g2d.getFont().getLineMetrics(string, g2d.getFontRenderContext());
if (!description) {
stringX -= (fontMetrics.stringWidth(string) / 2);
stringY += ((lineMetrics.getAscent() + lineMetrics.getDescent()) / 2) - lineMetrics.getDescent();
g2d.setColor(Color.BLACK);
g2d.drawString(string, (int)Math.round(stringX), (int)Math.round(stringY));
}
else {
stringY += lineMetrics.getAscent();
double wordXOffset = 0;;
double wordYOffset = 0;
int yCount = 0;
for (String word : string.split(" ")) {
int width = fontMetrics.stringWidth(word + " ");
if (wordXOffset + width > descriptionWidth) {
wordXOffset = 0;
wordYOffset = wordYOffset + fontMetrics.getHeight();
yCount++;
if (yCount == 3) {
descriptionWidth -= usedWidth;
}
if (yCount >= 3) {
wordXOffset += usedWidth;
}
}
g2d.drawString(word, (int)Math.round(stringX + wordXOffset), (int)Math.round(stringY + wordYOffset));
wordXOffset += width;
}
}
}
}
我希望问题不会太长,但是我可以通过哪些方式提高屏幕上绘制文字的质量?
我可能会在某些时候将中间卡的大小从125%更改为200%,并将其显示在屏幕的中心位置,因此文本的质量必须尽可能高。
答案 0 :(得分:2)
Graphics2D允许设置rendering hints。尝试进行实验,有various possible options,最佳值可能取决于所选字体和其他详细信息。
答案 1 :(得分:1)
一个问题是如何缩放卡片。您似乎以100%创建了卡的BufferedImage,并将其扩展到125%。此时,文本不再是文本,而是图像的一部分。从最大分辨率开始并缩小到缩略图,您会更安全。如果允许字体以每种分辨率呈现,则外观最佳。