Skip to content

Commit 55c9bda

Browse files
committed
Fix HeadlessException in Travis build
1 parent b64caaf commit 55c9bda

File tree

3 files changed

+207
-18
lines changed

3 files changed

+207
-18
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ script:
1212
- mvn test -B
1313

1414
after_success:
15-
- mvn clean cobertura:cobertura coveralls:report -B -P ci
15+
- mvn cobertura:cobertura coveralls:report -B -P ci
1616

1717
branches:
1818
except:
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
package com.github.sarxos.webcam;
2+
import java.awt.AWTException;
3+
import java.awt.Component;
4+
import java.awt.Container;
5+
import java.awt.Dimension;
6+
import java.awt.Graphics2D;
7+
import java.awt.Point;
8+
import java.awt.Rectangle;
9+
import java.awt.Robot;
10+
import java.awt.Toolkit;
11+
import java.awt.image.BufferedImage;
12+
import java.io.File;
13+
import java.io.IOException;
14+
import java.util.Arrays;
15+
import java.util.List;
16+
17+
import javax.imageio.ImageIO;
18+
import javax.swing.JComponent;
19+
import javax.swing.SwingUtilities;
20+
21+
22+
/*
23+
* Convenience class to create and optionally save to a file a
24+
* BufferedImage of an area on the screen. Generally there are
25+
* four different scenarios. Create an image of:
26+
*
27+
* a) an entire component
28+
* b) a region of the component
29+
* c) the entire desktop
30+
* d) a region of the desktop
31+
*
32+
* The first two use the Swing paint() method to draw the
33+
* component image to the BufferedImage. The latter two use the
34+
* AWT Robot to create the BufferedImage.
35+
*
36+
* The created image can then be saved to a file by usig the
37+
* writeImage(...) method. The type of file must be supported by the
38+
* ImageIO write method.
39+
*
40+
* Although this class was originally designed to create an image of a
41+
* component on the screen it can be used to create an image of components
42+
* not displayed on a GUI. Behind the scenes the component will be given a
43+
* size and the component will be layed out. The default size will be the
44+
* preferred size of the component although you can invoke the setSize()
45+
* method on the component before invoking a createImage(...) method. The
46+
* default functionality should work in most cases. However the only
47+
* foolproof way to get a image to is make sure the component has been
48+
* added to a realized window with code something like the following:
49+
*
50+
* JFrame frame = new JFrame();
51+
* frame.setContentPane( someComponent );
52+
* frame.pack();
53+
* ScreenImage.createImage( someComponent );
54+
*
55+
*/
56+
public class ScreenImage {
57+
58+
private static List<String> types = Arrays.asList(ImageIO.getWriterFileSuffixes());
59+
60+
/*
61+
* Create a BufferedImage for Swing components. The entire component will be captured to an
62+
* image.
63+
* @param component Swing component to create image from
64+
* @return image the image for the given region
65+
*/
66+
public static BufferedImage createImage(JComponent component) {
67+
Dimension d = component.getSize();
68+
69+
if (d.width == 0 || d.height == 0) {
70+
d = component.getPreferredSize();
71+
component.setSize(d);
72+
}
73+
74+
Rectangle region = new Rectangle(0, 0, d.width, d.height);
75+
return ScreenImage.createImage(component, region);
76+
}
77+
78+
/*
79+
* Create a BufferedImage for Swing components. All or part of the component can be captured to
80+
* an image.
81+
* @param component Swing component to create image from
82+
* @param region The region of the component to be captured to an image
83+
* @return image the image for the given region
84+
*/
85+
public static BufferedImage createImage(JComponent component, Rectangle region) {
86+
// Make sure the component has a size and has been layed out.
87+
// (necessary check for components not added to a realized frame)
88+
89+
if (!component.isDisplayable()) {
90+
Dimension d = component.getSize();
91+
92+
if (d.width == 0 || d.height == 0) {
93+
d = component.getPreferredSize();
94+
component.setSize(d);
95+
}
96+
97+
layoutComponent(component);
98+
}
99+
100+
BufferedImage image = new BufferedImage(region.width, region.height, BufferedImage.TYPE_INT_RGB);
101+
Graphics2D g2d = image.createGraphics();
102+
103+
// Paint a background for non-opaque components,
104+
// otherwise the background will be black
105+
106+
if (!component.isOpaque()) {
107+
g2d.setColor(component.getBackground());
108+
g2d.fillRect(region.x, region.y, region.width, region.height);
109+
}
110+
111+
g2d.translate(-region.x, -region.y);
112+
component.print(g2d);
113+
g2d.dispose();
114+
return image;
115+
}
116+
117+
/**
118+
* Convenience method to create a BufferedImage of the desktop
119+
*
120+
* @param fileName name of file to be created or null
121+
* @return image the image for the given region
122+
* @exception AWTException see Robot class constructors
123+
* @exception IOException if an error occurs during writing
124+
*/
125+
public static BufferedImage createDesktopImage()
126+
throws AWTException, IOException {
127+
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
128+
Rectangle region = new Rectangle(0, 0, d.width, d.height);
129+
return ScreenImage.createImage(region);
130+
}
131+
132+
/*
133+
* Create a BufferedImage for AWT components. This will include Swing components JFrame, JDialog
134+
* and JWindow which all extend from Component, not JComponent.
135+
* @param component AWT component to create image from
136+
* @return image the image for the given region
137+
* @exception AWTException see Robot class constructors
138+
*/
139+
public static BufferedImage createImage(Component component)
140+
throws AWTException {
141+
Point p = new Point(0, 0);
142+
SwingUtilities.convertPointToScreen(p, component);
143+
Rectangle region = component.getBounds();
144+
region.x = p.x;
145+
region.y = p.y;
146+
return ScreenImage.createImage(region);
147+
}
148+
149+
/**
150+
* Create a BufferedImage from a rectangular region on the screen.
151+
*
152+
* @param region region on the screen to create image from
153+
* @return image the image for the given region
154+
* @exception AWTException see Robot class constructors
155+
*/
156+
public static BufferedImage createImage(Rectangle region)
157+
throws AWTException {
158+
BufferedImage image = new Robot().createScreenCapture(region);
159+
return image;
160+
}
161+
162+
/**
163+
* Write a BufferedImage to a File.
164+
*
165+
* @param image image to be written
166+
* @param fileName name of file to be created
167+
* @exception IOException if an error occurs during writing
168+
*/
169+
public static void writeImage(BufferedImage image, String fileName)
170+
throws IOException {
171+
if (fileName == null)
172+
return;
173+
174+
int offset = fileName.lastIndexOf(".");
175+
176+
if (offset == -1) {
177+
String message = "file suffix was not specified";
178+
throw new IOException(message);
179+
}
180+
181+
String type = fileName.substring(offset + 1);
182+
183+
if (types.contains(type)) {
184+
ImageIO.write(image, type, new File(fileName));
185+
} else {
186+
String message = "unknown writer file suffix (" + type + ")";
187+
throw new IOException(message);
188+
}
189+
}
190+
191+
static void layoutComponent(Component component) {
192+
synchronized (component.getTreeLock()) {
193+
component.doLayout();
194+
195+
if (component instanceof Container) {
196+
for (Component child : ((Container) component).getComponents()) {
197+
layoutComponent(child);
198+
}
199+
}
200+
}
201+
}
202+
203+
}

webcam-capture/src/test/java/com/github/sarxos/webcam/WebcamPanelTest.java

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
import java.awt.Dimension;
44
import java.awt.image.BufferedImage;
55

6-
import javax.swing.JFrame;
7-
86
import org.assertj.core.api.Assertions;
97
import org.junit.Test;
108

@@ -79,14 +77,10 @@ public void test_modeFill() throws InterruptedException {
7977
.assertThat(p.getDrawMode())
8078
.isEqualTo(DrawMode.FILL);
8179

82-
final JFrame frame = new JFrame();
83-
frame.setContentPane(p);
84-
frame.pack();
80+
ScreenImage.createImage(p);
8581

8682
Thread.sleep(100);
8783

88-
frame.dispose();
89-
9084
p.stop();
9185
w.close();
9286
}
@@ -107,14 +101,10 @@ public void test_modeFit() throws InterruptedException {
107101
.assertThat(p.getDrawMode())
108102
.isEqualTo(DrawMode.FIT);
109103

110-
final JFrame frame = new JFrame();
111-
frame.setContentPane(p);
112-
frame.pack();
104+
ScreenImage.createImage(p);
113105

114106
Thread.sleep(100);
115107

116-
frame.dispose();
117-
118108
p.stop();
119109
w.close();
120110
}
@@ -135,14 +125,10 @@ public void test_modeNone() throws InterruptedException {
135125
.assertThat(p.getDrawMode())
136126
.isEqualTo(DrawMode.NONE);
137127

138-
final JFrame frame = new JFrame();
139-
frame.setContentPane(p);
140-
frame.pack();
128+
ScreenImage.createImage(p);
141129

142130
Thread.sleep(100);
143131

144-
frame.dispose();
145-
146132
p.stop();
147133
w.close();
148134
}

0 commit comments

Comments
 (0)