У меня несколько игр, работающих на скорости 60 кадров в секунду. Мне нужно захватить каждый кадр и клонировать на четыре разных экрана с определенным фильтром.
Программное обеспечение будет работать на двухэкранном мониторе, где основной и дополнительный экраны будут отвечать за запуск игры и отображать четыре фильтра соответственно.
Ограничение на применение фильтра:
- Фильтр будет работать только на изображении.
- Фильтр написан на Java, который практически невозможно переписать.
Поэтому я применяю логику примерно так:
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;
}
}
Выше медленнее для высококонтрастных изображений и требуется время для " g.drawImage (img, 0,0, ноль);"код. Можно ли улучшить производительность рисования изображения?