Dynamically resize buffered image in java

I tried resizing the buffered image using AffineTransform as well as Scalr.resize

Here are my codes for both.

using Scalr.resize:

BufferedImage buff = robot.createScreenCapture(new Rectangle(bufx,bufy,bufwidth,bufheight)); // x-coord, y-coord, width, height BufferedImage scrCapt = Scalr.resize(buff, Method.BALANCED, scrwidth, scrheight); 

using AffineTransform:

 BufferedImage buff = robot.createScreenCapture(new Rectangle(bufx,bufy,bufwidth,bufheight)); // x-coord, y-coord, width, height BufferedImage scrCapt = new BufferedImage(bufwidth,bufheight,BufferedImage.TYPE_INT_ARGB); AffineTransform atscr = new AffineTransform(); atscr.scale(aspectRatioWidth,aspectRatioHeight); AffineTransformOp scaleOp = new AffineTransformOp(atscr, AffineTransformOp.TYPE_BILINEAR); scrCapt = scaleOp.filter(buff, scrCapt); 

variables were declared at the beginning inside the class:

 static int bufx = 0; static int bufy = 0; static int bufwidth = 1; static int bufheight = 1; static int scrwidth = 0; static int scrheight = 0; static float aspectRatioWidth = 0; static float aspectRatioHeight = 0; 

I get values ​​for all variables dynamically inside another method:

 aspectRatioWidth = bufwidth/scrwidth; aspectRatioHeight = bufheight/scrheight; 

However, when I run this code, I get an error both in the AffineTransform functions and in Scalr.resize:

Scalr.resize:

 Exception in thread "Thread-2" java.lang.IllegalArgumentException: Width (0) and height (0) cannot be <= 0 at java.awt.image.DirectColorModel.createCompatibleWritableRaster(DirectColorModel.java:1016) at java.awt.image.BufferedImage.<init>(BufferedImage.java:331) at org.imgscalr.Scalr.createOptimalImage(Scalr.java:2006) at org.imgscalr.Scalr.scaleImage(Scalr.java:2133) at org.imgscalr.Scalr.resize(Scalr.java:1667) at org.imgscalr.Scalr.resize(Scalr.java:1415) 

AffineTransform:

 Exception in thread "Thread-2" java.awt.image.ImagingOpException: Unable to invert transform AffineTransform[[0.0, 0.0, 0.0], [0.0, 1.0, 0.0]] at java.awt.image.AffineTransformOp.validateTransform(AffineTransformOp.java:558) at java.awt.image.AffineTransformOp.<init>(AffineTransformOp.java:151) 

How can I do it? I understand that this is because I change the variable in another method and get them in another. But these two methods cannot be combined. Is there any way to make this work?

EDIT:

I changed the way I resize. Here's what I did now.

 public static BufferedImage resizeImage(BufferedImage image, double scalewidth, double scaleheight){ BufferedImage img = new BufferedImage(image.getWidth(), image.getHeight(),BufferedImage.SCALE_FAST); Graphics2D g = img.createGraphics(); g.scale(scalewidth, scaleheight); g.drawImage(image, null, 0, 0); g.dispose(); return image; } 

EDIT (2) :

For a clearer picture of what exactly is happening:

This is a method that returns scrwidth and scrheight

 public static void showOnScreen( int screen, JFrame framenew ) { GraphicsEnvironment ge = GraphicsEnvironment .getLocalGraphicsEnvironment(); GraphicsDevice[] gs = ge.getScreenDevices(); for (int i = 0; i < gs.length; i++) { screenwidth.add(gs[i].getDisplayMode().getWidth()); screenheight.add(gs[i].getDisplayMode().getHeight()); } scrwidth = screenwidth.get(screenwidth.size()-1); scrheight = screenheight.get(screenheight.size()-1); System.out.print(ge); System.out.print(gs); if( screen > -1 && screen < gs.length ) {gs[screen].setFullScreenWindow( framenew );} else if( gs.length > 0 ) {gs[0].setFullScreenWindow( framenew );} else {throw new RuntimeException( "No Screens Found" );}} 

And this is an actionlistener that returns bufwidth and bufheight:

  btnNewButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { //Execute when button is pressed System.out.println("You clicked the button"); int ind = c.getSelectedIndex(); bufx = capx.get(ind); bufy = capy.get(ind); bufwidth = capwidth.get(ind); bufheight = capheight.get(ind); frame.setVisible(false); framenew.setVisible(true); showOnScreen(1,framenew); aspectRatioWidth = (double) bufwidth/scrwidth; aspectRatioHeight = (double) bufheight/scrheight; System.out.print("aspectRatioWidth: "); System.out.println(aspectRatioWidth); System.out.print("aspectRatioHeight: "); System.out.println(aspectRatioHeight); } }); 

And aspectRatios are used inside run:

 public void run() { System.out.print("aspectRatioWidth: "); System.out.println(aspectRatioWidth); System.out.print("aspectRatioHeight: "); System.out.println(aspectRatioHeight); while(true){ BufferedImage buff = robot.createScreenCapture(new Rectangle(bufx,bufy,bufwidth,bufheight)); // x-coord, y-coord, width, height BufferedImage resizedbuff = resizeImage(buff, aspectRatioWidth, aspectRatioHeight);} 
+6
source share
1 answer

You are doing an int division, which always returns an int, here is 0, since the screen sizes are likely to be larger than the sizes of your image:

 aspectRatioWidth = bufwidth/scrwidth; aspectRatioHeight = bufheight/scrheight; 

Solution: convert the numbers to double and then do double division.

 aspectRatioWidth = (double) bufwidth/scrwidth; aspectRatioHeight = (double) bufheight/scrheight; 

Edit

Not sure what you're ultimately trying to do - place a computer screen image in your GUI? If so, maybe something like ...

 import java.awt.AWTException; import java.awt.Dimension; import java.awt.Graphics; 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.geom.AffineTransform; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.util.List; import javax.swing.*; public class ChangeVars extends JPanel { private static final int PREF_W = 400; private static final int PREF_H = PREF_W; private static final int DELAY = 20; public BufferedImage displayImage; private MyWorker myWorker; public ChangeVars() { try { myWorker = new MyWorker(DELAY); myWorker.execute(); } catch (AWTException e) { e.printStackTrace(); } } @Override // to initialize the panel to something public Dimension getPreferredSize() { if (isPreferredSizeSet()) { return super.getPreferredSize(); } return new Dimension(PREF_W, PREF_H); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); if (displayImage != null) { g.drawImage(displayImage, 0, 0, null); } } public void stopWorker() { if (myWorker != null && !myWorker.isDone()) { myWorker.setRunning(false); myWorker.cancel(true); } } private class MyWorker extends SwingWorker<Void, BufferedImage> { private volatile boolean running = true; private Robot robot; private int delay; public MyWorker(int delay) throws AWTException { this.delay = delay; robot = new Robot(); } @Override protected Void doInBackground() throws Exception { while (running) { Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); Rectangle screenRect = new Rectangle(0, 0, d.width, d.height); BufferedImage img = robot.createScreenCapture(screenRect); publish(img); Thread.sleep(delay); } return null; } @Override protected void process(List<BufferedImage> chunks) { for (BufferedImage image : chunks) { Dimension sz = getSize(); double scaleX = (double) sz.width / image.getWidth(); double scaleY = (double) sz.height / image.getHeight(); AffineTransform transform = AffineTransform.getScaleInstance( scaleX, scaleY); AffineTransformOp transformOp = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR); displayImage = new BufferedImage(sz.width, sz.height, BufferedImage.TYPE_INT_ARGB); displayImage = transformOp.filter(image, displayImage); repaint(); } } public void setRunning(boolean running) { this.running = running; } public boolean getRunning() { return running; } } private static void createAndShowGui() { final ChangeVars changeVars = new ChangeVars(); JFrame frame = new JFrame("ChangeVars"); frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { if (changeVars != null) { changeVars.stopWorker(); } System.exit(0); } }); frame.getContentPane().add(changeVars); frame.pack(); frame.setLocationByPlatform(true); frame.setVisible(true); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGui(); } }); } } 

Although it would be easier to just let paintComponent do the scaling:

 @Override protected void paintComponent(Graphics g) { super.paintComponent(g); if (displayImage != null) { int width = getWidth(); int height = getHeight(); g.drawImage(displayImage, 0, 0, width, height, null); } } // .... @Override protected void process(List<BufferedImage> chunks) { for (BufferedImage image : chunks) { displayImage = image; repaint(); } } 
+4
source

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


All Articles