web-dev-qa-db-ja.com

Java:JPanel背景画像のアスペクト比を維持する

私はJPanelにペイントされた背景画像と、他の小さな画像を保持するレイアウトマネージャーを持っています。これらはすべてJFrameの中にあります。背景画像はかなり大きいので、大きいモニターでも小さいモニターでもアスペクト比を維持できるようにしたいと考えています。

最終的には、セル内のLayoutManagerと小さい画像を背景画像に「接着」できるようにしたいと考えています。

リソースを探してみたところ、多くの例ではBufferedImageを使用しているようですが、私はそうではありません。これは問題になりますか?画像をペイントするためのコードを以下に投稿します。情報が不足している場合はお知らせください。

public class MonitorPanel extends JPanel {
    Image img;
    public MonitorPanel() throws MalformedURLException {
        //add components

        try {
            img = ImageIO.read(new File("src/customer_vlans.jpg"));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
protected void paintComponent(Graphics g)
{
    //Paint background image
    super.paintComponent(g);
    //g.drawImage(img, 0, 0, getWidth(), getHeight(), this);
    g.drawImage(img, 0, 0, this);

}

}

編集:アスペクト比の式を知っていることをお伝えしておきます:元の高さ/元の幅x新しい幅=新しい高さただし、私はそれを私の利点に正しく使用する方法がわかりません。

20
exit_1

さて、最も早くて簡単な解決策はImage.getScaledInstance

g.drawImage(img.getScaledInstance(newWidth, -1, Image. SCALE_SMOOTH), x, y, this);

負の数について疑問に思っている場合は、Java docsと言う:

幅または高さのいずれかが負の数の場合、元の画像の寸法のアスペクト比を維持するために値が置き換えられます。幅と高さの両方が負の場合、元の画像の寸法が使用されます。

[〜#〜]更新[〜#〜]

余談ですが(私のグーグルは遊んでいました)。

getScaledInstanceは最速でも最高品質でもありませんが、最も簡単な方法です。

その他のアイデアについては、 The Perils of Image.getScaledInstance を読んでください。

[〜#〜]更新[〜#〜]

領域に合わせて画像を拡大縮小することは、単にアスペクト比を拡大縮小するよりも少し複雑です。画像を領域内に「収める」(おそらくその周囲に空白の領域を残す)か、領域を「塗りつぶす」か(最小サイズが領域の最大サイズに合うようにする)かを選択する必要があります。

FitFill

フィット&フィル

基本的に、私はスケールファクターで作業します

これは、特定のサイズの倍率を返します。これを使用して、必要なアルゴリズムに基づいて、使用したい要素を決定します

public static double getScaleFactor(int iMasterSize, int iTargetSize) {

    double dScale = 1;
    if (iMasterSize > iTargetSize) {

        dScale = (double) iTargetSize / (double) iMasterSize;

    } else {

        dScale = (double) iTargetSize / (double) iMasterSize;

    }

    return dScale;

}

これらの2つの方法で使用されます。彼らは単に2つのDimensionsをとります。オリジナルとターゲット。

public static double getScaleFactorToFit(Dimension original, Dimension toFit) {

    double dScale = 1d;

    if (original != null && toFit != null) {

        double dScaleWidth = getScaleFactor(original.width, toFit.width);
        double dScaleHeight = getScaleFactor(original.height, toFit.height);

        dScale = Math.min(dScaleHeight, dScaleWidth);

    }

    return dScale;

}

public static double getScaleFactorToFill(Dimension masterSize, Dimension targetSize) {

    double dScaleWidth = getScaleFactor(masterSize.width, targetSize.width);
    double dScaleHeight = getScaleFactor(masterSize.height, targetSize.height);

    double dScale = Math.max(dScaleHeight, dScaleWidth);

    return dScale;

}

画像を(直接またはサポートメソッドを介して)に渡すのは比較的簡単です。したがって、たとえば、これをPaintメソッド内から呼び出すことができます

double factor getScaledFactorToFit(new Dimension(image.getWidth(), image.getHeight()), getSize());

int scaledWidth = image.getWidth() * scale;
int scaledHeight *= image.getWidth() * scale;

これにより、アスペクト比が自動的に処理されます;)

拡張された例で更新されました

public double getScaleFactor(int iMasterSize, int iTargetSize) {

    double dScale = 1;
    if (iMasterSize > iTargetSize) {

        dScale = (double) iTargetSize / (double) iMasterSize;

    } else {

        dScale = (double) iTargetSize / (double) iMasterSize;

    }

    return dScale;

}

public double getScaleFactorToFit(Dimension original, Dimension toFit) {

    double dScale = 1d;

    if (original != null && toFit != null) {

        double dScaleWidth = getScaleFactor(original.width, toFit.width);
        double dScaleHeight = getScaleFactor(original.height, toFit.height);

        dScale = Math.min(dScaleHeight, dScaleWidth);

    }

    return dScale;

}

@Override
protected void paintComponent(Graphics g) {

    super.paintComponent(g);

    double scaleFactor = Math.min(1d, getScaleFactorToFit(new Dimension(image.getWidth(), image.getHeight()), getSize()));

    int scaleWidth = (int) Math.round(image.getWidth() * scaleFactor);
    int scaleHeight = (int) Math.round(image.getHeight() * scaleFactor);

    Image scaled = image.getScaledInstance(scaleWidth, scaleHeight, Image.SCALE_SMOOTH);

    int width = getWidth() - 1;
    int height = getHeight() - 1;

    int x = (width - scaled.getWidth(this)) / 2;
    int y = (height - scaled.getHeight(this)) / 2;

    g.drawImage(scaled, x, y, this);

}
45
MadProgrammer

このようなものを試してください:

_import Java.awt.*;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class SG2B2 {

    JFrame frame;

    public static void main(String[] args) {
        SG2B2 gui = new SG2B2();
        gui.createUI();
    }

    public void createUI() {
        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        MyDrawPanel drawPanel = new MyDrawPanel();
        frame.getContentPane().add(BorderLayout.CENTER, drawPanel);
        frame.setSize(300, 400);
        frame.setVisible(true);
    }

    class MyDrawPanel extends JPanel {

        Image image;
        private final String pic = "Logo.jpg";

        public MyDrawPanel() {
            image = new ImageIcon(pic).getImage();
            image = scaleImage(image);
        }

        @Override
        public void paintComponent(Graphics g) {
            Graphics2D g2 = (Graphics2D) g;
            g2.drawImage(image, 0, 0, this);
        }

        private Image scaleImage(Image rawImage) {
            Image scaledImage = null;
            System.out.println("Scaling");
            try {
                int rawImageWidth = rawImage.getWidth(this);
                int rawImageHeight = rawImage.getHeight(this);
                int paneWidth = (int) getWidth();
                int paneHeight = (int) getHeight();
                System.out.println("Image W = " + rawImageWidth
                        + ", H = " + rawImageHeight
                        + "; Pane W = " + paneWidth
                        + ", H = " + paneHeight);
                // preserve the original ratio  
                float widthRatio = (float) rawImageWidth / (float) paneWidth;
                float heightRatio = (float) rawImageHeight / (float) paneHeight;
                int widthFactor = -1;
                int heightFactor = -1;
                if ((widthRatio > heightRatio) && (widthRatio > 1.0)) {
                    widthFactor = paneWidth;
                } else if ((heightRatio > widthRatio) && (heightRatio > 1.0)) {
                    heightFactor = paneHeight;
                }
                System.out.println("widthRatio = "
                        + String.format("%.3f", widthRatio)
                        + ", heightRatio = "
                        + String.format("%.3f", heightRatio));
                System.out.println("widthFactor = " + widthFactor
                        + ", heightFactor = " + heightFactor);
                if ((widthFactor < 0) && (heightFactor < 0)) {
                    scaledImage = rawImage;
                } else {
                    scaledImage = rawImage.getScaledInstance(widthFactor, heightFactor,
                            Image.SCALE_SMOOTH);
                    // load the new image, 'getScaledInstance' loads asynchronously  
                    MediaTracker tracker = new MediaTracker(this);
                    tracker.addImage(scaledImage, 0);
                    tracker.waitForID(0);
                }
            } catch (InterruptedException ie) {
                System.err.println("load interrupt: " + ie.getMessage());
            } catch (Exception e) {
                e.printStackTrace();
            }
            return (scaledImage);
        }
    }
}
_

getScaledInstance(int width, int height, ImageObserver io)を使用して、最終的に画像をJPanelのサイズにスケーリングします

4
David Kroukamp

以下のようにMadProgrammerによってPaintComponentメソッドを修正することに関心のある人は、表示の更新をより迅速に行うことができます。

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

            double scaleFactor = Math.min(1d, getScaleFactorToFit(new Dimension(image.getWidth(), image.getHeight()), getSize()));

            int scaleWidth = (int) Math.round(image.getWidth() * scaleFactor);
            int scaleHeight = (int) Math.round(image.getHeight() * scaleFactor);

            //Image scaled = image.getScaledInstance(scaleWidth, scaleHeight, Image.SCALE_SMOOTH);

            int width = getWidth() - 1;
            int height = getHeight() - 1;

            int x = (width - scaleWidth) / 2;
            int y = (height - scaleHeight) / 2;

            g2d.drawImage(image, x, y, scaleWidth, scaleHeight, this);

        }
2
Joe

私はこの解決策を思いつきました:

public class ImageLabel extends JPanel {

    private Image image = null;

    public void setImage(Image img) {
        image = img;
        repaint();
    }

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

        if (image != null) {

            int imgWidth, imgHeight;
            double contRatio = (double) getWidth() / (double) getHeight();
            double imgRatio =  (double) image.getWidth(this) / (double) image.getHeight(this);

            //width limited
            if(contRatio < imgRatio){
                imgWidth = getWidth();
                imgHeight = (int) (getWidth() / imgRatio);

            //height limited
            }else{
                imgWidth = (int) (getHeight() * imgRatio);
                imgHeight = getHeight();
            }

            //to center
            int x = (int) (((double) getWidth() / 2) - ((double) imgWidth / 2));
            int y = (int) (((double) getHeight()/ 2) - ((double) imgHeight / 2));

            g.drawImage(image, x, y, imgWidth, imgHeight, this);
        }
    }
}
1