Dynamically resize a bufferedimage in java - java

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

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

Related

Maintain aspect ratio when resizing an image and resizing jPanel at the same time

I'm trying to maintain aspect ratio by calculating width percentage and height percentage of the original image and then set the new height and new width based on percentages but there is something wrong in my code :
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.net.URL;
public class Test extends JFrame {
private JPanel principalPanel;
private BufferedImage image;
public Test() {
setSize(600,600);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
try {
URL url = new
URL("https://boygeniusreport.files.wordpress.com/2017/04/earth.jpg");
image = ImageIO.read(url);
} catch (Exception e) {
System.out.println("Problem loading image");
e.printStackTrace();
}
principalPanel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int width = image.getWidth();
int height = image.getHeight();
int wPercentage = (width*100)/(width+height);
int hPercentage = (height*100)/(width+height);
int w = (width+((getHeight()-height)*wPercentage)/hPercentage);
int h = (height+((getWidth()-width)*hPercentage)/wPercentage);
g.drawImage(image,0,0,w,h,this);
}
};
setContentPane(principalPanel);
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
}
Here is the solution:
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.net.URL;
public class Test extends JFrame {
private JPanel principalPanel;
private BufferedImage image;
public Test() {
setSize(600,600);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
try {
URL url = new
URL("https://boygeniusreport.files.wordpress.com/2017/04/earth.jpg");
image = ImageIO.read(url);
} catch (Exception e) {
System.out.println("Problem loading image");
e.printStackTrace();
}
principalPanel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int original_width = image.getWidth();
int original_height = image.getHeight();
int bound_width = getWidth();
int bound_height = getHeight();
int new_width = original_width;
int new_height = original_height;
// first check if we need to scale width
if (original_width > bound_width) {
//scale width to fit
new_width = bound_width;
//scale height to maintain aspect ratio
new_height = (new_width * original_height) / original_width;
}
// then check if we need to scale even with the new height
if (new_height > bound_height) {
//scale height to fit instead
new_height = bound_height;
//scale width to maintain aspect ratio
new_width = (new_height * original_width) / original_height;
}
g.drawImage(image,0,0,new_width,new_height,this);
}
};
setContentPane(principalPanel);
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
}

Adding ViewPort to JPanel

I would like to achieve the following for my swing project,
I was able to get this by extending a JPanel and and using JLayer.
I event tried using AlphaComposite but it didn't work.
Edit1: I think JTable or JViewport might help me to get what I want but I don't know how to use them.
Edit2: Updated the SSCCE, thank you trashgod for the suggestion.
I have made use of the Scalr library because after using getScaledInstance method of Image class, if i tried to use the getSubImage method of BufferedImage,the following exception is thrown:
java.lang.ClassCastException: sun.awt.image.ToolkitImage cannot be
cast to java.awt.image.BufferedImage
since the Image generated by getScaledInstance method is a instance of ToolkitImage so, it cannot be cast into a BufferedImage.
If you don't want to use the Scalr library,you can use the code suggested in this post to scale the BufferedImage and than use getSubImage method.
SCSE.java
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.util.Random;
import javax.swing.*;
import javax.swing.plaf.LayerUI;
import org.imgscalr.Scalr;
public class SCSE {
private JFrame mainFrame;
private JPanel mainPanel;
private GridView gridView;
private JButton imgBtn, shuffleBtn;
private int gridX = -1, gridY = -1, gridWidth = -1, gridHeight = -1;
private boolean isGridEmpty = false;
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
SCSE sc = new SCSE();
sc.createGUI();
});
}
private void createGUI() {
mainFrame = new JFrame();
mainFrame.setSize(500, 500);
mainFrame.setResizable(false);
mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
mainPanel = new JPanel(new BorderLayout());
gridView = new GridView();
imgBtn = new JButton("Get-Image");
shuffleBtn = new JButton("Shuffle-ViewPort");
imgBtn.addActionListener((ActionEvent evt) -> {
try {
gridView.setImage(ImageIO.read(new URL("http://www.keenthemes.com/preview/metronic/theme/assets/global/plugins/jcrop/demos/demo_files/image1.jpg")));
} catch (IOException ex) {
System.out.println(ex);
}
});
shuffleBtn.addActionListener((ActionEvent evt) -> {
gridView.startShuffle();
});
mainPanel.add(gridView.getComponent(), BorderLayout.CENTER);
mainPanel.add(imgBtn, BorderLayout.NORTH);
mainPanel.add(shuffleBtn, BorderLayout.SOUTH);
mainFrame.add(mainPanel);
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
}
class GridView {
private Random shuffleRandom;
private RegisterUI layerUi = null;
private JLayer<JPanel> gridLayer = null;
private ImagePanel mainPanel = null;
private int gridNos = 21; //number of grids
int digit[];
private int viewportDimensions = 4; //no of rows and columns in viewport
private JLabel gridLabel[][] = new JLabel[gridNos][gridNos];
private int gridX = -1, gridY = -1, gridWidth = -1, gridHeight = -1;
private boolean isGridInitialized = false;
public GridView() {
initPersuasive();
initPanel();
initGrids();
}
private void initPanel() {
mainPanel = new ImagePanel();
mainPanel.setLayout(new GridLayout(gridNos, gridNos, 0, 0)); //creates layout to place labels in grid form
layerUi = new RegisterUI();
gridLayer = new JLayer<>(mainPanel, layerUi);
}
private void initGrids() {
for (int i = 0; i < gridNos; i++) {
for (int j = 0; j < gridNos; j++) {
gridLabel[i][j] = new JLabel();
gridLabel[i][j].setOpaque(false);
gridLabel[i][j].setName("" + (i + 1)); // Since for loop index is 0 to 80, we add 1 to the name to make it 1 to 81
mainPanel.add(gridLabel[i][j]); //add it to mainPanel
}
}
}
private void initPersuasive() {
shuffleRandom = new Random();
digit = new int[2];
}
private void random() {
digit[0] = shuffleRandom.nextInt(gridNos - viewportDimensions);
digit[1] = shuffleRandom.nextInt(gridNos - viewportDimensions);
}
public void startShuffle() {
random();
int x = gridLabel[digit[0]][digit[1]].getX();
int y = gridLabel[digit[0]][digit[1]].getY();
layerUi.placeViewport(x, y);
}
public void stopShuffle() {
layerUi.removeViewPort();
}
public void setupGridView() {
gridX = gridLabel[0][0].getX();
gridY = gridLabel[0][0].getY();
gridWidth = gridLabel[0][0].getWidth();
gridHeight = gridLabel[0][0].getHeight();
mainPanel.setValues(gridX, gridY);
layerUi.setViewSize(gridWidth * viewportDimensions, gridHeight * viewportDimensions);
}
public void setImage(BufferedImage img) {
if (!isGridInitialized) {
setupGridView();
isGridInitialized = true;
}
BufferedImage sendImg = Scalr.resize(img, Scalr.Mode.FIT_EXACT, gridWidth * gridNos, gridHeight * gridNos, Scalr.OP_ANTIALIAS);
layerUi.setupViewport(img);
mainPanel.paintImage(img);
}
public JLayer<JPanel> getComponent() {
return gridLayer;
}
}
class RegisterUI extends LayerUI<JPanel> {
private int viewX, viewY, viewWidth, viewHeight;
private boolean shuffleIsRunning = false;
private BufferedImage viewportImage = null;
private void drawPCCP(Graphics g, int w, int h) {
Graphics2D g2 = ((Graphics2D) g);
Color c = new Color(1.0f, 1.0f, 1.0f, 0.7f);
g2.setPaint(c);
g2.fillRect(0, 0, w, h);
BufferedImage highlightGrid = Scalr.pad(Scalr.crop(viewportImage, viewX, viewY, viewWidth, viewHeight), 2, Color.BLACK, Scalr.OP_ANTIALIAS);
g2.drawImage(highlightGrid, viewX, viewY, null);
g2.dispose();
}
public void paint(Graphics g, JComponent c) {
super.paint(g, c);
int w = c.getWidth();
int h = c.getHeight();
if (shuffleIsRunning) {
drawPCCP(g, w, h);
}
}
public void setupViewport(BufferedImage bi) {
viewportImage = bi;
}
public void setViewSize(int w, int h) {
viewWidth = w;
viewHeight = h;
}
public void placeViewport(int x, int y) {
viewX = x;
viewY = y;
if (!shuffleIsRunning) {
shuffleIsRunning = true;
}
firePropertyChange("shuffleui", 0, 1);
}
public void removeViewPort() {
if (!shuffleIsRunning) {
return;
}
viewX = 0;
viewY = 0;
viewWidth = 0;
viewHeight = 0;
shuffleIsRunning = false;
firePropertyChange("shuffleui", 0, 1);
}
#Override
public void applyPropertyChange(PropertyChangeEvent evt, JLayer<? extends JPanel> l) {
if ("disableui".equals(evt.getPropertyName()) || "shuffleui".equals(evt.getPropertyName())) {
l.repaint();
}
}
}
class ImagePanel extends JPanel {
private BufferedImage displayImage = null;
private int x, y;
public void setValues(int x, int y) {
this.x = x;
this.y = y;
}
public void paintImage(BufferedImage bi) {
System.out.print(bi);
displayImage = bi;
repaint(); // repaint calls paintComponent method internally
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(displayImage, x, y, this); // To Paint the image on the panel
}
}
}
Instead of using AlphaComposite directly, as shown here, try RescaleOp to alter the image's color/alpha bands, as shown in this example. This will allow you to mute the tone of the entire image as desired. Copy a portion of the original image using getSubimage() to restore the highlight.

NullPointerException - I don't understand

what is wrong with this code?
I keep getting the error
Exception in thread "Thread-2" java.lang.NullPointerException
at GUI.render(GUI.java:68)
at GUI.run(GUI.java:51)
please help
import graphics.*;
import javax.swing.*;
import java.awt.*;
import java.awt.Canvas;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
public class GUI extends Canvas implements Runnable {
private static final long serialVersionUID = 1L;
final static String LABEL_TEXT = "Game";
public static final int Width = 1020;
public static final int Height = 680;
private Thread thread;
private Screen screen;
private Render render;
private BufferedImage img;
private boolean running = false;
private int[] pixels;
public void display() {
screen = new Screen(Height, Width);
vimg = new BufferedImage(Width, Height, BufferedImage.TYPE_INT_RGB);
pixels = ((DataBufferInt)img.getRaster().getDataBuffer()).getData();
}
private void start() {
if(running)
return;
running = true;
thread = new Thread(this);
thread.start();
}
private void stop() {
if(!running)
return;
running = false;
try {
thread.join();
} catch (Exception e) {
e.printStackTrace();
System.exit(0);
}
}
public void run() {
while (running){
tick();
render();
}
}
public void tick() {
}
private void render() {
BufferStrategy bs = this.getBufferStrategy();;
if(bs == null) {
createBufferStrategy(3);
return;
}
screen.render();
for (int i = 0; i <Width*Height; i++){
pixels[i] = screen.pixels[i];
}
Graphics g = bs.getDrawGraphics();
g.drawImage(img, 0, 0, Width, Height, null);
g.dispose();
bs.show();
}
/**
* Create and show the GUI.
*/
public static void main(String[] args) {
/*Create Canvas*/
GUI game = new GUI();
/*Create and set up the frame*/
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
/*Add content pane to frame*/
frame.add(game);
/*Size and then display the frame.*/
frame.setSize(Width, Height);
frame.setVisible(true);
frame.setLocationRelativeTo(null);
game.start();
}
}
package graphics;
public class Render {
public final int width;
public final int height;
public int[] pixels;
public Render(int height, int width) {
this.width = width;
this.height = height;
pixels = new int[width*height];
}
public void draw(Render render, int xOffset, int yOffset) {
for (int y =0; y<height; y++) {
int yPix = y + yOffset;
for (int x =0; x<width; x++) {
int xPix = x + xOffset;
pixels[xPix+yPix*width] = pixels[x+y*width];
}
}
}
}
package graphics;
import java.util.Random;
import graphics.Render;
public class Screen extends Render{
private Render test;
public Screen(int width, int height) {
super(width, height);
Random rand = new Random();
test = new Render(256, 256);
for (int i =0; i< 256*256; i++){
test.pixels[i] = rand.nextInt();
}
}
public void render() {
draw(test, 0, 0);
}
}
You haven't called display() to initialize your variables before you use them.

java making a screen shot preview with JPanel

I'm making a fun little test screen recording program in java, and I want it to have a preview of your screen before you start recording.. but its a very slow and poor method of which I am using, involving capturing an image, saving it, then reading it in through a bufferedimage and drawing that image using Graphics. Its very slow and not useful as a "preview" is there a way to speed up and have a more efficient "previewing system".
Here is what I have so far:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class MainFrame implements ActionListener, Runnable {
//add frame components
public static JFrame frame = new JFrame("Screen Caper - v1.0.1");
JButton start = new JButton("record");
JButton close = new JButton("Exit");
JPanel preview = new JPanel();
public static boolean running = false;
public static boolean recording = false;
public static boolean paused = false;
public static String curDir = System.getProperty("user.dir");
//get the screen width
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double width = screenSize.getWidth();
double height = screenSize.getHeight();
Container a = new Container();
Container b = new Container();
public MainFrame() {
frame.setSize((int)(width) - 80, (int)(height) - 80);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//setup the buttons and JPanel
a.setLayout(new GridLayout(1, 2));
a.add(start);
start.addActionListener(this);
a.add(close);
close.addActionListener(this);
frame.add(a, BorderLayout.NORTH);
b.setLayout(new GridLayout(1, 2));
b.add(preview);
frame.add(b, BorderLayout.CENTER);
//add anything else
running = true;
//set frame to visible
frame.setVisible(true);
run();
}
public static void main(String[] args) {
new MainFrame();
}
public void run() {
Graphics g = frame.getGraphics();
while (running) {
//draw the preview of the computer screen on the JPanel if its not recording already
if (!recording && !paused) {
drawPreview(g);
}
}
}
public void drawPreview(Graphics g) {
BufferedImage image;
try {
image = new Robot().createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
ImageIO.write(image, "png", new File("test.png"));
} catch (Exception ex) {
ex.printStackTrace();
}
BufferedImage prevIm;
try {
prevIm = ImageIO.read(new File("test.png"));
g.setColor(new Color(0, 0, 0));
g.fillRect(preview.getX() + 3, preview.getY() + 51, preview.getWidth(), preview.getHeight() + 1);
g.drawImage(prevIm, preview.getX() + 3, preview.getY() + 51, preview.getX() + preview.getWidth(), preview.getY() + preview.getHeight(), null);
} catch (IOException ex) {
ex.printStackTrace();
}
}
public void record(Graphics g) {
}
#Override
public void actionPerformed(ActionEvent event) {
if (event.getSource().equals(start)) {
if (!recording) {
//if the program isn't recording, then start recording
Graphics g = frame.getGraphics();
record(g);
start.setText("Finish");
recording = true;
System.out.println("recording...");
} else {
//else stop recording
start.setText("record");
recording = false;
System.out.println("done");
}
}
if (event.getSource().equals(close)) {
paused = true;
int ans = JOptionPane.showConfirmDialog(null, "Woah there! You're about to quit the application\nAre you sure you want to procced?", "Caution!", JOptionPane.YES_NO_OPTION);
if (ans == JOptionPane.YES_OPTION) {
System.exit(0);
} else if (ans == JOptionPane.NO_OPTION) {
paused = false;
}
}
}
}
any help is appreciated!
Don't use getGraphics, this is not how custom painting is done.
Your run method may simply be running to fast, consider using a javax.swing.Timer instead
Toolkit.getDefaultToolkit().getScreenSize() only returns the "default" screen and does not take into consideration split screens
Capturing the screen is a time consuming process and there's not much you can do about reducing it (as it's outside of your control). You "could" setup a series of Threads whose job it was to capture a given section of the desktop. You could also achieve this using SwingWorkers which would make it easier to sync the updates back to the UI...
Take a look at:
Performing Custom Painting
Concurrency in Swing
How to Use Swing Timers
Updated with example
This is a proof of concept only! You should understand what it's trying to do and borrow ideas from it...
You can see the preview window change inside the preview window...kinda freaky...
It tested this on a virtual desktop of 4480x1600.
Basically, it divides the desktop up into a 4x4 grid and starts a Thread for each section. Each thread is responsible for capturing it's own section of the screen.
It also scales that resulting image down and feeds it back to the UI.
I had started with SwingWorkers, but it seems to be hard to be limited to 10 threads. You could reduce the grid size and use SwingWorkers, they tend to be simpler to use and manage then raw Threads.
Each section is given an id, which allows me keep track of what's changed. Technically, you could just add elements to a List, but how do you determine what's new and what's old?
import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Robot;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class PreviewDesktop {
public static void main(String[] args) {
new PreviewDesktop();
}
public PreviewDesktop() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel implements Puzzler {
private Rectangle virtualBounds;
private double scale;
private Map<Integer, PuzzlePiece> pieces;
public TestPane() {
virtualBounds = getVirtualBounds();
int columns = 4;
int rows = 4;
pieces = new HashMap<>(columns * rows);
int columnWidth = Math.round(virtualBounds.width / (float) columns);
int rowHeight = Math.round(virtualBounds.height / (float) rows);
int id = 0;
for (int row = 0; row < rows; row++) {
int y = virtualBounds.y + (row * rowHeight);
for (int column = 0; column < columns; column++) {
int x = virtualBounds.x + (column * columnWidth);
Rectangle bounds = new Rectangle(x, y, columnWidth, rowHeight);
GrabberWorker worker = new GrabberWorker(id, this, bounds);
System.out.println(id);
id++;
startThread(worker);
}
}
}
#Override
public double getScale() {
return scale;
}
#Override
public void invalidate() {
super.invalidate();
scale = getScaleFactorToFit(virtualBounds.getSize(), getSize());
}
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
for (Integer id : pieces.keySet()) {
PuzzlePiece piece = pieces.get(id);
Rectangle bounds = piece.getBounds();
BufferedImage img = piece.getImage();
g2d.drawImage(img, bounds.x, bounds.y, this);
// If you want to see each sections bounds, uncomment below...
//g2d.draw(bounds);
}
g2d.dispose();
}
#Override
public void setPiece(int id, PuzzlePiece piece) {
pieces.put(id, piece);
repaint();
}
protected void startThread(GrabberWorker worker) {
Thread thread = new Thread(worker);
thread.setDaemon(true);
thread.start();
}
}
public class PuzzlePiece {
private final Rectangle bounds;
private final BufferedImage img;
public PuzzlePiece(Rectangle bounds, BufferedImage img) {
this.bounds = bounds;
this.img = img;
}
public Rectangle getBounds() {
return bounds;
}
public BufferedImage getImage() {
return img;
}
}
public interface Puzzler {
public void setPiece(int id, PuzzlePiece piece);
public double getScale();
}
public class GrabberWorker implements Runnable {
private Rectangle bounds;
private Puzzler puzzler;
private int id;
private volatile PuzzlePiece parked;
private ReentrantLock lckParked;
public GrabberWorker(int id, Puzzler puzzler, Rectangle bounds) {
this.id = id;
this.bounds = bounds;
this.puzzler = puzzler;
lckParked = new ReentrantLock();
}
protected void process(PuzzlePiece piece) {
// puzzler.setPiece(bounds, chunks.get(chunks.size() - 1));
puzzler.setPiece(id, piece);
}
protected void publish(PuzzlePiece piece) {
lckParked.lock();
try {
parked = piece;
} finally {
lckParked.unlock();
}
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
lckParked.lock();
try {
process(parked);
} finally {
lckParked.unlock();
}
}
});
}
#Override
public void run() {
try {
Robot bot = new Robot();
while (true) {
BufferedImage img = bot.createScreenCapture(bounds);
double scale = puzzler.getScale();
Rectangle scaled = new Rectangle(bounds);
scaled.x *= scale;
scaled.y *= scale;
scaled.width *= scale;
scaled.height *= scale;
BufferedImage imgScaled = getScaledInstance(img, scale);
publish(new PuzzlePiece(scaled, imgScaled));
Thread.sleep(500);
}
} catch (AWTException | InterruptedException exp) {
exp.printStackTrace();
}
}
}
public static Rectangle getVirtualBounds() {
Rectangle bounds = new Rectangle(0, 0, 0, 0);
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice lstGDs[] = ge.getScreenDevices();
for (GraphicsDevice gd : lstGDs) {
bounds.add(gd.getDefaultConfiguration().getBounds());
}
return bounds;
}
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 getScaleFactor(int iMasterSize, int iTargetSize) {
double dScale = (double) iTargetSize / (double) iMasterSize;
return dScale;
}
public static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor) {
return getScaledInstance(img, dScaleFactor, RenderingHints.VALUE_INTERPOLATION_BILINEAR, true);
}
protected static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor, Object hint, boolean bHighQuality) {
BufferedImage imgScale = img;
int iImageWidth = (int) Math.round(img.getWidth() * dScaleFactor);
int iImageHeight = (int) Math.round(img.getHeight() * dScaleFactor);
// System.out.println("Scale Size = " + iImageWidth + "x" + iImageHeight);
if (dScaleFactor <= 1.0d) {
imgScale = getScaledDownInstance(img, iImageWidth, iImageHeight, hint, bHighQuality);
} else {
imgScale = getScaledUpInstance(img, iImageWidth, iImageHeight, hint, bHighQuality);
}
return imgScale;
}
protected static BufferedImage getScaledDownInstance(BufferedImage img,
int targetWidth,
int targetHeight,
Object hint,
boolean higherQuality) {
int type = (img.getTransparency() == Transparency.OPAQUE)
? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage) img;
if (targetHeight > 0 || targetWidth > 0) {
int w, h;
if (higherQuality) {
// Use multi-step technique: start with original size, then
// scale down in multiple passes with drawImage()
// until the target size is reached
w = img.getWidth();
h = img.getHeight();
} else {
// Use one-step technique: scale directly from original
// size to target size with a single drawImage() call
w = targetWidth;
h = targetHeight;
}
do {
if (higherQuality && w > targetWidth) {
w /= 2;
if (w < targetWidth) {
w = targetWidth;
}
}
if (higherQuality && h > targetHeight) {
h /= 2;
if (h < targetHeight) {
h = targetHeight;
}
}
BufferedImage tmp = new BufferedImage(Math.max(w, 1), Math.max(h, 1), type);
Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2.drawImage(ret, 0, 0, w, h, null);
g2.dispose();
ret = tmp;
} while (w != targetWidth || h != targetHeight);
} else {
ret = new BufferedImage(1, 1, type);
}
return ret;
}
protected static BufferedImage getScaledUpInstance(BufferedImage img,
int targetWidth,
int targetHeight,
Object hint,
boolean higherQuality) {
int type = BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage) img;
int w, h;
if (higherQuality) {
w = img.getWidth();
h = img.getHeight();
} else {
w = targetWidth;
h = targetHeight;
}
do {
if (higherQuality && w < targetWidth) {
w *= 2;
if (w > targetWidth) {
w = targetWidth;
}
}
if (higherQuality && h < targetHeight) {
h *= 2;
if (h > targetHeight) {
h = targetHeight;
}
}
BufferedImage tmp = new BufferedImage(w, h, type);
Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2.drawImage(ret, 0, 0, w, h, null);
g2.dispose();
ret = tmp;
tmp = null;
} while (w != targetWidth || h != targetHeight);
return ret;
}
}
Now, if you're feeling really adventurous, you could update this idea so that if the underlying image for a section didn't change and the scale didn't change, it didn't send that to the UI, which might help reduce some of the overhead ... and no, I don't have code to do that ;)

dynamically update JPanel background does't work

After reading image from JFilechooser, I am trying to read pixel of an image one by one and display it to JPanel after some delay in sequential manner. can't update the background of JPanel.
public class ImageMain extends JFrame implements ActionListener {
/**
*
*/
private static final long serialVersionUID = 2916361361443483318L;
private JFileChooser fc = null;
private JMenuItem item1, item2;
private BufferedImage image = null;
private JPanel panel = null;
private int width = 0;
private int height = 0;
private BorderLayout card;
private Container contentPane;
//private int loopcount = 0;
//private int counter = 0;
public ImageMain() {
JFrame frame = new JFrame("Image Extraction Tool");
frame.setExtendedState(Frame.MAXIMIZED_BOTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
contentPane = frame.getContentPane();
panel = new JPanel();
card = new BorderLayout();
panel.setLayout(card);
panel.setBackground(Color.white);
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("Menu");
menuBar.add(menu);
item1 = new JMenuItem("Browse an image");
item2 = new JMenuItem("Exit");
item1.addActionListener(this);
item2.addActionListener(this);
menu.add(item1);
menu.add(item2);
frame.setJMenuBar(menuBar);
contentPane.add(panel);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
try {
SwingUtilities.invokeAndWait(new Runnable() {
#Override
public void run() {
ImageMain img = new ImageMain();
}
});
} catch (InvocationTargetException | InterruptedException e) {
e.printStackTrace();
}
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == item1) {
if (fc == null)
fc = new JFileChooser();
int retVal = fc.showOpenDialog(null);
if (retVal == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
try {
image = ImageIO.read(file);
height = image.getHeight();
width = image.getWidth();
// final int[][] pixelData = new int[height * width][3];
// int[] rgb;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
System.out.println(i + " " + j);
Color c = new Color(image.getRGB(j, i));
panel.setBackground(c);
panel.invalidate();
panel.validate();
panel.repaint();
}
}
} catch (IOException e1) {
System.out.println("IO::" + e1.getMessage());
} catch (Exception e1) {
System.out.println("Exception::" + e1.getMessage());
}
}
}
if (e.getSource() == item2) {
System.exit(0);
}
}}
Inside ActionPerformed, I got Color object by reading RGB values and then I am stuck at displaying them to JApplet. Suggestion are welcome if there is a better way to achieve this.
Thanks in advance.
The main problem is your performing a long running task within the context of the Event Dispatching Thread, which is responsible for, amongst other things, processing repaint requests.
#Override
public void actionPerformed(ActionEvent e) {
//...
// Nothing will be updated until after the
// actionPerformed method exists
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
System.out.println(i + " " + j);
Color c = new Color(image.getRGB(j, i));
panel.setBackground(c);
panel.invalidate();
panel.validate();
panel.repaint();
}
}
The other problem you have is that you are required to only modify the state of the UI from within the context of the EDT
Depending on your exact needs, you could use a SwingWorker, which would allow you to process the pixels in the background while updating the UI from within the context of the EDT, however, because SwingWorker consolidates it's updates, you could miss color changes.
A better solution might be to use a java.swing.Timer which would allow you to trigger updates at a specified period, which are triggered within the context of the EDT.
See Concurrency in Swing for more details...
Updated with example
In order to draw pixels, you need something to draw them on. Now, you could simply add each pixel you want to paint to an array and loop that array each time you need to repaint the component, but that's kind of expensive...
Instead, it would be simpler to have a backing buffer of some kind, onto which you paint the pixels and then paint that buffer to the component, which should be faster.
Basically, the allows you to supply the height and width of the expected image and then supply each pixel as you need..
public class ImagePane extends JPanel {
private BufferedImage img;
public ImagePane() {
}
public void reset(int width, int height) {
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
revalidate();
}
public void reset() {
img = null;
revalidate();
}
public void setPixelAt(int x, int y, int pixel) {
img.setRGB(x, y, pixel);
}
#Override
public Dimension getPreferredSize() {
return img == null ? new Dimension(200, 200) : new Dimension(img.getWidth(), img.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (img != null) {
int x = (getWidth() - img.getWidth()) / 2;
int y = (getHeight() - img.getHeight()) / 2;
g2d.drawImage(img, x, y, this);
}
g2d.dispose();
}
}
Take a look at Performing Custom Painting for more details...
Then you need some way to process the original image and update the image panel...Now, based on the updated requirements, I would use a SwingWorker, the reason for this, is that the SwingWorker can cache what is passed back to the EDT, this allows the background thread to continue processing and caching the output until the EDT (and system) is ready to process it...
public class PixelExposerWorker extends SwingWorker<Void, Pixel> {
private final BufferedImage img;
private final ImagePane imagePane;
private final List<Point> points;
public PixelExposerWorker(BufferedImage img, ImagePane imagePane) {
this.img = img;
this.imagePane = imagePane;
points = new ArrayList<>(img.getWidth() * img.getHeight());
for (int x = 0; x < img.getWidth(); x++) {
for (int y = 0; y < img.getHeight(); y++) {
points.add(new Point(x, y));
}
}
}
#Override
protected void process(List<Pixel> chunks) {
System.out.println("Publish " + chunks.size());
for (Pixel pixel : chunks) {
imagePane.setPixelAt(pixel.getX(), pixel.getY(), pixel.getColor());
}
imagePane.repaint();
}
#Override
protected Void doInBackground() throws Exception {
int pixelCount = (int) (points.size() * 0.005);
while (!points.isEmpty()) {
for (int count = 0; count < pixelCount && !points.isEmpty(); count++) {
int index = (int) (Math.random() * (points.size() - 1));
Point p = points.remove(index);
Pixel pixel = new Pixel(p.x, p.y, img.getRGB(p.x, p.y));
publish(pixel);
}
Thread.yield();
}
return null;
}
}
Basically, this SwingWorker builds a List of "pixel points", it uses the list to randomly remove points from the list, generate a virtual Pixel and publish back to the EDT for processing. The worker will process around 0.5% of the pixels at a time, meaning that the work is always trying to send a "bunch" of pixels back to the EDT, rather the one at a time.
Finally, it will yield to allow other threads to run (and the hopefully for the EDT to update it self)
An image of 650x975 takes roughly 1m and 10s to fully renderer
And the full code...
import core.util.StopWatch;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.Timer;
public class PixelShower implements ActionListener {
private static final long serialVersionUID = 2916361361443483318L;
private JFileChooser fc = null;
private JMenuItem item1, item2;
private BufferedImage image = null;
private ImagePane panel = null;
private int width = 0;
private int height = 0;
private BorderLayout card;
private Container contentPane;
public PixelShower() {
JFrame frame = new JFrame("Image Extraction Tool");
frame.setExtendedState(Frame.MAXIMIZED_BOTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
contentPane = frame.getContentPane();
panel = new ImagePane();
card = new BorderLayout();
panel.setLayout(card);
panel.setBackground(Color.white);
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("Menu");
menuBar.add(menu);
item1 = new JMenuItem("Browse an image");
item2 = new JMenuItem("Exit");
item1.addActionListener(this);
item2.addActionListener(this);
menu.add(item1);
menu.add(item2);
frame.setJMenuBar(menuBar);
contentPane.add(panel);
frame.setVisible(true);
}
public static void main(String[] args) {
try {
SwingUtilities.invokeAndWait(new Runnable() {
#Override
public void run() {
PixelShower img = new PixelShower();
}
});
} catch (InvocationTargetException | InterruptedException e) {
e.printStackTrace();
}
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == item1) {
if (fc == null) {
fc = new JFileChooser();
}
int retVal = fc.showOpenDialog(null);
if (retVal == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
try {
image = ImageIO.read(file);
panel.reset(image.getWidth(), image.getHeight());
PixelExposerWorker worker = new PixelExposerWorker(image, panel);
worker.execute();
} catch (IOException e1) {
e1.printStackTrace();
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
if (e.getSource() == item2) {
System.exit(0);
}
}
public class ImagePane extends JPanel {
private BufferedImage img;
public ImagePane() {
}
public void reset(int width, int height) {
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
revalidate();
}
public void reset() {
img = null;
revalidate();
}
public void setPixelAt(int x, int y, int pixel) {
img.setRGB(x, y, pixel);
}
#Override
public Dimension getPreferredSize() {
return img == null ? new Dimension(200, 200) : new Dimension(img.getWidth(), img.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (img != null) {
int x = (getWidth() - img.getWidth()) / 2;
int y = (getHeight() - img.getHeight()) / 2;
g2d.drawImage(img, x, y, this);
}
g2d.dispose();
}
}
public class Pixel {
private int x;
private int y;
private int color;
public Pixel(int x, int y, int color) {
this.x = x;
this.y = y;
this.color = color;
}
public int getColor() {
return color;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
public class PixelExposerWorker extends SwingWorker<Void, Pixel> {
private final BufferedImage img;
private final ImagePane imagePane;
private final List<Point> points;
public PixelExposerWorker(BufferedImage img, ImagePane imagePane) {
this.img = img;
this.imagePane = imagePane;
points = new ArrayList<>(img.getWidth() * img.getHeight());
for (int x = 0; x < img.getWidth(); x++) {
for (int y = 0; y < img.getHeight(); y++) {
points.add(new Point(x, y));
}
}
}
#Override
protected void process(List<Pixel> chunks) {
System.out.println("Publish " + chunks.size());
for (Pixel pixel : chunks) {
imagePane.setPixelAt(pixel.getX(), pixel.getY(), pixel.getColor());
}
imagePane.repaint();
}
#Override
protected Void doInBackground() throws Exception {
StopWatch sw = StopWatch.newInstance().start();
int pixelCount = (int) (points.size() * 0.005);
System.out.println("pixelCount = " + pixelCount + "; " + points.size());
while (!points.isEmpty()) {
StopWatch sw1 = StopWatch.newInstance().start();
for (int count = 0; count < pixelCount && !points.isEmpty(); count++) {
int index = (int) (Math.random() * (points.size() - 1));
Point p = points.remove(index);
Pixel pixel = new Pixel(p.x, p.y, img.getRGB(p.x, p.y));
publish(pixel);
}
Thread.yield();
}
System.out.println("Took " + sw.stop());
return null;
}
}
}

Categories