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); } } 

EDIT: Я должен упомянуть, что я знаю форму соотношения сторон: оригинальная высота / оригинальная ширина x новая ширина = новая высота. Однако я не знаю, как правильно использовать это в свою пользу.

Ну, самое быстрое и простое решение – использовать Image.getScaledInstance

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

Если вы задаетесь вопросом об отрицательном числе, java docs говорят:

Если ширина или высота являются отрицательным числом, тогда значение заменяется, чтобы сохранить соотношение сторон исходных размеров изображения. Если и ширина, и высота отрицательные, используются исходные размеры изображения.

ОБНОВИТЬ

Как примечание (мой Google играл).

getScaledInstance является ни самым быстрым, ни высоким качеством, но он самый простой.

Прочитайте «Опасности» Image.getScaledInstance для еще нескольких идей

ОБНОВИТЬ

Масштабирование изображения в зависимости от области немного сложнее, чем просто масштабирование соотношения сторон. Вам нужно сделать выбор, если вы хотите, чтобы изображение «поместилось» в пределах области (возможно, оставив пустые области вокруг нее) или поверх «заполнить» область (так, чтобы ее наименьший размер соответствовал наибольшему размеру области).

Поместитьсязаполнить

Fit & Fill

В принципе, я работаю с масштабными факторами

Это возвращает коэффициент масштабирования для определенного размера. Я использую это, чтобы принимать решения о том, какой фактор я хочу использовать, основываясь на том, какой алгоритм мне нужен

 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 s. Оригинал и цель.

 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); } } } 

который в конечном итоге масштабирует изображение до размера JPanel , используя getScaledInstance(int width, int height, ImageObserver io)

Для тех, кто заинтересован в том, чтобы использовать метод PaintComponent от MadProgrammer, это позволяет значительно ускорить отображение

  @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); } 

Я придумал это решение:

 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); } } } 
Interesting Posts
Давайте будем гением компьютера.