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+ }
0 commit comments