Compare commits
2 Commits
40a6183529
...
c0aa3421a4
| Author | SHA1 | Date | |
|---|---|---|---|
| c0aa3421a4 | |||
| 98ff3b9b76 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -46,3 +46,6 @@ dependency-reduced-pom.xml
|
||||
|
||||
## This is for our app, cause it likes to store stuff ##
|
||||
network_cameras.json
|
||||
|
||||
## exec launch4j config ##
|
||||
execfg.xml
|
||||
@@ -2,7 +2,7 @@ package io.swtc;
|
||||
|
||||
import com.github.sarxos.webcam.Webcam;
|
||||
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 java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
@@ -10,6 +10,7 @@ import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class SwingIFrame {
|
||||
private final JFrame mainFrame;
|
||||
@@ -109,7 +110,14 @@ public class SwingIFrame {
|
||||
popupMenu.removeAll(); // clean slate
|
||||
|
||||
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());
|
||||
mmfullscreenItem.addActionListener(e -> toggleMMFullscreen());
|
||||
backgroundcolor.addActionListener(e -> toggleBackground());
|
||||
colorpicker.addActionListener(e -> chooseBgColor());
|
||||
|
||||
popupMenu.addPopupMenuListener(new javax.swing.event.PopupMenuListener() {
|
||||
@Override
|
||||
@@ -121,6 +129,22 @@ public class SwingIFrame {
|
||||
});
|
||||
|
||||
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() {
|
||||
@@ -137,6 +161,7 @@ public class SwingIFrame {
|
||||
|
||||
private void setupFullscreenToggle() {
|
||||
JRootPane root = mainFrame.getRootPane();
|
||||
// One Monitor FS
|
||||
root.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
|
||||
.put(KeyStroke.getKeyStroke("F11"), "toggleFullscreen");
|
||||
root.getActionMap().put("toggleFullscreen", new AbstractAction() {
|
||||
@@ -145,6 +170,16 @@ public class SwingIFrame {
|
||||
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() {
|
||||
@@ -153,6 +188,33 @@ public class SwingIFrame {
|
||||
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 */
|
||||
private void toggleFullscreen() {
|
||||
if (!fullscreen) {
|
||||
|
||||
@@ -1,30 +1,106 @@
|
||||
package io.swtc.proccessing;
|
||||
|
||||
import io.swtc.proccessing.ui.ShowError;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Enhanced CameraPanel with support for custom image processors
|
||||
*/
|
||||
public class CameraPanel extends JPanel {
|
||||
|
||||
private volatile BufferedImage sourceImage;
|
||||
private volatile BufferedImage processedImage;
|
||||
|
||||
private Function<BufferedImage, BufferedImage> imageProcessor;
|
||||
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() {
|
||||
setBackground(Color.BLACK);
|
||||
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) {
|
||||
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)) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
repaintScheduled.set(false);
|
||||
@@ -33,37 +109,100 @@ public class CameraPanel extends JPanel {
|
||||
}
|
||||
}
|
||||
|
||||
public void setImageProcessor(Function<BufferedImage, BufferedImage> processor) {
|
||||
this.imageProcessor = processor;
|
||||
private void handleZoom(MouseWheelEvent e) {
|
||||
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
|
||||
protected void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
|
||||
BufferedImage src = sourceImage;
|
||||
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;
|
||||
if (processedImage == null) return;
|
||||
|
||||
Graphics2D g2d = (Graphics2D) g;
|
||||
|
||||
AffineTransform originalTransform = g2d.getTransform();
|
||||
|
||||
g2d.setRenderingHint(
|
||||
RenderingHints.KEY_INTERPOLATION,
|
||||
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() {
|
||||
return processedImage;
|
||||
}
|
||||
|
||||
public void resetView() {
|
||||
zoomLevel = 1.0;
|
||||
xOffset = 0;
|
||||
yOffset = 0;
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user