你如何使用重新调整所有Graphic2D的大小

2 java swing render jframe image-resizing

在java中你怎么能让游戏完全实现!但是逻辑和图形可以用它吗?我尝试过使用SCALE方法.但这并不能让每台电脑完全全屏.所以我做了这个:

    public void resize(int WIDTH, int HEIGHT, boolean UNDECORATED) {

          frame.setPreferredSize(new Dimension(WIDTH, HEIGHT));
          frame.setMaximumSize(new Dimension(WIDTH, HEIGHT));
          frame.setMinimumSize(new Dimension(WIDTH, HEIGHT));

          this.WIDTH = WIDTH;
          this.HEIGHT = HEIGHT;
          frame.setUndecorated(UNDECORATED);
          frame.setSize(WIDTH, HEIGHT);
      }
Run Code Online (Sandbox Code Playgroud)

因此,您可以将屏幕大小设置为您想要的任何值!它工作但图形不适用它?Graphics2D中是否有一种方法可以拉伸所有图形以使其适合?例如,如果有一个方法存在,如:

            G2D.resize(WIDTH, HEIGHT, Image.NEAREST_PARENT_RESCALE);
Run Code Online (Sandbox Code Playgroud)

任何的想法?

我尝试过的事情:

  • 将所有图形绘制到缓冲图像,然后将该图像绘制到屏幕尺寸上.
  • 只需使用SCALE并进行WIDTH*SCALE等
  • 很多数学

我不介意的事情

  • 如果你有一个WIDE-SCREEN,它会将graphic2D对象拉伸到这个大小.
  • 如果你有一个SQUARE-SCREEN它会将graphics2D对象调整到这个大小.

那么如何使用Graphics2D,JFrame制作完全可重复密封的游戏.

Mar*_*o13 12

在最通用的形式中,人们可以将其视为图形编程的经典问题,即从世界坐标屏幕坐标的转换.在世界坐标系中有一个大小为"1.0 x 1.0"的对象(无论它具有哪个单位).并且应该对该对象进行绘制,使其在屏幕上具有例如"600像素×600像素"的大小.

从广义上讲,在Swing中至少有三种方法可以实现这一目标:

  • 您可以绘制成图像,然后绘制图像的缩放版本
  • 您可以绘制成缩放Graphics2D对象
  • 您可以绘制缩放的对象

每一个都有可能的优点和缺点,以及隐藏的警告.

绘制图像,并绘制图像的缩放版本:

这可能看起来像一个简单的解决方案,但有一个潜在的缺点:图像本身具有一定的分辨率(大小).如果图像太小,并且您要将其缩放以填充屏幕,则可能看起来很块.如果图像太大,并且您将其缩小以适合屏幕,则图像的像素可能会丢失.

在这两种情况下,缩放图像的过程都有几个调整参数.实际上,缩放图像远比第一眼看上去要复杂得多.有关详细信息,请参阅Chris Campbell 撰写的文章The Perils of Image.getScaledInstance().

绘制成缩放的Graphics2D对象

Graphics2D已经提供了完整的功能所必需的创造之间的变换世界坐标系屏幕坐标系.这是由Graphics2D类通过内部存储来完成的AffineTransform,它描述了这种转换.这AffineTransform可以通过Graphics2D对象直接修改:

void paintSomething(Graphics2D g) {
    ...
    g.draw(someShape);

    // Everything that is painted after this line will
    // be painted 3 times as large: 
    g.scale(3.0, 3.0);

    g.draw(someShape); // Will be drawn larger 
}
Run Code Online (Sandbox Code Playgroud)

必须注意正确管理存储在Graphics2D对象中的变换.通常,应该AffineTransform在应用其他转换之前创建原始备份,然后恢复此原始转换:

// Create a backup of the original transform
AffineTransform oldAT = g.getTransform();

// Apply some transformations
g.scale(3.0, 4.0);
g.translate(10.0, 20.0);

// Do custom painting the the transformed graphics
paintSomething(g):

// Restore the original transformation
g.setTransform(oldAT);
Run Code Online (Sandbox Code Playgroud)

(对于最后一种方法的另一个建议:永远不应该使用该Graphics2D#setTransform方法 在现有变换之上应用新的坐标变换.它仅用于恢复"旧"变换,如本示例所示(并且在文档中)这种方法)).

使用Graphics2D该类缩放的一个潜在缺点是,之后,所有内容都将被缩放.特别地,该缩放将影响线宽(即,宽度中风).例如,考虑一下这样的调用序列:

// By default, this will paint a line with a width (stroke) of 1.0:
g.draw(someLine);

// Apply some scaling...
g.scale(10.0, 10.0);

// Now, this will paint the same line, but with a width of 10. 
g.draw(someLine);
Run Code Online (Sandbox Code Playgroud)

第二次调用将导致绘制一条宽10像素的线.在许多情况下可能不需要这样做.第三种选择可以避免这种影响:

绘制缩放的对象

世界坐标系屏幕坐标系之间的转换也可以手动维护.将此表示为一个很方便AffineTransform.的AffineTransform类可以被用于创建的转换版本Shape对象,然后可以直接吸入进( -转化的)Graphics2D对象.这是通过以下AffineTransform#createTransformedShape方法完成的:

void paintSomething(Graphics2D g) {
    ...
    // Draw some shape in its normal size
    g.draw(someShape);

    // Create a scaling transform
    AffineTransform at = AffineTransform.getScaleInstance(3.0, 3.0);

    // Create a scaled version of the shape
    Shape transformedShape = at.createTransformedShape(someShape);

    // Draw the scaled shape
    g.draw(transformedShape);
}
Run Code Online (Sandbox Code Playgroud)

这可能是最通用的方法.唯一的潜在缺点是,当绘制许多小而简单的形状时,这将导致产生许多小的临时变形形状,这可能导致性能降低.(有一些方法可以缓解这个问题,但详细的性能考虑和优化超出了这个答案的范围).


摘要

下图显示了所有方法的比较.Shape绘制了一些示例对象(表示为对象).每行比较上面提到的三种不同的缩放方法.使用"默认"大小,对象将填充大小为100x100的世界坐标中的矩形.在前两行中,它们按比例放大以填充屏幕上190x190像素的区域.在最后两行中,它们按比例缩小以填充屏幕上60x60像素的区域.(选择这些尺寸是为了使一些"奇数"缩放因子为1.9和0.6.当缩放因子是整数时,某些效果(伪像)可能不会出现,或者恰好为0.5).

对于升级和降尺度,还有"标准"绘画方式和"高质量"绘画之间的比较(在每个小组的标题中用"(HQ)"表示).这里的"高质量"仅仅意味着渲染提示

KEY_ANTIALIAS = VALUE_ANTIALIAS_ON
KEY_RENDERING = VALUE_RENDER_QUALITY
Run Code Online (Sandbox Code Playgroud)

已经设定:

ScalingMethods

这是相应的程序,作为MCVE:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class ScalingMethodComparison
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                createAndShowGUI();
            }
        });
    }
    private static void createAndShowGUI()
    {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.getContentPane().setLayout(new GridLayout(0,1));

        Dimension larger = new Dimension(190,190);
        Dimension smaller = new Dimension(60,60);

        f.getContentPane().add(createPanel(larger, false));
        f.getContentPane().add(createPanel(larger, true));
        f.getContentPane().add(createPanel(smaller, false));
        f.getContentPane().add(createPanel(smaller, true));

        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    private static JPanel createPanel(Dimension d, boolean highQuality)
    {
        JPanel p = new JPanel(new GridLayout(1,3));
        for (ScalingMethodComparisonPanel.ScalingMethod scalingMethod : 
            ScalingMethodComparisonPanel.ScalingMethod.values())
        {
            p.add(createPanel(d, scalingMethod, highQuality));
        }
        return p;
    }

    private static JPanel createPanel(
        Dimension d, ScalingMethodComparisonPanel.ScalingMethod scalingMethod, 
        boolean highQuality)
    {
        JPanel p = new JPanel(new GridLayout(1,1));
        p.setBorder(BorderFactory.createTitledBorder(
            scalingMethod.toString()+(highQuality?" (HQ)":"")));
        JPanel scalingMethodComparisonPanel = 
            new ScalingMethodComparisonPanel(
                createObjects(), d, scalingMethod, highQuality);
        p.add(scalingMethodComparisonPanel);
        return p;
    }

    // Returns a list of objects that should be drawn, 
    // occupying a rectangle of 100x100 in WORLD COORDINATES
    private static List<Shape> createObjects()
    {
        List<Shape> objects = new ArrayList<Shape>();
        objects.add(new Ellipse2D.Double(10,10,80,80));
        objects.add(new Rectangle2D.Double(20,20,60,60));
        objects.add(new Line2D.Double(30,30,70,70));
        return objects;
    }
}


class ScalingMethodComparisonPanel extends JPanel
{
    private static final Color COLORS[] = {
        Color.RED, Color.GREEN, Color.BLUE,
    };

    enum ScalingMethod
    {
        SCALING_IMAGE,
        SCALING_GRAPHICS,
        SCALING_SHAPES,
    }

    private final List<Shape> objects;
    private final ScalingMethod scalingMethod;
    private final boolean highQuality;

    private final Dimension originalSize = new Dimension(100,100);
    private final Dimension scaledSize;

    private BufferedImage image;

    public ScalingMethodComparisonPanel(
        List<Shape> objects,
        Dimension scaledSize,
        ScalingMethod scalingMethod,
        boolean highQuality)
    {
        this.objects = objects;
        this.scaledSize = new Dimension(scaledSize);
        this.scalingMethod = scalingMethod;
        this.highQuality = highQuality;
    }

    @Override
    public Dimension getPreferredSize()
    {
        return new Dimension(scaledSize);
    }

    @Override
    protected void paintComponent(Graphics gr)
    {
        super.paintComponent(gr);
        Graphics2D g = (Graphics2D)gr;
        g.setColor(Color.WHITE);
        g.fillRect(0,0,getWidth(), getHeight());

        if (highQuality)
        {
            g.setRenderingHint( 
                RenderingHints.KEY_ANTIALIASING, 
                RenderingHints.VALUE_ANTIALIAS_ON);
            g.setRenderingHint(
                RenderingHints.KEY_RENDERING, 
                RenderingHints.VALUE_RENDER_QUALITY);
        }

        if (scalingMethod == ScalingMethod.SCALING_IMAGE)
        {
            paintByScalingImage(g);
        }
        else if (scalingMethod == ScalingMethod.SCALING_GRAPHICS)
        {
            paintByScalingGraphics(g);
        }
        else if (scalingMethod == ScalingMethod.SCALING_SHAPES)
        {
            paintByScalingShapes(g);
        }
    }

    private void paintByScalingImage(Graphics2D g)
    {
        if (image == null)
        {
            image = new BufferedImage(
                originalSize.width, originalSize.height,
                BufferedImage.TYPE_INT_ARGB);
        }
        Graphics2D ig = image.createGraphics();
        paintObjects(ig, null);
        ig.dispose();

        g.drawImage(image, 0, 0, scaledSize.width, scaledSize.height, null);
    }

    private void paintByScalingGraphics(Graphics2D g)
    {
        AffineTransform oldAT = g.getTransform();
        double scaleX = (double)scaledSize.width / originalSize.width;
        double scaleY = (double)scaledSize.height / originalSize.height;
        g.scale(scaleX, scaleY);
        paintObjects(g, null);
        g.setTransform(oldAT);
    }

    private void paintByScalingShapes(Graphics2D g)
    {
        double scaleX = (double)scaledSize.width / originalSize.width;
        double scaleY = (double)scaledSize.height / originalSize.height;
        AffineTransform at = 
            AffineTransform.getScaleInstance(scaleX, scaleY);
        paintObjects(g, at);
    }



    private void paintObjects(Graphics2D g, AffineTransform at)
    {
        for (int i=0; i<objects.size(); i++)
        {
            Shape shape = objects.get(i);
            g.setColor(COLORS[i%COLORS.length]);
            if (at == null)
            {
                g.draw(shape);
            }
            else
            {
                g.draw(at.createTransformedShape(shape));
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)