2 Commits

3 changed files with 226 additions and 22 deletions

3
.gitignore vendored
View File

@@ -46,3 +46,6 @@ dependency-reduced-pom.xml
## 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

View File

@@ -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) {

View File

@@ -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();
}
} }