Compare commits
2 Commits
40a6183529
...
c0aa3421a4
| Author | SHA1 | Date | |
|---|---|---|---|
| c0aa3421a4 | |||
| 98ff3b9b76 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -45,4 +45,7 @@ dependency-reduced-pom.xml
|
|||||||
.idea
|
.idea
|
||||||
|
|
||||||
## This is for our app, cause it likes to store stuff ##
|
## This is for our app, cause it likes to store stuff ##
|
||||||
network_cameras.json
|
network_cameras.json
|
||||||
|
|
||||||
|
## exec launch4j config ##
|
||||||
|
execfg.xml
|
||||||
@@ -2,7 +2,7 @@ package io.swtc;
|
|||||||
|
|
||||||
import com.github.sarxos.webcam.Webcam;
|
import com.github.sarxos.webcam.Webcam;
|
||||||
import io.swtc.proccessing.ui.IconSetter;
|
import io.swtc.proccessing.ui.IconSetter;
|
||||||
import io.swtc.proccessing.ui.iframe.*; // Your custom frames
|
import io.swtc.proccessing.ui.iframe.*;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
@@ -10,6 +10,7 @@ import java.awt.event.MouseAdapter;
|
|||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
public class SwingIFrame {
|
public class SwingIFrame {
|
||||||
private final JFrame mainFrame;
|
private final JFrame mainFrame;
|
||||||
@@ -109,7 +110,14 @@ public class SwingIFrame {
|
|||||||
popupMenu.removeAll(); // clean slate
|
popupMenu.removeAll(); // clean slate
|
||||||
|
|
||||||
JCheckBoxMenuItem fullscreenItem = new JCheckBoxMenuItem("Fullscreen");
|
JCheckBoxMenuItem fullscreenItem = new JCheckBoxMenuItem("Fullscreen");
|
||||||
|
JCheckBoxMenuItem mmfullscreenItem = new JCheckBoxMenuItem("Multi Monitor Fullscreen");
|
||||||
|
JCheckBoxMenuItem backgroundcolor = new JCheckBoxMenuItem("Calmer Background");
|
||||||
|
JMenuItem colorpicker = new JMenuItem("Set background color");
|
||||||
|
|
||||||
fullscreenItem.addActionListener(e -> toggleFullscreen());
|
fullscreenItem.addActionListener(e -> toggleFullscreen());
|
||||||
|
mmfullscreenItem.addActionListener(e -> toggleMMFullscreen());
|
||||||
|
backgroundcolor.addActionListener(e -> toggleBackground());
|
||||||
|
colorpicker.addActionListener(e -> chooseBgColor());
|
||||||
|
|
||||||
popupMenu.addPopupMenuListener(new javax.swing.event.PopupMenuListener() {
|
popupMenu.addPopupMenuListener(new javax.swing.event.PopupMenuListener() {
|
||||||
@Override
|
@Override
|
||||||
@@ -121,6 +129,22 @@ public class SwingIFrame {
|
|||||||
});
|
});
|
||||||
|
|
||||||
popupMenu.add(fullscreenItem);
|
popupMenu.add(fullscreenItem);
|
||||||
|
popupMenu.add(mmfullscreenItem);
|
||||||
|
popupMenu.add(backgroundcolor);
|
||||||
|
popupMenu.add(colorpicker);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void chooseBgColor() {
|
||||||
|
Color selected = JColorChooser.showDialog(
|
||||||
|
mainFrame,
|
||||||
|
"Select Background Color",
|
||||||
|
desktopPane.getBackground()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!Objects.isNull(selected)) {
|
||||||
|
desktopPane.setBackground(selected);
|
||||||
|
desktopPane.repaint();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupBlackBg() {
|
private void setupBlackBg() {
|
||||||
@@ -137,6 +161,7 @@ public class SwingIFrame {
|
|||||||
|
|
||||||
private void setupFullscreenToggle() {
|
private void setupFullscreenToggle() {
|
||||||
JRootPane root = mainFrame.getRootPane();
|
JRootPane root = mainFrame.getRootPane();
|
||||||
|
// One Monitor FS
|
||||||
root.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
|
root.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
|
||||||
.put(KeyStroke.getKeyStroke("F11"), "toggleFullscreen");
|
.put(KeyStroke.getKeyStroke("F11"), "toggleFullscreen");
|
||||||
root.getActionMap().put("toggleFullscreen", new AbstractAction() {
|
root.getActionMap().put("toggleFullscreen", new AbstractAction() {
|
||||||
@@ -145,6 +170,16 @@ public class SwingIFrame {
|
|||||||
toggleFullscreen();
|
toggleFullscreen();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Multi Monitor FS
|
||||||
|
root.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
|
||||||
|
.put(KeyStroke.getKeyStroke("F12"), "toggleMMFullscreen");
|
||||||
|
root.getActionMap().put("toggleMMFullscreen", new AbstractAction() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
toggleMMFullscreen();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void toggleBackground() {
|
private void toggleBackground() {
|
||||||
@@ -153,6 +188,33 @@ public class SwingIFrame {
|
|||||||
desktopPane.repaint();
|
desktopPane.repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void toggleMMFullscreen() {
|
||||||
|
if (!fullscreen) {
|
||||||
|
windowedBounds = mainFrame.getBounds();
|
||||||
|
|
||||||
|
Rectangle virtualBounds = new Rectangle();
|
||||||
|
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||||
|
GraphicsDevice[] gs = ge.getScreenDevices();
|
||||||
|
|
||||||
|
for (GraphicsDevice gd : gs) {
|
||||||
|
GraphicsConfiguration[] gc = gd.getConfigurations();
|
||||||
|
for (GraphicsConfiguration configuration : gc) {
|
||||||
|
virtualBounds = virtualBounds.union(configuration.getBounds());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mainFrame.dispose();
|
||||||
|
mainFrame.setUndecorated(true);
|
||||||
|
|
||||||
|
mainFrame.setBounds(virtualBounds);
|
||||||
|
mainFrame.setVisible(true);
|
||||||
|
|
||||||
|
fullscreen = true;
|
||||||
|
} else {
|
||||||
|
toggleFullscreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Toggle fullscreen mode */
|
/** Toggle fullscreen mode */
|
||||||
private void toggleFullscreen() {
|
private void toggleFullscreen() {
|
||||||
if (!fullscreen) {
|
if (!fullscreen) {
|
||||||
|
|||||||
@@ -1,30 +1,106 @@
|
|||||||
package io.swtc.proccessing;
|
package io.swtc.proccessing;
|
||||||
|
|
||||||
|
import io.swtc.proccessing.ui.ShowError;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
import java.awt.event.*;
|
||||||
|
import java.awt.geom.AffineTransform;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
|
||||||
* Enhanced CameraPanel with support for custom image processors
|
|
||||||
*/
|
|
||||||
public class CameraPanel extends JPanel {
|
public class CameraPanel extends JPanel {
|
||||||
|
|
||||||
private volatile BufferedImage sourceImage;
|
private volatile BufferedImage sourceImage;
|
||||||
private volatile BufferedImage processedImage;
|
private volatile BufferedImage processedImage;
|
||||||
|
|
||||||
private Function<BufferedImage, BufferedImage> imageProcessor;
|
private Function<BufferedImage, BufferedImage> imageProcessor;
|
||||||
private final AtomicBoolean repaintScheduled = new AtomicBoolean(false);
|
private final AtomicBoolean repaintScheduled = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
private double zoomLevel = 1.0;
|
||||||
|
private double xOffset = 0;
|
||||||
|
private double yOffset = 0;
|
||||||
|
private Point dragStartPoint;
|
||||||
|
|
||||||
|
private static final double MIN_ZOOM = 1.0;
|
||||||
|
private static final double MAX_ZOOM = 10.0; // ten is enough if ur using 640x480
|
||||||
|
private static final double ZOOM_MULTIPLIER = 1.1;
|
||||||
|
|
||||||
public CameraPanel() {
|
public CameraPanel() {
|
||||||
setBackground(Color.BLACK);
|
setBackground(Color.BLACK);
|
||||||
setPreferredSize(new Dimension(640, 480));
|
setPreferredSize(new Dimension(640, 480));
|
||||||
|
|
||||||
|
initInteractionListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initInteractionListeners() {
|
||||||
|
MouseAdapter mouseHandler = new MouseAdapter() {
|
||||||
|
@Override
|
||||||
|
public void mouseWheelMoved(MouseWheelEvent e) {
|
||||||
|
handleZoom(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mousePressed(MouseEvent e) {
|
||||||
|
dragStartPoint = e.getPoint();
|
||||||
|
setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseClicked(MouseEvent e) {
|
||||||
|
if (e.getClickCount() == 2)
|
||||||
|
resetView();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseReleased(MouseEvent e) { setCursor(Cursor.getDefaultCursor()); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseDragged(MouseEvent e) {
|
||||||
|
handlePan(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseExited(MouseEvent e) { setCursor(Cursor.getDefaultCursor()); }
|
||||||
|
};
|
||||||
|
|
||||||
|
addMouseWheelListener(mouseHandler);
|
||||||
|
addMouseListener(mouseHandler);
|
||||||
|
addMouseMotionListener(mouseHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setImage(BufferedImage img) {
|
public void setImage(BufferedImage img) {
|
||||||
sourceImage = img;
|
sourceImage = img;
|
||||||
|
updateProcessedImage();
|
||||||
|
|
||||||
|
scheduleRepaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setImageProcessor(Function<BufferedImage, BufferedImage> processor) {
|
||||||
|
this.imageProcessor = processor;
|
||||||
|
if (sourceImage != null) {
|
||||||
|
updateProcessedImage();
|
||||||
|
scheduleRepaint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateProcessedImage() {
|
||||||
|
if (sourceImage == null) return;
|
||||||
|
|
||||||
|
if (imageProcessor != null) {
|
||||||
|
try {
|
||||||
|
processedImage = imageProcessor.apply(sourceImage);
|
||||||
|
} catch (Exception e) {
|
||||||
|
ShowError.error(null,"Fucked up in rendering \n" + Arrays.toString(e.getStackTrace()),"Problem");
|
||||||
|
processedImage = sourceImage; // Fallback
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
processedImage = sourceImage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scheduleRepaint() {
|
||||||
if (repaintScheduled.compareAndSet(false, true)) {
|
if (repaintScheduled.compareAndSet(false, true)) {
|
||||||
SwingUtilities.invokeLater(() -> {
|
SwingUtilities.invokeLater(() -> {
|
||||||
repaintScheduled.set(false);
|
repaintScheduled.set(false);
|
||||||
@@ -33,37 +109,100 @@ public class CameraPanel extends JPanel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setImageProcessor(Function<BufferedImage, BufferedImage> processor) {
|
private void handleZoom(MouseWheelEvent e) {
|
||||||
this.imageProcessor = processor;
|
if (processedImage == null) return;
|
||||||
|
|
||||||
|
double oldZoom = zoomLevel;
|
||||||
|
|
||||||
|
if (e.getWheelRotation() < 0) {
|
||||||
|
zoomLevel *= ZOOM_MULTIPLIER; // Zoom In
|
||||||
|
} else {
|
||||||
|
zoomLevel /= ZOOM_MULTIPLIER; // Zoom Out
|
||||||
|
}
|
||||||
|
|
||||||
|
// clamp shit
|
||||||
|
zoomLevel = Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, zoomLevel));
|
||||||
|
|
||||||
|
if (oldZoom != zoomLevel) {
|
||||||
|
double xRel = e.getX() - xOffset;
|
||||||
|
double yRel = e.getY() - yOffset;
|
||||||
|
|
||||||
|
double zoomFactor = zoomLevel / oldZoom;
|
||||||
|
|
||||||
|
xOffset = e.getX() - (xRel * zoomFactor);
|
||||||
|
yOffset = e.getY() - (yRel * zoomFactor);
|
||||||
|
|
||||||
|
checkBounds();
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handlePan(MouseEvent e) {
|
||||||
|
if (processedImage == null || dragStartPoint == null) return;
|
||||||
|
|
||||||
|
// Calculate delta
|
||||||
|
int dx = e.getX() - dragStartPoint.x;
|
||||||
|
int dy = e.getY() - dragStartPoint.y;
|
||||||
|
|
||||||
|
xOffset += dx;
|
||||||
|
yOffset += dy;
|
||||||
|
|
||||||
|
dragStartPoint = e.getPoint();
|
||||||
|
|
||||||
|
checkBounds();
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkBounds() {
|
||||||
|
double viewedWidth = getWidth() * zoomLevel;
|
||||||
|
double viewedHeight = getHeight() * zoomLevel;
|
||||||
|
|
||||||
|
if (xOffset > 0) xOffset = 0;
|
||||||
|
if (yOffset > 0) yOffset = 0;
|
||||||
|
|
||||||
|
if (xOffset + viewedWidth < getWidth()) {
|
||||||
|
xOffset = getWidth() - viewedWidth;
|
||||||
|
}
|
||||||
|
if (yOffset + viewedHeight < getHeight()) {
|
||||||
|
yOffset = getHeight() - viewedHeight;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintComponent(Graphics g) {
|
protected void paintComponent(Graphics g) {
|
||||||
super.paintComponent(g);
|
super.paintComponent(g);
|
||||||
|
|
||||||
BufferedImage src = sourceImage;
|
if (processedImage == null) return;
|
||||||
if (src == null) return;
|
|
||||||
|
|
||||||
BufferedImage img = src;
|
|
||||||
|
|
||||||
if (imageProcessor != null) {
|
|
||||||
// we only apply the proccessor if it is present
|
|
||||||
// that is due too CPU Usage ; This project was built for a DUAL Core CPU, not a quad or even 6 Core CPU
|
|
||||||
img = imageProcessor.apply(src);
|
|
||||||
}
|
|
||||||
|
|
||||||
processedImage = img;
|
|
||||||
|
|
||||||
Graphics2D g2d = (Graphics2D) g;
|
Graphics2D g2d = (Graphics2D) g;
|
||||||
|
|
||||||
|
AffineTransform originalTransform = g2d.getTransform();
|
||||||
|
|
||||||
g2d.setRenderingHint(
|
g2d.setRenderingHint(
|
||||||
RenderingHints.KEY_INTERPOLATION,
|
RenderingHints.KEY_INTERPOLATION,
|
||||||
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR
|
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR
|
||||||
);
|
);
|
||||||
|
|
||||||
g2d.drawImage(img, 0, 0, getWidth(), getHeight(), null);
|
g2d.translate(xOffset, yOffset);
|
||||||
|
|
||||||
|
double scaleX = (double) getWidth() / processedImage.getWidth();
|
||||||
|
double scaleY = (double) getHeight() / processedImage.getHeight();
|
||||||
|
|
||||||
|
g2d.scale(scaleX * zoomLevel, scaleY * zoomLevel);
|
||||||
|
|
||||||
|
g2d.drawImage(processedImage, 0, 0, null);
|
||||||
|
|
||||||
|
g2d.setTransform(originalTransform);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BufferedImage getCurrentProcessedImage() {
|
public BufferedImage getCurrentProcessedImage() {
|
||||||
return processedImage;
|
return processedImage;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public void resetView() {
|
||||||
|
zoomLevel = 1.0;
|
||||||
|
xOffset = 0;
|
||||||
|
yOffset = 0;
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user