Trying to draw an image in JFrame using Java BufferedImage, Graphics

I try to capture the screen and then draw the image in the JFrame recursively while scaling the image (to create the effect that you get when you look at a mirror in a mirror).

I am having problems with my code - it does not draw graphics. What am I doing wrong?

import java.awt.AWTException; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.HeadlessException; import java.awt.Image; import java.awt.Rectangle; import java.awt.Robot; import java.awt.Toolkit; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.image.BufferedImage; import javax.swing.JFrame; public class ScreenCapture extends JFrame { BufferedImage screenCapture; Graphics screenCaptureGraphics; private static int recurseCount = 0; private static float $scale = 0.9f; private static float scale = 1.0f; private static int height; private static int width; ScreenCapture() { try { screenCapture = new Robot().createScreenCapture( new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()) ); height = screenCapture.getHeight(); width = screenCapture.getWidth(); setSize(new Dimension(width, height)); addWindowListener(new LocalWindowListener()); Graphics g = recursiveDraw(screenCapture, getGraphics()); paint(g); } catch (HeadlessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (AWTException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private Graphics recursiveDraw(BufferedImage img, Graphics imgG) { updateScale(++recurseCount); float newWidth = scale*width; float newHeight = scale*height; int w = (int) newWidth; int h = (int) newHeight; System.out.println("W: " + w + "; H: " + h); if (w >= 10 && h >= 10) { //scale image System.out.print("Creating scaled Image..."); Image scaled = img.getScaledInstance(w, h, Image.SCALE_SMOOTH); BufferedImage resized = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); imgG = resized.createGraphics(); imgG.drawImage(scaled, 0, 0, null); System.out.println("...Image drawn to graphics"); //return new graphics return recursiveDraw(resized, imgG); } else { //otherwise return old graphics System.out.println("Completed."); return imgG; } } private void updateScale(int count) { for (int i=0; i<count; i++) { scale *= $scale; } System.out.println("Updated scale: " + scale + "; Recurse count: " + recurseCount); } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { new ScreenCapture().setVisible(true); } }); } private class LocalWindowListener extends WindowAdapter { @Override public void windowClosing(WindowEvent e) { System.exit(0); return; } } } 

EDIT: This is what I tried after @ andrew-thompson's answer:

 ScreenCapture() { try { screenCapture = new Robot().createScreenCapture( new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()) ); height = screenCapture.getHeight(); width = screenCapture.getWidth(); setSize(new Dimension(width, height)); addWindowListener(new LocalWindowListener()); setLayout(new GridLayout()); add(new PaintPanel()); } catch (HeadlessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (AWTException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private class PaintPanel extends JPanel { @Override public void paintComponent(Graphics g) { g=recursiveDraw(screenCapture, g); //what to do with g? } } 

I still have the same problem when I don't know how to make BufferedImage draw with graphics.

+4
source share
4 answers

extract your Swing code from your recursive image creation code. Actually think about creating a static method that creates and returns a BufferedImage, and it doesn't have Swing code. Then ask your GUI to call the method whenever it wants, and take the image and either write it to disk or display it in the JLabel ImageIcon.

When I did this (actually today), I created a recursive method with this signature

 private static void recursiveDraw(BufferedImage img, Graphics imgG, double scale) { 

and with this method body (in pseudocode)

 start recursiveDraw method // most important: all recursions must have a good ending condition: get img height and width. If either <= a min, return create a BufferedImage, smlImg, for the smaller image using the height, width and scale factor Get the Graphics object, smlG, from the small image Use smlG.drawImage(...) overload to draw the big image in shrunken form onto the little image recursively call recursiveDraw passing in smlImg, smlG, and scale. dispose of smlG draw smlImg (the small image) onto the bigger one using the bigger Graphics object (passed into this method) and a different overload of the drawImage method. end recursiveDraw method 

This algorithm led to the following images: enter image description here

For instance:

 import java.awt.*; import java.awt.Dialog.ModalityType; import java.awt.event.ActionEvent; import java.awt.image.BufferedImage; import javax.swing.*; public class RecursiveDrawTest { private static final Color BACKGRND_1 = Color.green; private static final Color BACKGRND_2 = Color.MAGENTA; private static final Color FOREGRND_1 = Color.blue; private static final Color FOREGRND_2 = Color.RED; private static void createAndShowGui() { final JPanel mainPanel = new JPanel(new BorderLayout()); final JSlider slider = new JSlider(50, 90, 65); slider.setMajorTickSpacing(10); slider.setMinorTickSpacing(5); slider.setPaintLabels(true); slider.setPaintTicks(true); JPanel southPanel = new JPanel(); southPanel.add(new JLabel("Percent Size Reduction:")); southPanel.add(slider); southPanel.add(new JButton(new AbstractAction("Create Recursive Image") { @Override public void actionPerformed(ActionEvent arg0) { try { double scale = slider.getValue() / 100.0; BufferedImage img = createRecursiveImg(scale); ImageIcon icon = new ImageIcon(img); JLabel label = new JLabel(icon); Window win = SwingUtilities.getWindowAncestor(mainPanel); JDialog dialog = new JDialog(win, "Image", ModalityType.MODELESS); dialog.getContentPane().add(label); dialog.pack(); dialog.setLocationRelativeTo(null); dialog.setVisible(true); } catch (AWTException e) { e.printStackTrace(); } } })); mainPanel.add(new JScrollPane(new JLabel(new ImageIcon(createLabelImg()))), BorderLayout.CENTER); mainPanel.add(southPanel, BorderLayout.PAGE_END); JFrame frame = new JFrame("RecursiveDrawTest"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(mainPanel); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } // create a background image to display in a JLabel so that the GUI // won't be boring. private static BufferedImage createLabelImg() { Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); int width = (5 * d.width) / 6; int height = (5 * d.height) / 6; BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); Graphics2D g2 = img.createGraphics(); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setPaint(new GradientPaint(0, 0, BACKGRND_1, 40, 40, BACKGRND_2, true)); g2.fillRect(0, 0, width, height); g2.setPaint(new GradientPaint(0, height, FOREGRND_1, 40, height - 40, FOREGRND_2, true)); g2.fillOval(0, 0, 2 * width, 2 * height); g2.dispose(); return img; } // non-recursive image to get the initial image that will be drawn recursively public static BufferedImage createRecursiveImg(double scale) throws AWTException { Robot robot = new Robot(); Dimension screenSz = Toolkit.getDefaultToolkit().getScreenSize(); Rectangle screenRect = new Rectangle(screenSz); BufferedImage img = robot.createScreenCapture(screenRect); Graphics g = img.getGraphics(); recursiveDraw(img, g, scale); // call recursive method g.dispose(); return img; } // recursive method to draw image inside of image private static void recursiveDraw(BufferedImage img, Graphics g, double scale) { int w = img.getWidth(); int h = img.getHeight(); int smlW = (int)(w * scale); int smlH = (int)(h * scale); // criteria to end recursion if (smlW <= 1 || smlH <= 1) { return; } BufferedImage smlImg = new BufferedImage(smlW, smlH, BufferedImage.TYPE_INT_ARGB); Graphics smlG = smlImg.getGraphics(); // draw big image in little image, scaled to little image smlG.drawImage(img, 0, 0, smlW, smlH, null); // recursive call recursiveDraw(smlImg, smlG, scale); smlG.dispose(); // clear resources when done with them // these guys center the smaller img on the bigger int smlX = (w - smlW) / 2; int smlY = (h - smlH) / 2; // draw small img on big img g.drawImage(smlImg, smlX, smlY, smlW, smlH, null); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGui(); } }); } } 
+6
source
  Graphics g = recursiveDraw(screenCapture, getGraphics()); 

Do not call getGraphics() . Override paint(Graphics) 1 and use the provided Graphics instance.

  • When using Swing, it is best to override the paintComponent(Graphics) JComponent for JComponent or JPanel . Then add this to the top level container.
+5
source

This is what you hope for:

 import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.Robot; import java.awt.Toolkit; import java.awt.image.BufferedImage; import javax.imageio.ImageIO; import javax.swing.*; public class CaptureScreen extends JPanel { private BufferedImage screenShot; private JLabel imageLabel; private BufferedImage secondScreenShot; public void createAndDisplayGUI() { JFrame frame = new JFrame("CAPTURE SCREEN"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLocationByPlatform(true); //imageLabel = new JLabel(); //getImageForLabel(); //add(imageLabel); frame.getContentPane().add(this); frame.setSize(600, 600); frame.setVisible(true); } private void getImageForLabel() { Robot robot = null; try { robot = new Robot(); } catch(Exception e) { e.printStackTrace(); } screenShot = robot.createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize())); ImageIcon icon = new ImageIcon(screenShot); imageLabel.setIcon(icon); } public void paintComponent(Graphics g) { Robot robot = null; try { robot = new Robot(); } catch(Exception e) { e.printStackTrace(); } screenShot = robot.createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize())); secondScreenShot = getScaledImage((Image) screenShot, 300, 300); g.drawImage(screenShot, 0, 0, null); g.drawImage(secondScreenShot, 150, 150, null); } private BufferedImage getScaledImage(Image srcImg, int w, int h) { BufferedImage resizedImg = new BufferedImage(w, h, BufferedImage.TRANSLUCENT); Graphics2D g2 = resizedImg.createGraphics(); g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g2.drawImage(srcImg, 0, 0, w, h, null); g2.dispose(); return resizedImg; } public static void main(String... args) { SwingUtilities.invokeLater(new Runnable() { public void run() { new CaptureScreen().createAndDisplayGUI(); } }); } } 

Here is the result:

ScreenShot over another

+1
source

Get rid of recursion. Create one buffered image with the correct size and create a Graphics object for it. Just use the loop to draw progressively smaller scaled images down to any threshold you choose. Finally, use g.drawImage () inside paintComponent () to draw the image on the screen. If you keep recursion, you need to transfer the image and constantly overlay the thumbnail. You do not need to return anything from the method.

+1
source

Source: https://habr.com/ru/post/1402098/


All Articles