我将从下到上开始解释,这样您就可以真正了解我的目标,并更好地理解我的代码。
我正在创建一个库,让您捕获一个区域,无论捕获是gif动画还是图像。捕获完成后,库将返回包含ByteArrayInputStream
的对象和createImage
之类的util方法。
阅读本文时,您可以访问此库:https://github.com/BenBeri/WiseCapturer/
现在这是关于我的图书馆工作方式的一个虚拟示例:
您的应用程序使用capturer类创建一个bootstrap实例,并开始捕获:
public static void main(String[] args) throws AWTException {
final Bootstrap b = new Bootstrap(new ScreenshotCapturer());
b.beginCapture(new ScreenCaptureCallback() {
@Override
public void captureEnded(CapturedImage img) {
b.beginCapture(new ScreenCaptureCallback() {
@Override
public void captureEnded(CapturedImage img) {
JFrame frame = new JFrame();
frame.add(new JLabel(new ImageIcon(img.getBufferedImage())));
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
});
}
});
}
听众将返回CapturedImage
,您可以使用它来做任何您想做的事情。
现在通过这个例子,这可以让你在完成后一次又一次地捕获两次,一旦完成,它将在JFrame窗口中显示第二次捕获。
现在我不是在谈论这个JFrame。
问题只发生在ScreeenshotCapturer
,它可以与GifCapturer
实例配合使用。
完成第一次捕获后,第二个捕获JFrame透明窗口将不会出现,我不会在Windows工具栏中看到它,也不会在任何地方看到它,但应用程序仍在运行。
但是,正如我所说,如果我使用GifCapturer实例,它确实有用。
现在让我们调试我的库的工作方式:
Bootstrap构造函数:
/**
* Bootstrap consturctor, let it bootstrap!
* @param c
* Capturer instance
* @throws AWTException
*/
public Bootstrap(Capturer c) throws AWTException {
this.capturer = c;
}
现在Capturer类初始化,它是抽象类,是所有捕获器的相同构造函数:
public Capturer() throws AWTException {
this.camera = new CaptureCamera(this);
}
这会创建一个新的捕获相机,这是我遇到问题的地方。 CaptureCamera的目的是拥有整个JFrame,透明大小与我的屏幕相同,并在其中包含负责选择矩形绘图的JPanel。
它的构造函数:
public CaptureCamera(Capturer c) throws AWTException {
this.c = c;
this.toolkit = Toolkit.getDefaultToolkit();
this.screen = this.toolkit.getScreenSize();
this.robot = new Robot();
this.selector = new SelectionCamera();
super.setSize(this.screen);
super.setUndecorated(true);
super.setBackground(new Color(255, 255, 255, 1));
// Listeners for area selection
super.addMouseListener(new SelectionAdapter(this, this.selector));
super.addMouseMotionListener(new SelectionMotion(this, this.selector));
super.add(this.selector);
}
好的,现在让我们来看看捕获是如何开始的。
bootstrap中的beginCapture
方法:
/**
* Starts capturing the screen, sends back a callback event with the
* captured file.
*
* The system saves a temporary file to send the file.
* @param c
* Callback instance
*/
public void beginCapture(ScreenCaptureCallback c) {
this.capturer.setCallback(c);
this.capturer.beginSelection();
}
setCallback
对此问题并不重要,因此beginSelection
方法:
所有捕获者都一样
@Override
public void beginSelection() {
super.init();
this.setHotkeys();
super.getCamera().startSelection();
}
startSelection方法(对于以后具有相同含义的笨重复名称而感到抱歉):
/**
* Starts area selection event
* @param c Capturer instance
*/
public void startSelection() {
super.setVisible(true);
}
好的,这就是它应该让JFrame可见的地方,我之前尝试过打印并且显示正确,但JFrame在第二次尝试时没有显示。
现在框架可见,用户可以选择一个区域。
选择后,mouese适配器将执行startCapturing
方法。
startCapturing
:
@Override
public void startCapturing(final int x, final int y, final int width, final int height) {
this.border = new GifCaptureBorder(x, y, width, height);
this.process = new TimerCaptureProcess(this, x, y, width, height);
Timer timer = new Timer();
timer.schedule(this.process, 0, 600);
}
` ScreenshotCapturer 中的startCapturing:
@Override
public void startCapturing(int x, int y, int width, int height) {
Robot robot = super.getCamera().getRobot();
BufferedImage image = robot.createScreenCapture(new Rectangle(x, y, width, height));
super.disableSelectionFrame();
try {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
ImageIO.write(image, "png", stream);
super.setCaptureResult(stream);
super.finish();
} catch (IOException e) {
e.printStackTrace();
}
}
现在在 GifCapturer 中,流程会更长,因为它实际上会启动Timer
来截取每个60ms
的每个帧的屏幕截图。
要完成捕获gif,请单击"输入",我使用JKeyMaster检测热键。
点击" ENTER"后,此方法将在GifCapturer
public void createGif() {
super.disableSelectionFrame();
AnimatedGifEncoder gif = new AnimatedGifEncoder();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
gif.start(stream);
gif.setDelay(1000);
this.border.updateProgress(10);
for(int i = 0; i < this.frames.size(); i++) {
gif.addFrame(this.frames.get(i));
}
this.border.updateProgress(50);
gif.finish();
super.setCaptureResult(stream);
this.border.updateProgress(100);
super.finish();
this.border.setVisible(false);
this.border = null;
}
这就是它,如果我将使用GifCapturer
两次,一切正常,但如果我将使用ScreenshotCapturer
两次,JFrame将不会第二次出现!
我不确定为什么,这可能是Swing中的一个错误吗?也许是因为GifCapturer
需要更长时间才能使框架可见?
我做错了什么?
答案 0 :(得分:2)
好的,据我所知,你遇到的问题是这个代码...
基本上,WiseCapturer API允许您拖动&#34;当您拨打beginCapture
...
public static void main(String[] args) throws AWTException {
final Bootstrap b = new Bootstrap(new ScreenshotCapturer());
b.beginCapture(new ScreenCaptureCallback() {
@Override
public void captureEnded(CapturedImage img) {
b.beginCapture(new ScreenCaptureCallback() {
@Override
public void captureEnded(CapturedImage img) {
JFrame frame = new JFrame();
frame.add(new JLabel(new ImageIcon(img.getBufferedImage())));
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
});
}
});
}
你遇到的问题是在调用captureEnded
时(对于外部捕获),内部捕获过程没有说明(并且你不能拖延&#34;透明选择矩形)...
这似乎是因为只要线程/事件队列WiseCapturer正在使用并且captureEnded
事件未被允许完成就会阻塞...
如果我做某事......
try {
final Bootstrap b = new Bootstrap(new ScreenshotCapturer());
b.beginCapture(new ScreenCaptureCallback() {
@Override
public void captureEnded(CapturedImage img) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
b.beginCapture(new ScreenCaptureCallback() {
@Override
public void captureEnded(CapturedImage img) {
System.out.println("...");
JFrame frame = new JFrame();
frame.add(new JLabel(new ImageIcon(img.getBufferedImage())));
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
});
}
});
t.start();
}
});
System.out.println("Hello");
} catch (AWTException exp) {
exp.printStackTrace();
}
在外部Thread
电话中开始新的captureEnded
,我可以让它发挥作用......
另外,我不知道此API的线程安全规则,我还使用了SwingUtilities.invokeLater
try {
final Bootstrap b = new Bootstrap(new ScreenshotCapturer());
b.beginCapture(new ScreenCaptureCallback() {
@Override
public void captureEnded(CapturedImage img) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
b.beginCapture(new ScreenCaptureCallback() {
@Override
public void captureEnded(CapturedImage img) {
System.out.println("...");
JFrame frame = new JFrame();
frame.add(new JLabel(new ImageIcon(img.getBufferedImage())));
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
});
}
});
}
});
System.out.println("Hello");
} catch (AWTException exp) {
exp.printStackTrace();
}
并且有它的工作......我也有点担心你为什么会这样做,但那只是我