Compare commits
1 Commits
40a6183529
...
98ff3b9b76
| Author | SHA1 | Date | |
|---|---|---|---|
| 98ff3b9b76 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -45,4 +45,7 @@ dependency-reduced-pom.xml
|
||||
.idea
|
||||
|
||||
## This is for our app, cause it likes to store stuff ##
|
||||
network_cameras.json
|
||||
network_cameras.json
|
||||
|
||||
## exec launch4j config ##
|
||||
execfg.xml
|
||||
@@ -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