I have multiple games running on 60 frame per second rate. I need to capture each frame and clone into four different screen with specific filter.
Software will work on dual screen monitor where primary and secondary screen will be responsible for running game and displaying four filter view respectively.
Limitation on applying filter:
- Filter will work on image only.
- Filter is written in java which almost impossible to rewrite.
So I am applying logic something like below:
import java.awt.*;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import com.sun.jna.platform.win32.GDI32Util;
import com.sun.jna.platform.win32.WinDef.HWND;
import java.awt.image.BufferedImage;
public class MultiFrameApplet implements Runnable
{
public JFrame currentFrame = null;
public PanelPaint currentCanvas = null;
public BufferedImage screenshotImage = null;
com.sun.jna.platform.win32.User32 user32 = null;
HWND hwnd = null;
Thread th = null;
String CurrentFrameText = "";
private long lastTime;
private double fps; //could be int or long for integer values
public MultiFrameApplet(int filtertype)
{
main(null,filtertype);
}
public void main(String[] argv,int filtertype)
{
try
{
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice[] gd = ge.getScreenDevices();
//First Screen
GraphicsConfiguration gcFirst = gd[0].getDefaultConfiguration();
Toolkit toolkit = Toolkit.getDefaultToolkit();
if (toolkit == null)
{
return;
}
Rectangle screenRectFirst = gcFirst.getBounds();
Insets screenInsetsFirst = toolkit.getScreenInsets(gcFirst);
screenRectFirst.x = screenInsetsFirst.left;
screenRectFirst.y = screenInsetsFirst.top;
Robot robot = new Robot(gcFirst.getDevice());
//Second Screen
GraphicsConfiguration gcSecond = gd[1].getDefaultConfiguration();
Rectangle screenRectSecond = gcSecond.getBounds();
Insets screenInsetsSecond = Toolkit.getDefaultToolkit().getScreenInsets(gcSecond);
Rectangle effectiveScreenArea = new Rectangle();
/*Remove start bar area*/
effectiveScreenArea.x = screenRectSecond.x + screenInsetsSecond.left;
effectiveScreenArea.y = screenRectSecond.y + screenInsetsSecond.top;
effectiveScreenArea.height = screenRectSecond.height - screenInsetsSecond.top - screenInsetsSecond.bottom;
effectiveScreenArea.width = screenRectSecond.width - screenInsetsSecond.left - screenInsetsSecond.right;
//Scaling will decide capture image needs to shrink or not.!
double xscaling = 0;
double yscaling = 0;
screenshotImage = robot.createScreenCapture(screenRectFirst);
int differenceWidth = screenRectSecond.width / screenRectFirst.width;
int differenceheight = screenRectSecond.height / screenRectFirst.height;
xscaling = differenceWidth / 2.0;
yscaling = differenceheight / 2.0;
yscaling = yscaling - 0.018;
currentFrame = new JFrame();
currentFrame.setSize((int)effectiveScreenArea.width/2, (int)effectiveScreenArea.height/2);
if(filtertype == 0)
{
currentFrame.setLocation(effectiveScreenArea.x, effectiveScreenArea.y);
currentFrame.setTitle("First");
CurrentFrameText = "First";
}
else if(filtertype == 1)
{
currentFrame.setLocation(effectiveScreenArea.x + ((int)effectiveScreenArea.width/2), effectiveScreenArea.y);
currentFrame.setTitle("Second");
CurrentFrameText = "Second";
}
else if(filtertype == 2)
{
currentFrame.setLocation(effectiveScreenArea.x + ((int)effectiveScreenArea.width/2), effectiveScreenArea.y);
currentFrame.setTitle("Third");
CurrentFrameText = "Third";
}
else if(filtertype == 3)
{
currentFrame.setLocation(effectiveScreenArea.x + ((int)effectiveScreenArea.width/2),effectiveScreenArea.y + ((int)effectiveScreenArea.height/2));
currentFrame.setTitle("Forth");
CurrentFrameText = "Forth";
}
currentCanvas = new PanelPaint((int)effectiveScreenArea.width/2,(int)effectiveScreenArea.height/2,xscaling,yscaling,CurrentFrameText);
currentCanvas.xpos = (int)effectiveScreenArea.width/2;
currentCanvas.ypos = (int)effectiveScreenArea.height/2;
currentFrame.getContentPane().add(currentCanvas);
currentFrame.setUndecorated(true);
currentFrame.setVisible(true);
user32 = com.sun.jna.platform.win32.User32.INSTANCE;
hwnd = user32.GetDesktopWindow();
th = new Thread(this);
th.start();
}
catch (AWTException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void close()
{
currentFrame.dispose();
currentFrame = null;
currentCanvas.close();
currentCanvas = null;
screenshotImage = null;
user32 = null;
hwnd = null;
th = null;
}
@Override
public void run()
{
while(true)
{
lastTime = System.nanoTime();
screenshotImage = GDI32Util.getScreenshot(hwnd);
///screenshotImage = screenshotImage.Convert(); //Place where filter applied
currentCanvas.setImg(screenshotImage,fps);
java.awt.EventQueue.invokeLater(currentCanvas::repaint);
fps = 1000000000.0 / (System.nanoTime() - lastTime); //one second(nano) divided by amount of time it takes for one frame to finish
lastTime = System.nanoTime();
}
}
}
@SuppressWarnings("serial")
class PanelPaint extends javax.swing.JPanel
{
public int xpos = 0;
public int ypos = 0;
BufferedImage img = null;
java.awt.Graphics2D gc = null;
Font currentFont = null;
double fps = 0;
String CurrentFrameText;
PanelPaint(int xpos,int ypos,double sx,double sy,String argCurrentFrameText)
{
img = new BufferedImage(xpos, ypos, BufferedImage.TYPE_INT_ARGB);
gc = img.createGraphics();
gc.scale(sx, sy);
currentFont = new Font("default", Font.BOLD, 30);
CurrentFrameText = argCurrentFrameText;
gc.setFont(currentFont);
gc.setColor(Color.RED);
}
@Override
public Dimension getPreferredSize()
{
return new Dimension(xpos, ypos);
}
public void setImg(BufferedImage img,double argfps)
{
gc.drawImage(img, 0, 0, null);
gc.drawString(CurrentFrameText + ": " + (int)fps, 25, 25);
fps = argfps;
}
@Override
public void paint(java.awt.Graphics g)
{
g.drawImage(img, 0, 0, null);
}
public void close()
{
img = null;
gc = null;
currentFont = null;
}
}
Above is slower for high contrast images and taking time for "g.drawImage(img, 0, 0, null);" code. Can performance for draw image can be improve?