Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

1199
LINES

< > BotCompany Repo | #1014901 // JavaX Live WebCam - Show live webcam image in frame v5 [try to minimize CPU when iconified - program works, but doesn't make a difference to vanilla WebcamPanel]

JavaX source code (desktop) [tags: use-pretranspiled] - run with: x30.jar

Download Jar. Uses 6490K of libraries. Click here for Pure Java version (10470L/73K).

1  
!7
2  
3  
import static java.awt.RenderingHints.KEY_ANTIALIASING;
4  
import static java.awt.RenderingHints.KEY_INTERPOLATION;
5  
import static java.awt.RenderingHints.KEY_RENDERING;
6  
import static java.awt.RenderingHints.VALUE_ANTIALIAS_OFF;
7  
import static java.awt.RenderingHints.VALUE_ANTIALIAS_ON;
8  
import static java.awt.RenderingHints.VALUE_INTERPOLATION_BILINEAR;
9  
import static java.awt.RenderingHints.VALUE_RENDER_SPEED;
10  
11  
import java.beans.PropertyChangeEvent;
12  
import java.beans.PropertyChangeListener;
13  
import org.slf4j.Logger;
14  
import org.slf4j.LoggerFactory;
15  
16  
static BufferedImage imageFromWebcamPanel(WebcamPanel2 panel) {
17  
  ret panel.image;
18  
}
19  
/**
20  
 * Simply implementation of JPanel allowing users to render pictures taken with webcam.
21  
 *
22  
 * @author Bartosz Firyn (SarXos)
23  
 */
24  
sclass WebcamPanel2 extends JPanel implements WebcamListener, PropertyChangeListener {
25  
26  
	/**
27  
	 * This enum is to control of how image will be drawn in the panel bounds.
28  
	 *
29  
	 * @author Sylwia Kauczor
30  
	 */
31  
	public enum DrawMode {
32  
33  
		/**
34  
		 * Do not resize image - paint it as it is. This will make the image to go off out the
35  
		 * bounds if panel is smaller than image size.
36  
		 */
37  
		NONE,
38  
39  
		/**
40  
		 * Will resize image to the panel bounds. This mode does not care of the image scale, so the
41  
		 * final image may be disrupted.
42  
		 */
43  
		FILL,
44  
45  
		/**
46  
		 * Will fir image into the panel bounds. This will resize the image and keep both x and y
47  
		 * scale factor.
48  
		 */
49  
		FIT,
50  
	}
51  
52  
	public interface ImageSupplier {
53  
		public BufferedImage get();
54  
	}
55  
56  
	private static class DefaultImageSupplier implements ImageSupplier {
57  
58  
		private final Webcam webcam;
59  
60  
		public DefaultImageSupplier(Webcam webcam) {
61  
			this.webcam = webcam;
62  
		}
63  
64  
		@Override
65  
		public BufferedImage get() {
66  
			return webcam.getImage();
67  
		}
68  
	}
69  
70  
	/**
71  
	 * Interface of the painter used to draw image in panel.
72  
	 *
73  
	 * @author Bartosz Firyn (SarXos)
74  
	 */
75  
	public interface Painter {
76  
77  
		/**
78  
		 * Paint panel without image.
79  
		 *
80  
		 * @param panel the webcam panel to paint on
81  
		 * @param g2 the graphics 2D object used for drawing
82  
		 */
83  
		void paintPanel(WebcamPanel2 panel, Graphics2D g2);
84  
85  
		/**
86  
		 * Paint webcam image in panel.
87  
		 *
88  
		 * @param panel the webcam panel to paint on
89  
		 * @param image the image from webcam
90  
		 * @param g2 the graphics 2D object used for drawing
91  
		 */
92  
		void paintImage(WebcamPanel2 panel, BufferedImage image, Graphics2D g2);
93  
	}
94  
95  
	/**
96  
	 * Default painter used to draw image in panel.
97  
	 *
98  
	 * @author Bartosz Firyn (SarXos)
99  
	 * @author Sylwia Kauczor
100  
	 */
101  
	public class DefaultPainter implements Painter {
102  
103  
		/**
104  
		 * Webcam device name.
105  
		 */
106  
		private String name = null;
107  
108  
		/**
109  
		 * Lat repaint time, uset for debug purpose.
110  
		 */
111  
		private long lastRepaintTime = -1;
112  
113  
		/**
114  
		 * Buffered image resized to fit into panel drawing area.
115  
		 */
116  
		private BufferedImage resizedImage = null;
117  
118  
		@Override
119  
		public void paintPanel(WebcamPanel2 owner, Graphics2D g2) {
120  
121  
			assert owner != null;
122  
			assert g2 != null;
123  
124  
			Object antialiasing = g2.getRenderingHint(KEY_ANTIALIASING);
125  
126  
			g2.setRenderingHint(KEY_ANTIALIASING, isAntialiasingEnabled() ? VALUE_ANTIALIAS_ON : VALUE_ANTIALIAS_OFF);
127  
			g2.setBackground(Color.BLACK);
128  
			g2.fillRect(0, 0, getWidth(), getHeight());
129  
130  
			int cx = (getWidth() - 70) / 2;
131  
			int cy = (getHeight() - 40) / 2;
132  
133  
			g2.setStroke(new BasicStroke(2));
134  
			g2.setColor(Color.LIGHT_GRAY);
135  
			g2.fillRoundRect(cx, cy, 70, 40, 10, 10);
136  
			g2.setColor(Color.WHITE);
137  
			g2.fillOval(cx + 5, cy + 5, 30, 30);
138  
			g2.setColor(Color.LIGHT_GRAY);
139  
			g2.fillOval(cx + 10, cy + 10, 20, 20);
140  
			g2.setColor(Color.WHITE);
141  
			g2.fillOval(cx + 12, cy + 12, 16, 16);
142  
			g2.fillRoundRect(cx + 50, cy + 5, 15, 10, 5, 5);
143  
			g2.fillRect(cx + 63, cy + 25, 7, 2);
144  
			g2.fillRect(cx + 63, cy + 28, 7, 2);
145  
			g2.fillRect(cx + 63, cy + 31, 7, 2);
146  
147  
			g2.setColor(Color.DARK_GRAY);
148  
			g2.setStroke(new BasicStroke(3));
149  
			g2.drawLine(0, 0, getWidth(), getHeight());
150  
			g2.drawLine(0, getHeight(), getWidth(), 0);
151  
152  
			String str;
153  
154  
			final String strInitDevice = rb.getString("INITIALIZING_DEVICE");
155  
			final String strNoImage = rb.getString("NO_IMAGE");
156  
			final String strDeviceError = rb.getString("DEVICE_ERROR");
157  
158  
			if (errored) {
159  
				str = strDeviceError;
160  
			} else {
161  
				str = starting ? strInitDevice : strNoImage;
162  
			}
163  
164  
			FontMetrics metrics = g2.getFontMetrics(getFont());
165  
			int w = metrics.stringWidth(str);
166  
			int h = metrics.getHeight();
167  
168  
			int x = (getWidth() - w) / 2;
169  
			int y = cy - h;
170  
171  
			g2.setFont(getFont());
172  
			g2.setColor(Color.WHITE);
173  
			g2.drawString(str, x, y);
174  
175  
			if (name == null) {
176  
				name = webcam.getName();
177  
			}
178  
179  
			str = name;
180  
181  
			w = metrics.stringWidth(str);
182  
			h = metrics.getHeight();
183  
184  
			g2.drawString(str, (getWidth() - w) / 2, cy - 2 * h);
185  
			g2.setRenderingHint(KEY_ANTIALIASING, antialiasing);
186  
		}
187  
188  
		@Override
189  
		public void paintImage(WebcamPanel2 owner, BufferedImage image, Graphics2D g2) {
190  
191  
			assert owner != null;
192  
			assert image != null;
193  
			assert g2 != null;
194  
195  
			int pw = getWidth();
196  
			int ph = getHeight();
197  
			int iw = image.getWidth();
198  
			int ih = image.getHeight();
199  
200  
			Object antialiasing = g2.getRenderingHint(KEY_ANTIALIASING);
201  
			Object rendering = g2.getRenderingHint(KEY_RENDERING);
202  
203  
			g2.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_OFF);
204  
			g2.setRenderingHint(KEY_RENDERING, VALUE_RENDER_SPEED);
205  
			g2.setBackground(Color.BLACK);
206  
			g2.setColor(Color.BLACK);
207  
			g2.fillRect(0, 0, pw, ph);
208  
209  
			// resized image position and size
210  
			int x = 0;
211  
			int y = 0;
212  
			int w = 0;
213  
			int h = 0;
214  
215  
			switch (drawMode) {
216  
				case NONE:
217  
					w = image.getWidth();
218  
					h = image.getHeight();
219  
					break;
220  
				case FILL:
221  
					w = pw;
222  
					h = ph;
223  
					break;
224  
				case FIT:
225  
					double s = Math.max((double) iw / pw, (double) ih / ph);
226  
					double niw = iw / s;
227  
					double nih = ih / s;
228  
					double dx = (pw - niw) / 2;
229  
					double dy = (ph - nih) / 2;
230  
					w = (int) niw;
231  
					h = (int) nih;
232  
					x = (int) dx;
233  
					y = (int) dy;
234  
					break;
235  
			}
236  
237  
			if (resizedImage != null) {
238  
				resizedImage.flush();
239  
			}
240  
241  
			if (w == image.getWidth() && h == image.getHeight() && !mirrored) {
242  
				resizedImage = image;
243  
			} else {
244  
245  
				GraphicsEnvironment genv = GraphicsEnvironment.getLocalGraphicsEnvironment();
246  
				GraphicsConfiguration gc = genv.getDefaultScreenDevice().getDefaultConfiguration();
247  
248  
				Graphics2D gr = null;
249  
				try {
250  
251  
					resizedImage = gc.createCompatibleImage(pw, ph);
252  
					gr = resizedImage.createGraphics();
253  
					gr.setComposite(AlphaComposite.Src);
254  
255  
					for (Map.Entry<RenderingHints.Key, Object> hint : imageRenderingHints.entrySet()) {
256  
						gr.setRenderingHint(hint.getKey(), hint.getValue());
257  
					}
258  
259  
					gr.setBackground(Color.BLACK);
260  
					gr.setColor(Color.BLACK);
261  
					gr.fillRect(0, 0, pw, ph);
262  
263  
					int sx1, sx2, sy1, sy2; // source rectangle coordinates
264  
					int dx1, dx2, dy1, dy2; // destination rectangle coordinates
265  
266  
					dx1 = x;
267  
					dy1 = y;
268  
					dx2 = x + w;
269  
					dy2 = y + h;
270  
271  
					if (mirrored) {
272  
						sx1 = iw;
273  
						sy1 = 0;
274  
						sx2 = 0;
275  
						sy2 = ih;
276  
					} else {
277  
						sx1 = 0;
278  
						sy1 = 0;
279  
						sx2 = iw;
280  
						sy2 = ih;
281  
					}
282  
283  
					gr.drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null);
284  
285  
				} finally {
286  
					if (gr != null) {
287  
						gr.dispose();
288  
					}
289  
				}
290  
			}
291  
292  
			g2.drawImage(resizedImage, 0, 0, null);
293  
294  
			if (isFPSDisplayed()) {
295  
296  
				String str = String.format("FPS: %.1f", webcam.getFPS());
297  
298  
				int sx = 5;
299  
				int sy = ph - 5;
300  
301  
				g2.setFont(getFont());
302  
				g2.setColor(Color.BLACK);
303  
				g2.drawString(str, sx + 1, sy + 1);
304  
				g2.setColor(Color.WHITE);
305  
				g2.drawString(str, sx, sy);
306  
			}
307  
308  
			if (isImageSizeDisplayed()) {
309  
310  
				String res = String.format("%d\u2A2F%d px", iw, ih);
311  
312  
				FontMetrics metrics = g2.getFontMetrics(getFont());
313  
				int sw = metrics.stringWidth(res);
314  
				int sx = pw - sw - 5;
315  
				int sy = ph - 5;
316  
317  
				g2.setFont(getFont());
318  
				g2.setColor(Color.BLACK);
319  
				g2.drawString(res, sx + 1, sy + 1);
320  
				g2.setColor(Color.WHITE);
321  
				g2.drawString(res, sx, sy);
322  
			}
323  
324  
			if (isDisplayDebugInfo()) {
325  
326  
				if (lastRepaintTime < 0) {
327  
					lastRepaintTime = System.currentTimeMillis();
328  
				} else {
329  
330  
					long now = System.currentTimeMillis();
331  
					String res = String.format("DEBUG: repaints per second: %.1f", (double) 1000 / (now - lastRepaintTime));
332  
					lastRepaintTime = now;
333  
					g2.setFont(getFont());
334  
					g2.setColor(Color.BLACK);
335  
					g2.drawString(res, 6, 16);
336  
					g2.setColor(Color.WHITE);
337  
					g2.drawString(res, 5, 15);
338  
				}
339  
			}
340  
341  
			g2.setRenderingHint(KEY_ANTIALIASING, antialiasing);
342  
			g2.setRenderingHint(KEY_RENDERING, rendering);
343  
		}
344  
	}
345  
346  
	private static final class PanelThreadFactory implements ThreadFactory {
347  
348  
		private static final AtomicInteger number = new AtomicInteger(0);
349  
350  
		@Override
351  
		public Thread newThread(Runnable r) {
352  
			Thread t = new Thread(r, String.format("webcam-panel-scheduled-executor-%d", number.incrementAndGet()));
353  
			t.setUncaughtExceptionHandler(WebcamExceptionHandler.getInstance());
354  
			t.setDaemon(true);
355  
			return t;
356  
		}
357  
	}
358  
359  
	/**
360  
	 * This runnable will do nothing more than repaint panel.
361  
	 */
362  
	private static final class SwingRepainter implements Runnable {
363  
364  
		private WebcamPanel2 panel = null;
365  
366  
		public SwingRepainter(WebcamPanel2 panel) {
367  
			this.panel = panel;
368  
		}
369  
370  
		@Override
371  
		public void run() {
372  
			panel.repaint();
373  
		}
374  
	}
375  
376  
	private static final long serialVersionUID = 1L;
377  
378  
	private static final Logger LOG = LoggerFactory.getLogger(WebcamPanel2.class);
379  
380  
	public static final double MIN_FREQUENCY = 0.016; // 1 frame per minute
381  
382  
	private static final double MAX_FREQUENCY = 50; // 50 frames per second
383  
384  
	private static final ThreadFactory THREAD_FACTORY = new PanelThreadFactory();
385  
386  
	public static final Map<RenderingHints.Key, Object> DEFAULT_IMAGE_RENDERING_HINTS = new HashMap<RenderingHints.Key, Object>();
387  
	static {
388  
		DEFAULT_IMAGE_RENDERING_HINTS.put(KEY_INTERPOLATION, VALUE_INTERPOLATION_BILINEAR);
389  
		DEFAULT_IMAGE_RENDERING_HINTS.put(KEY_RENDERING, VALUE_RENDER_SPEED);
390  
		DEFAULT_IMAGE_RENDERING_HINTS.put(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON);
391  
	}
392  
393  
	/**
394  
	 * This runnable will do nothing more than repaint panel.
395  
	 */
396  
	private final Runnable repaint = new SwingRepainter(this);
397  
398  
	/**
399  
	 * Rendering hints to be used when painting image to be displayed.
400  
	 */
401  
	private Map<RenderingHints.Key, Object> imageRenderingHints = new HashMap<RenderingHints.Key, Object>(DEFAULT_IMAGE_RENDERING_HINTS);
402  
403  
	/**
404  
	 * Scheduled executor acting as timer.
405  
	 */
406  
	private ScheduledExecutorService executor = null;
407  
408  
	/**
409  
	 * Image updater reads images from camera and force panel to be repainted.
410  
	 *
411  
	 * @author Bartosz Firyn (SarXos)
412  
	 */
413  
	private class ImageUpdater implements Runnable {
414  
		private class RepaintScheduler extends Thread {
415  
			public RepaintScheduler() {
416  
				setUncaughtExceptionHandler(WebcamExceptionHandler.getInstance());
417  
				setName(String.format("repaint-scheduler-%s", webcam.getName()));
418  
				setDaemon(true);
419  
			}
420  
421  
			@Override
422  
			public void run() {
423  
424  
				// do nothing when not running
425  
				if (!running.get() || isInIconifiedFrame(WebcamPanel2.this)) {
426  
				  _sleep(100);
427  
					return;
428  
				}
429  
430  
				repaintPanel();
431  
432  
				// loop when starting, to wait for images
433  
				while (starting) {
434  
					try {
435  
						Thread.sleep(50);
436  
					} catch (InterruptedException e) {
437  
						throw new RuntimeException(e);
438  
					}
439  
				}
440  
441  
				// schedule update when webcam is open, otherwise schedule
442  
				// second scheduler execution
443  
444  
				try {
445  
446  
					// FPS limit means that panel rendering frequency is
447  
					// limited to the specific value and panel will not be
448  
					// rendered more often then specific value
449  
450  
					if (webcam.isOpen()) {
451  
452  
						// TODO: rename FPS value in panel to rendering
453  
						// frequency
454  
455  
						if (isFPSLimited()) {
456  
							executor.scheduleAtFixedRate(updater, 0, (long) (1000 / frequency), TimeUnit.MILLISECONDS);
457  
						} else {
458  
							executor.scheduleWithFixedDelay(updater, 100, 1, TimeUnit.MILLISECONDS);
459  
						}
460  
					} else {
461  
						executor.schedule(this, 500, TimeUnit.MILLISECONDS);
462  
					}
463  
				} catch (RejectedExecutionException e) {
464  
465  
					// executor has been shut down, which means that someone
466  
					// stopped panel / webcam device before it was actually
467  
					// completely started (it was in "starting" timeframe)
468  
469  
					LOG.warn("Executor rejected paint update");
470  
					LOG.trace("Executor rejected paint update because of", e);
471  
				}
472  
			}
473  
		}
474  
475  
		/**
476  
		 * Update scheduler thread.
477  
		 */
478  
		private Thread scheduler = null;
479  
480  
		/**
481  
		 * Is repainter running?
482  
		 */
483  
		private AtomicBoolean running = new AtomicBoolean(false);
484  
485  
		/**
486  
		 * Start repainter. Can be invoked many times, but only first call will take effect.
487  
		 */
488  
		public void start() {
489  
			if (running.compareAndSet(false, true)) {
490  
				executor = Executors.newScheduledThreadPool(1, THREAD_FACTORY);
491  
				scheduler = new RepaintScheduler();
492  
				scheduler.start();
493  
			}
494  
		}
495  
496  
		/**
497  
		 * Stop repainter. Can be invoked many times, but only first call will take effect.
498  
		 *
499  
		 * @throws InterruptedException
500  
		 */
501  
		public void stop() throws InterruptedException {
502  
			if (running.compareAndSet(true, false)) {
503  
				executor.shutdown();
504  
				executor.awaitTermination(5000, TimeUnit.MILLISECONDS);
505  
				scheduler.join();
506  
			}
507  
		}
508  
509  
		@Override
510  
		public void run() {
511  
			try {
512  
				update();
513  
			} catch (Throwable t) {
514  
				errored = true;
515  
				WebcamExceptionHandler.handle(t);
516  
			}
517  
		}
518  
519  
		/**
520  
		 * Perform single panel area update (repaint newly obtained image).
521  
		 */
522  
		private void update() {
523  
524  
			// do nothing when updater not running, when webcam is closed, or
525  
			// panel repainting is paused
526  
527  
			if (!running.get() || !webcam.isOpen() || paused) {
528  
				return;
529  
			}
530  
531  
			// get new image from webcam
532  
533  
			BufferedImage tmp = supplier.get();
534  
			boolean repaint = true;
535  
536  
			if (tmp != null) {
537  
538  
				// ignore repaint if image is the same as before
539  
				if (image == tmp) {
540  
					repaint = false;
541  
				}
542  
543  
				errored = false;
544  
				image = tmp;
545  
			}
546  
547  
			if (repaint) {
548  
				repaintPanel();
549  
			}
550  
		}
551  
	}
552  
553  
	/**
554  
	 * Resource bundle.
555  
	 */
556  
	private ResourceBundle rb = null;
557  
558  
	/**
559  
	 * The mode of how the image will be resized to fit into panel bounds. Default is
560  
	 * {@link DrawMode#FIT}
561  
	 *
562  
	 * @see DrawMode
563  
	 */
564  
	private DrawMode drawMode = DrawMode.FIT;
565  
566  
	/**
567  
	 * Frames requesting frequency.
568  
	 */
569  
	private double frequency = 5; // FPS
570  
571  
	/**
572  
	 * Is frames requesting frequency limited? If true, images will be fetched in configured time
573  
	 * intervals. If false, images will be fetched as fast as camera can serve them.
574  
	 */
575  
	private boolean frequencyLimit = false;
576  
577  
	/**
578  
	 * Display FPS.
579  
	 */
580  
	private boolean frequencyDisplayed = false;
581  
582  
	/**
583  
	 * Display image size.
584  
	 */
585  
	private boolean imageSizeDisplayed = false;
586  
587  
	/**
588  
	 * Is antialiasing enabled (true by default).
589  
	 */
590  
	private boolean antialiasingEnabled = true;
591  
592  
	/**
593  
	 * Webcam object used to fetch images.
594  
	 */
595  
	private final Webcam webcam;
596  
597  
	private final ImageSupplier supplier;
598  
599  
	/**
600  
	 * Repainter is used to fetch images from camera and force panel repaint when image is ready.
601  
	 */
602  
	private final ImageUpdater updater;
603  
604  
	/**
605  
	 * Image currently being displayed.
606  
	 */
607  
	BufferedImage image = null;
608  
609  
	/**
610  
	 * Webcam is currently starting.
611  
	 */
612  
	private volatile boolean starting = false;
613  
614  
	/**
615  
	 * Painting is paused.
616  
	 */
617  
	private volatile boolean paused = false;
618  
619  
	/**
620  
	 * Is there any problem with webcam?
621  
	 */
622  
	private volatile boolean errored = false;
623  
624  
	/**
625  
	 * Webcam has been started.
626  
	 */
627  
	private final AtomicBoolean started = new AtomicBoolean(false);
628  
629  
	/**
630  
	 * Default painter.
631  
	 */
632  
	private final Painter defaultPainter = new DefaultPainter();
633  
634  
	/**
635  
	 * Painter used to draw image in panel.
636  
	 *
637  
	 * @see #setPainter(Painter)
638  
	 * @see #getPainter()
639  
	 */
640  
	private Painter painter = defaultPainter;
641  
642  
	/**
643  
	 * Preferred panel size.
644  
	 */
645  
	private Dimension defaultSize = null;
646  
647  
	/**
648  
	 * If debug info should be displayed.
649  
	 */
650  
	private boolean displayDebugInfo = false;
651  
652  
	/**
653  
	 * Is image mirrored.
654  
	 */
655  
	private boolean mirrored = false;
656  
657  
	/**
658  
	 * Creates webcam panel and automatically start webcam.
659  
	 *
660  
	 * @param webcam the webcam to be used to fetch images
661  
	 */
662  
	public WebcamPanel2(Webcam webcam) {
663  
		this(webcam, true);
664  
	}
665  
666  
	/**
667  
	 * Creates new webcam panel which display image from camera in you your Swing application.
668  
	 *
669  
	 * @param webcam the webcam to be used to fetch images
670  
	 * @param start true if webcam shall be automatically started
671  
	 */
672  
	public WebcamPanel2(Webcam webcam, boolean start) {
673  
		this(webcam, null, start);
674  
	}
675  
676  
	/**
677  
	 * Creates new webcam panel which display image from camera in you your Swing application. If
678  
	 * panel size argument is null, then image size will be used. If you would like to fill panel
679  
	 * area with image even if its size is different, then you can use
680  
	 * {@link WebcamPanel#setFillArea(boolean)} method to configure this.
681  
	 *
682  
	 * @param webcam the webcam to be used to fetch images
683  
	 * @param size the size of panel
684  
	 * @param start true if webcam shall be automatically started
685  
	 * @see WebcamPanel#setFillArea(boolean)
686  
	 */
687  
	public WebcamPanel2(Webcam webcam, Dimension size, boolean start) {
688  
		this(webcam, size, start, new DefaultImageSupplier(webcam));
689  
	}
690  
691  
	public WebcamPanel2(Webcam webcam, Dimension size, boolean start, ImageSupplier supplier) {
692  
693  
		if (webcam == null) {
694  
			throw new IllegalArgumentException(String.format("Webcam argument in %s constructor cannot be null!", getClass().getSimpleName()));
695  
		}
696  
697  
		this.defaultSize = size;
698  
		this.webcam = webcam;
699  
		this.updater = new ImageUpdater();
700  
		this.supplier = supplier;
701  
		this.rb = WebcamUtils.loadRB(WebcamPanel.class, getLocale());
702  
703  
		setDoubleBuffered(true);
704  
705  
		addPropertyChangeListener("locale", this);
706  
707  
		if (size == null) {
708  
			Dimension r = webcam.getViewSize();
709  
			if (r == null) {
710  
				r = webcam.getViewSizes()[0];
711  
			}
712  
			setPreferredSize(r);
713  
		} else {
714  
			setPreferredSize(size);
715  
		}
716  
717  
		if (start) {
718  
			start();
719  
		}
720  
	}
721  
722  
	/**
723  
	 * Set new painter. Painter is a class which pains image visible when
724  
	 *
725  
	 * @param painter the painter object to be set
726  
	 */
727  
	public void setPainter(Painter painter) {
728  
		this.painter = painter;
729  
	}
730  
731  
	/**
732  
	 * Get painter used to draw image in webcam panel.
733  
	 *
734  
	 * @return Painter object
735  
	 */
736  
	public Painter getPainter() {
737  
		return painter;
738  
	}
739  
740  
	@Override
741  
	protected void paintComponent(Graphics g) {
742  
743  
		super.paintComponent(g);
744  
745  
		if (image == null) {
746  
			painter.paintPanel(this, (Graphics2D) g);
747  
		} else {
748  
			painter.paintImage(this, image, (Graphics2D) g);
749  
		}
750  
	}
751  
752  
	/**
753  
	 * Open webcam and start rendering.
754  
	 */
755  
	public void start() {
756  
757  
		if (!started.compareAndSet(false, true)) {
758  
			return;
759  
		}
760  
761  
		webcam.addWebcamListener(this);
762  
763  
		LOG.debug("Starting panel rendering and trying to open attached webcam");
764  
765  
		updater.start();
766  
767  
		starting = true;
768  
769  
		final SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
770  
771  
			@Override
772  
			protected Void doInBackground() throws Exception {
773  
774  
				try {
775  
					if (!webcam.isOpen()) {
776  
						errored = !webcam.open();
777  
					}
778  
				} catch (WebcamException e) {
779  
					errored = true;
780  
					throw e;
781  
				} finally {
782  
					starting = false;
783  
					repaintPanel();
784  
				}
785  
786  
				return null;
787  
			}
788  
		};
789  
		worker.execute();
790  
	}
791  
792  
	/**
793  
	 * Stop rendering and close webcam.
794  
	 */
795  
	public void stop() {
796  
797  
		if (!started.compareAndSet(true, false)) {
798  
			return;
799  
		}
800  
801  
		webcam.removeWebcamListener(this);
802  
803  
		LOG.debug("Stopping panel rendering and closing attached webcam");
804  
805  
		try {
806  
			updater.stop();
807  
		} catch (InterruptedException e) {
808  
			throw new RuntimeException(e);
809  
		}
810  
811  
		image = null;
812  
813  
		final SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
814  
815  
			@Override
816  
			protected Void doInBackground() throws Exception {
817  
818  
				try {
819  
					if (webcam.isOpen()) {
820  
						errored = !webcam.close();
821  
					}
822  
				} catch (WebcamException e) {
823  
					errored = true;
824  
					throw e;
825  
				} finally {
826  
					repaintPanel();
827  
				}
828  
829  
				return null;
830  
			}
831  
		};
832  
		worker.execute();
833  
	}
834  
835  
	/**
836  
	 * Repaint panel in Swing asynchronous manner.
837  
	 */
838  
	private void repaintPanel() {
839  
		SwingUtilities.invokeLater(repaint);
840  
	}
841  
842  
	/**
843  
	 * Pause rendering.
844  
	 */
845  
	public void pause() {
846  
		if (paused) {
847  
			return;
848  
		}
849  
850  
		LOG.debug("Pausing panel rendering");
851  
852  
		paused = true;
853  
	}
854  
855  
	/**
856  
	 * Resume rendering.
857  
	 */
858  
	public void resume() {
859  
860  
		if (!paused) {
861  
			return;
862  
		}
863  
864  
		LOG.debug("Resuming panel rendering");
865  
866  
		paused = false;
867  
	}
868  
869  
	/**
870  
	 * Is frequency limit enabled?
871  
	 *
872  
	 * @return True or false
873  
	 */
874  
	public boolean isFPSLimited() {
875  
		return frequencyLimit;
876  
	}
877  
878  
	/**
879  
	 * Enable or disable frequency limit. Frequency limit should be used for <b>all IP cameras
880  
	 * working in pull mode</b> (to save number of HTTP requests). If true, images will be fetched
881  
	 * in configured time intervals. If false, images will be fetched as fast as camera can serve
882  
	 * them.
883  
	 *
884  
	 * @param frequencyLimit true if limiting the frequency of image requests
885  
	 */
886  
	public void setFPSLimited(boolean frequencyLimit) {
887  
		this.frequencyLimit = frequencyLimit;
888  
	}
889  
890  
	/**
891  
	 * Get rendering frequency in FPS (equivalent to Hz).
892  
	 *
893  
	 * @return Rendering frequency
894  
	 */
895  
	public double getFPSLimit() {
896  
		return frequency;
897  
	}
898  
899  
	/**
900  
	 * Set rendering frequency (in Hz or FPS). Minimum frequency is 0.016 (1 frame per minute) and
901  
	 * maximum is 25 (25 frames per second).
902  
	 *
903  
	 * @param fps the frequency
904  
	 */
905  
	public void setFPSLimit(double fps) {
906  
		if (fps > MAX_FREQUENCY) {
907  
			fps = MAX_FREQUENCY;
908  
		}
909  
		if (fps < MIN_FREQUENCY) {
910  
			fps = MIN_FREQUENCY;
911  
		}
912  
		this.frequency = fps;
913  
	}
914  
915  
	/**
916  
	 * Is displaying of some debug information enabled.
917  
	 *
918  
	 * @return True if debug information are enabled, false otherwise
919  
	 */
920  
	public boolean isDisplayDebugInfo() {
921  
		return displayDebugInfo;
922  
	}
923  
924  
	/**
925  
	 * Display some debug information on image surface.
926  
	 *
927  
	 * @param displayDebugInfo the value to control debug information
928  
	 */
929  
	public void setDisplayDebugInfo(boolean displayDebugInfo) {
930  
		this.displayDebugInfo = displayDebugInfo;
931  
	}
932  
933  
	/**
934  
	 * This method return true in case if camera FPS is set to be displayed on panel surface.
935  
	 * Default value returned is false.
936  
	 *
937  
	 * @return True if camera FPS is set to be displayed on panel surface
938  
	 * @see #setFPSDisplayed(boolean)
939  
	 */
940  
	public boolean isFPSDisplayed() {
941  
		return frequencyDisplayed;
942  
	}
943  
944  
	/**
945  
	 * This method is to control if camera FPS should be displayed on the webcam panel surface.
946  
	 *
947  
	 * @param displayed the value to control if camera FPS should be displayed
948  
	 */
949  
	public void setFPSDisplayed(boolean displayed) {
950  
		this.frequencyDisplayed = displayed;
951  
	}
952  
953  
	/**
954  
	 * This method will return true in case when panel is configured to display image size. The
955  
	 * string will be printed in the right bottom corner of the panel surface.
956  
	 *
957  
	 * @return True in case if panel is configured to display image size
958  
	 */
959  
	public boolean isImageSizeDisplayed() {
960  
		return imageSizeDisplayed;
961  
	}
962  
963  
	/**
964  
	 * Configure panel to display camera image size to be displayed.
965  
	 *
966  
	 * @param imageSizeDisplayed if true the pixel dimensions are displayed over the image.
967  
	 */
968  
	public void setImageSizeDisplayed(boolean imageSizeDisplayed) {
969  
		this.imageSizeDisplayed = imageSizeDisplayed;
970  
	}
971  
972  
	/**
973  
	 * Turn on/off antialiasing.
974  
	 *
975  
	 * @param antialiasing the true to enable, false to disable antialiasing
976  
	 */
977  
	public void setAntialiasingEnabled(boolean antialiasing) {
978  
		this.antialiasingEnabled = antialiasing;
979  
	}
980  
981  
	/**
982  
	 * @return True is antialiasing is enabled, false otherwise
983  
	 */
984  
	public boolean isAntialiasingEnabled() {
985  
		return antialiasingEnabled;
986  
	}
987  
988  
	/**
989  
	 * Is webcam panel repainting starting.
990  
	 *
991  
	 * @return True if panel is starting
992  
	 */
993  
	public boolean isStarting() {
994  
		return starting;
995  
	}
996  
997  
	/**
998  
	 * Is webcam panel repainting started.
999  
	 *
1000  
	 * @return True if panel repainting has been started
1001  
	 */
1002  
	public boolean isStarted() {
1003  
		return started.get();
1004  
	}
1005  
1006  
	/**
1007  
	 * This method returns the current draw mode, mainly used by custom painters
1008  
	 * 
1009  
	 * @return the current value of the {@link DrawMode}
1010  
	 */
1011  
	public DrawMode getDrawMode() {
1012  
		return this.drawMode;
1013  
	}
1014  
1015  
	/**
1016  
	 * This method sets the drawmode
1017  
	 * 
1018  
	 * @param drawMode the desired {@link DrawMode}
1019  
	 */
1020  
	public void setDrawMode(DrawMode drawMode) {
1021  
		this.drawMode = drawMode;
1022  
	}
1023  
1024  
	/**
1025  
	 * Indicates whether the panel is in an error state
1026  
	 * 
1027  
	 * @return true if the panel has an error present
1028  
	 */
1029  
	public boolean isErrored() {
1030  
		return errored;
1031  
	}
1032  
1033  
	/**
1034  
	 * Hints for rendering, mainly used for custom painters
1035  
	 * 
1036  
	 * @return the stored RenderingHints
1037  
	 * @deprecated use {@link #getDrawMode()} instead.
1038  
	 */
1039  
	@Deprecated
1040  
	public Map<RenderingHints.Key, Object> getImageRenderingHints() {
1041  
		return imageRenderingHints;
1042  
	}
1043  
1044  
	@Deprecated
1045  
	public boolean isFitArea() {
1046  
		return drawMode == DrawMode.FIT;
1047  
	}
1048  
1049  
	/**
1050  
	 * This method will change the mode of panel area painting so the image will be resized and will
1051  
	 * keep scale factor to fit into drawable panel bounds. When set to false, the mode will be
1052  
	 * reset to {@link DrawMode#NONE} so image will be drawn as it is.
1053  
	 *
1054  
	 * @param fitArea the fit area mode enabled or disabled
1055  
	 * @deprecated use {@link #setDrawMode(DrawMode drawMode)} instead.
1056  
	 */
1057  
	@Deprecated
1058  
	public void setFitArea(boolean fitArea) {
1059  
		this.drawMode = fitArea ? DrawMode.FIT : DrawMode.NONE;
1060  
	}
1061  
1062  
	/**
1063  
	 * Image will be resized to fill panel area if true. If false then image will be rendered as it
1064  
	 * was obtained from webcam instance.
1065  
	 *
1066  
	 * @param fillArea shall image be resided to fill panel area
1067  
	 * @deprecated use {@link #setDrawMode(DrawMode drawMode)} instead.
1068  
	 */
1069  
	@Deprecated
1070  
	public void setFillArea(boolean fillArea) {
1071  
		this.drawMode = fillArea ? DrawMode.FILL : DrawMode.NONE;
1072  
	}
1073  
1074  
	/**
1075  
	 * Get value of fill area setting. Image will be resized to fill panel area if true. If false
1076  
	 * then image will be rendered as it was obtained from webcam instance.
1077  
	 *
1078  
	 * @return True if image is being resized, false otherwise
1079  
	 * @deprecated use {@link #getDrawMode()} instead.
1080  
	 */
1081  
	@Deprecated
1082  
	public boolean isFillArea() {
1083  
		return drawMode == DrawMode.FILL;
1084  
	}
1085  
1086  
	/**
1087  
	 * Get default painter used to draw panel.
1088  
	 *
1089  
	 * @return Default painter
1090  
	 */
1091  
	public Painter getDefaultPainter() {
1092  
		return defaultPainter;
1093  
	}
1094  
1095  
	@Override
1096  
	public void propertyChange(PropertyChangeEvent evt) {
1097  
		Locale lc = (Locale) evt.getNewValue();
1098  
		if (lc != null) {
1099  
			rb = WebcamUtils.loadRB(WebcamPanel.class, lc);
1100  
		}
1101  
	}
1102  
1103  
	@Override
1104  
	public void webcamOpen(WebcamEvent we) {
1105  
1106  
		// if default size has not been provided, then use the one from webcam
1107  
		// device (this will be current webcam resolution)
1108  
1109  
		if (defaultSize == null) {
1110  
			setPreferredSize(webcam.getViewSize());
1111  
		}
1112  
	}
1113  
1114  
	@Override
1115  
	public void webcamClosed(WebcamEvent we) {
1116  
		stop();
1117  
	}
1118  
1119  
	@Override
1120  
	public void webcamDisposed(WebcamEvent we) {
1121  
		stop();
1122  
	}
1123  
1124  
	@Override
1125  
	public void webcamImageObtained(WebcamEvent we) {
1126  
		// do nothing
1127  
	}
1128  
1129  
	/**
1130  
	 * This method returns true if image mirroring is enabled. The default value is false.
1131  
	 *
1132  
	 * @return True if image is mirrored, false otherwise
1133  
	 */
1134  
	public boolean isMirrored() {
1135  
		return mirrored;
1136  
	}
1137  
1138  
	/**
1139  
	 * Decide whether or not the image from webcam painted on panel surface will be mirrored. The
1140  
	 * image from camera itself is not modified.
1141  
	 *
1142  
	 * @param mirrored the parameter to control if image should be mirrored
1143  
	 */
1144  
	public void setMirrored(boolean mirrored) {
1145  
		this.mirrored = mirrored;
1146  
	}
1147  
1148  
	/**
1149  
	 * Return {@link Webcam} used by this panel.
1150  
	 * 
1151  
	 * @return {@link Webcam}
1152  
	 */
1153  
	public Webcam getWebcam() {
1154  
		return webcam;
1155  
	}
1156  
1157  
	/**
1158  
	 * @return {@link BufferedImage} displayed on {@link WebcamPanel}
1159  
	 */
1160  
	public BufferedImage getImage() {
1161  
		return image;
1162  
	}
1163  
}
1164  
1165  
static WebcamPanel2 panel;
1166  
static bool savingOn = true;
1167  
static double saveEvery = 10.0;
1168  
static volatile File latestSaved;
1169  
1170  
p {
1171  
  restartWith128MBHeap();
1172  
  outBuf(50000);
1173  
  substance();
1174  
  selectWebCam(voidfunc(Webcam cam) {
1175  
    panel = new WebcamPanel2(cam, true);
1176  
    panel.setFPSDisplayed(true);
1177  
    frameIcon(#1009177, exitProgramOnFrameClose(alwaysOnTop(showPackedFrame("JavaX Live WebCam", panel)));
1178  
    bot("WebCam.");
1179  
    doEvery_daemon_now(saveEvery, f saveDefault);
1180  
  });
1181  
  hideConsole();
1182  
}
1183  
1184  
answer {
1185  
  if "save jpeg at *" {
1186  
    saveJPEG(newFile($1), imageFromWebcamPanel(panel));
1187  
    ret "OK";
1188  
  }
1189  
  if "latest file"
1190  
    ret latestSaved == null ? "Not saved yet"
1191  
      : "OK " + quote(f2s(latestSaved));
1192  
}
1193  
1194  
svoid saveDefault {
1195  
  if (!savingOn) ret;
1196  
  File file = newFile(javaxDataDir(), "WebCam", ("webcam-" + dateWithSecondsForFile() + ".jpg");
1197  
  saveJPEG(file, imageFromWebcamPanel(panel));
1198  
  latestSaved = file;
1199  
}

Author comment

Began life as a copy of #1013489

download  show line numbers  debug dex  old transpilations   

Travelled to 13 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt

No comments. add comment

Snippet ID: #1014901
Snippet name: JavaX Live WebCam - Show live webcam image in frame v5 [try to minimize CPU when iconified - program works, but doesn't make a difference to vanilla WebcamPanel]
Eternal ID of this version: #1014901/8
Text MD5: 7750d67fc344e1dcaecf6d54d46f14bb
Transpilation MD5: 6c38f054e53b86af88e25be20646b691
Author: stefan
Category: javax / desktop / camera
Type: JavaX source code (desktop)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2018-05-06 11:38:19
Source code size: 29723 bytes / 1199 lines
Pitched / IR pitched: No / No
Views / Downloads: 297 / 780
Version history: 7 change(s)
Referenced in: [show references]