6

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

Here are my codes for both of them.

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

the variables have been declared in the beginning inside 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 am getting the values for for all the variables dynamically inside a different method:

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

However when I run this code I get an error in both the functions AffineTransform as well as 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 do I go about this? I understand that this is happening because I am changing the variable in a different method and accessing them in another one. But those two methods can't be combined. Is there any way I can make this work?

EDIT:

I changed the method of resizing 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 idea of what is happening exactly:

This is a method which 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 the actionlistener which 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);}
newbie2015
  • 581
  • 5
  • 29
  • So, ... you've made some changes (have you made the change that I recommended?) -- what did your changes do? Is your code now working? Are you still seeing an exception? – Hovercraft Full Of Eels May 30 '15 at 14:23
  • yes I converted the numbers to double. It is giving the right value when I perform the division inside method which is returning bufwidth, bufheight and all the variables However it is returning zero when I print out aspectRatioWidth and aspectRatioHeight inside run() I understand this is happening because when the run() is implemented, the values of all the variables haven't been incremented yet How do i make sure that run() occurs only after the values have been incremented? – newbie2015 May 30 '15 at 14:28

1 Answers1

5

You're doing int division which always returns an int, here 0 since your screen dimensions will likely be greater than your image dimensions:

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 -- post the image of the computer screen in your GUI? If so, perhaps 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 simpler would be 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();
     }
  }
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • I am using a different method to implement the image scaling It works fine except now I realized there's a different issue The two variables are being changed in a different function while I am accessing them inside run() So when aspectRatioWidth and aspectRatioHeight always return a zero because bufwidth and bufheight have been initialized to zero Is there any way I can make sure the other functions are implemented before run() – newbie2015 May 30 '15 at 14:23
  • @newbie2015: so you're now changing requirements on us. In the future, please try to avoid this as this can be frustrating for us and can invalidate existing answers. As to your problem, if you're now running into a new problem, then edit your question and clarify your problem as much as possible. I'm not sure that I can fully understand what's wrong based on the blurb you've posted above. For example, I have no way of knowing how the variables are related. – Hovercraft Full Of Eels May 30 '15 at 14:25
  • @newbie2015: consider creating and posting a [Minimal, Complete, and Verifiable Example Program](http://stackoverflow.com/help/mcve) where you condense your code into the smallest bit that still compiles and runs, has no outside dependencies (such as need to link to a database or images), has no extra code that's not relevant to your problem, but still demonstrates your problem. As a side issue, your current code looks to be over-using static fields, something that in general should be avoided. – Hovercraft Full Of Eels May 30 '15 at 14:26
  • Sir, I have made another edit explaining where exactly the variables are being changed and where they are being accessed. Sorry for posting wrong question. I did not realize until I changed the resize method that resizing was not an issue afterall. – newbie2015 May 30 '15 at 14:36
  • @newbie2015: what is this code trying to do? Why create all the images? Why use an uncontrolled while (true) polling loop? – Hovercraft Full Of Eels May 30 '15 at 14:39
  • I am trying to create a screencapturer which captures and displays runtime. – newbie2015 May 30 '15 at 14:47
  • @newbie2015: You need to show more code, again preferably a [mcve](http://stackoverflow.com/help/mcve) so we can test your simple code and see how your variables relate. Are you capturing the entire screen, or just a section of it? If section, what determines what section? – Hovercraft Full Of Eels May 30 '15 at 14:54
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/79202/discussion-between-newbie2015-and-hovercraft-full-of-eels). – newbie2015 May 30 '15 at 15:19