Search code examples
javaimageuser-interfaceimage-processingscaling

Image displayed in original size and cropped instead of scaled down


I am writing a program that is supposed to display changing images in a slideshow. For that the intent is to scale down the images so they will not burst out of the borders of the screen. But instead of being displayed as scaled down, the images are shown in their original size and cropped at the sides.

By now I have already tried different approaches - trying the methods .getScaledInstance() (which is only delivering this nonsense), tried to redraw the files using Graphis or Graphis2D, which only returned white surfaces, tried implementing Scalr and Thumbnator (which didn't work at all but only threw error messages) and Marvin which wouldn't even compile. So possible solutions like in this tutorial or here on stackoverflow have been unsuccessfull for me.

At this point I am seriously lost and in dire need of help.

The code I am using is in this state right now:

    public class Main {
        
        Dimension screenSize = new Dimension();
        DisplayImage comp = new DisplayImage();
        File error = new File("error.jpg");

        public static void main(String[] args) throws IOException {
            
            List<File> fileList = new ArrayList<File>();
            
            //fill the list
            fileList.add(new File("test1.jpg"));
            fileList.add(new File("test2.jpg"));
            fileList.add(new File("test3.jpg"));
            fileList.add(new File("test4.jpg"));
            
            screenSize.setSize(GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()[0].getDisplayMode().getWidth(), GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()[0].getDisplayMode().getHeight());
            JFrame frame = TextDisplay.displayText(comp, screenSize);
            long refactoring = System.currentTimeMillis();
            
            for (int i = 0;i<fileList.size();i++) {
                
                while (1*1000 > System.currentTimeMillis() - refactoring+2) {
                    Thread.sleep(1l);       //SlideShow is supposed to wait for a fixed amount of time before loading the next picture
                }
                loadDisplay(fileList.get(i));
            }
            frame.dispose();
        }

        //loads a new picture into the JComponent, updating the old one.
        private void loadDisplay(File imageFile) throws IOException {
            
            if (imageFile.exists()) {
                if(ImageIO.read(imageFile) != null) {
                    comp.setImage(DisplayImage.displayImage(imageFile, screenSize));
                } else {
                    comp.setImage(DisplayImage.displayImage(error, screenSize));
                }
            } else {
                comp.setImage(DisplayImage.displayImage(error, screenSize));
            }
        }
    }
    
    
    //This extension class for JComponent is supposed to organize the pictures for the slideshow
    public class DisplayImage extends JComponent {
        
        private static final long serialVersionUID = 8027213542020243319L;
        private static Image image;
        
        @Override
        protected void paintComponent(Graphics g) {
           if (image != null) {
              g.drawImage(image, 0, 0, this);
           }
        }
        
        //This method that is supposed to load and (if neccessary) rescale the pictures.
        public static Image displayImage(File f, Dimension screenSize) throws IOException {
            
            BufferedImage originalImage = ImageIO.read(f);
            double width = screenSize.getWidth()*0.75;
            double z1 = (originalImage.getWidth()/width);
            double z2 = (originalImage.getHeight()/(screenSize.getHeight()-20));
            int setWidth, setHeight;

            //case 1: height is smaller than width so scaling depends on the width
            if (originalImage.getHeight()/z1 <= width && originalImage.getHeight()/z1 < (screenSize.getHeight()-20)) {

                if (originalImage.getWidth()/z1 < width) {
                    setWidth = (int) width;
                    setHeight = (int)((originalImage.getHeight()/z1)*((originalImage.getWidth()/z1)/width));
                } else {
                    setWidth = (int) (originalImage.getWidth()/z1);
                    setHeight = (int)(originalImage.getHeight()/z1);
                }

            //case 2: width is smaller than height so scaling depends on the height
            } else {
                if (originalImage.getHeight()/z2 < (screenSize.getHeight()-20)) {
                    setWidth = (int) width;
                    setHeight = (int)((originalImage.getHeight()/z2)/(originalImage.getWidth()/z2)*width);
                } else {
                    setWidth = (int) (originalImage.getWidth()/z2);
                    setHeight = (int)(originalImage.getHeight()/z2);
                }
            }
            return originalImage.getScaledInstance(setWidth, setHeight, Image.SCALE_AREA_AVERAGING);
        }
    }


    //This class is supposed to organize the frame-elements for the slideshow.
    //The frame should contain a place fot the scaled down picture as well as a text area to display text to the pictures.
    public class TextDisplay {
        
        public static JTextArea textField = new JTextArea();
        private static JSplitPane panelText = new JSplitPane();
        private final static JSplitPane mainPanel = new JSplitPane();
        private static JFrame frame = new JFrame();
        
        public static void setText(String string) {
            operatorsField.setText(string);     
        }   

        public static void setFont(Font font) {
            operatorsField.setFont(font);       
        }
        
        
        public static JFrame displayText(DisplayImage comp, Dimension screenSize) {
            
            textField.setLayout((LayoutManager) new BoxLayout(textField, BoxLayout.Y_AXIS));
            textField.setPreferredSize(new Dimension(screenSize.getWidth()/5,screenSize.getHeight()));
            textField.setFont(new Font("Tahoma", Font.PLAIN, 25));
            textField.setLineWrap(true);
            textField.setWrapStyleWord(true);
            textField.setEditable(false);
            textField.setFocusable(true);
            
            
            panelText.setLayout(new BoxLayout(panelText, BoxLayout.Y_AXIS));
            panelText.setOrientation(JSplitPane.VERTICAL_SPLIT);
            panelText.setOneTouchExpandable(false);
            panelText.setFocusable(true);
            panelText.setBottomComponent(textField);
            
            mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
            mainPanel.setOrientation(JSplitPane.VERTICAL_SPLIT);
            mainPanel.setDividerLocation(70);
            mainPanel.setDividerSize(0);
            mainPanel.setOneTouchExpandable(false);
            mainPanel.setFocusable(true);
            mainPanel.setBottomComponent(panelText);
            mainPanel.setEnabled(false);
        
            
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setPreferredSize(screenSize);
            frame.setVisible(true);
            frame.add(comp, BorderLayout.CENTER);
            frame.add(mainPanel,BorderLayout.EAST);
            frame.pack();
            
            return frame;
        }
    }

How do I make the program scale down the images I want to display instead of cropping them?


Solution

  • Here's a complete example:

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.GraphicsDevice;
    import java.awt.GraphicsEnvironment;
    import java.awt.Image;
    import java.awt.RenderingHints;
    import java.io.File;
    import java.io.IOException;
    
    import javax.imageio.ImageIO;
    import javax.swing.JComponent;
    import javax.swing.JFrame;
    
    public class Main {
    
        public static void main(String[] args) throws IOException {
            JFrame frame = new JFrame();
            
            File pathToFile = new File("./doggo.jpeg");
            Image img = ImageIO.read(pathToFile);
            
            JComponent panel = new JComponent()
            {
                @Override
                public void paintComponent(Graphics g)
                {
                    Graphics2D g2 = (Graphics2D) g;
    
                    int w = this.getWidth();
                    int h = this.getHeight();
    
                    int[] scale = scaleImage(img, w, h);
    
                    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                    g2.setColor(Color.black);
                    g2.fillRect(0, 0, getWidth(), getHeight());
                    g2.drawImage(img, scale[2], scale[3], scale[0], scale[1], null);
                }
            };
            panel.setBackground(Color.black);
            frame.add(panel, BorderLayout.CENTER);
            frame.setBackground(Color.black);
            
            GraphicsDevice gd =
                    GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
    
            if (gd.isFullScreenSupported()) {
                frame.setUndecorated(true);
                gd.setFullScreenWindow(frame);
            } else {
                System.err.println("Full screen not supported");
                frame.setSize(765, 1024);
                frame.setVisible(true);
            }
        }
    
        public static int[] scaleImage(Image image, int newWidth, int newHeight) {
            double thumbRatio = (double) newWidth / (double) newHeight;
            int imageWidth = image.getWidth(null);
            int imageHeight = image.getHeight(null);
            double aspectRatio = (double) imageWidth / (double) imageHeight;
    
            int x = 0;
            int y = 0;
    
            if (thumbRatio < aspectRatio) {
                y = newHeight;
                newHeight = (int) (newWidth / aspectRatio);
                y /= 2;
                y -= newHeight / 2;
            } else {
                x = newWidth;
                newWidth = (int) (newHeight * aspectRatio);
                x /= 2;
                x -= newWidth / 2;
            }
    
            return new int[] { newWidth, newHeight, x, y };
        }
    }