2

我对 drawString 函数的质量有疑问,目前我有这张图片: 例子

基本上你在底部中间看到的是一张按其大小的 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%,并将其显示在屏幕的中心位置,因此文本的质量必须尽可能高。

4

2 回答 2

2

Graphics2D 允许设置渲染提示。尝试尝试,有各种可能的选项,最佳值可能取决于所选字体和其他细节。

于 2013-04-07T17:54:01.870 回答
1

一个问题是如何扩展卡。看来您以 100% 创建了卡片的 BufferedImage 并将其缩放到 125%。此时,文本不再是文本,而是图像的一部分。从最大分辨率开始,一直到缩略图,您会更安全。如果允许字体以每种分辨率呈现,则外观将是最好的。

于 2013-04-16T06:28:09.247 回答