Java:保持JPanel背景图像的纵横比
我有一个带有绘制背景图像的JPanel
和一个布局pipe理器,其中包含所有的JFrame
。 背景图像相当大,我希望能够保持它的宽高比,无论是在一个大的或小的显示器上。
最终,我希望能够将我的LayoutManager
和其单元格中的较小图像粘贴到背景图片上。
我环顾四周寻找资源,似乎很多例子使用了一个BufferedImage
但我不是; 这会造成一个问题吗? 我将在下面张贴我的代码来绘制图像,如果我缺less任何信息,请让我知道。
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); } }
编辑:我应该提到,我知道宽高比公式: 原始高度/原始宽度×新宽度=新高度但是,我不知道如何正确使用我的优势。
那么,最快最简单的解决scheme就是使用Image.getScaledInstance
g.drawImage(img.getScaledInstance(newWidth, -1, Image. SCALE_SMOOTH), x, y, this);
如果你想知道负数,java文档说:
如果宽度或高度是负数,则会replace一个值以保持原始图像尺寸的纵横比。 如果宽度和高度均为负数,则使用原始图像尺寸。
UPDATE
就像一个侧面说明(我的谷歌正在玩)。
getScaledInstance
既不是最快的或最高质量的方法,但它是最简单的。
阅读Image.getScaledInstance中的更多想法
UPDATE
缩放图像以适应区域稍微复杂一些,然后简单地缩放纵横比。 如果要让图像在区域内“适合”(可能会留下空白区域)或“填充”区域(使其最小尺寸适合该区域的最大尺寸),则必须作出select。
适合和填充
基本上,我使用比例因子
这将返回特定大小的缩放因子。 我使用这个来根据我需要的algorithm来决定使用哪个因子
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; }
它被这两种方法所使用。 他们只需要两个Dimension
。 原来的和目标。
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); }
尝试这样的事情:
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
的大小。
对于任何有兴趣修改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); }
我想出了这个解决scheme:
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); } } }