From 98ff3b9b769646af31357acf8720356d6a34b457 Mon Sep 17 00:00:00 2001 From: rattatwinko Date: Fri, 23 Jan 2026 19:18:37 +0100 Subject: [PATCH] zooming in CameraPanel.java with new methods and more efficient rendering! --- .gitignore | 5 +- .../java/io/swtc/proccessing/CameraPanel.java | 179 ++++++++++++++++-- 2 files changed, 163 insertions(+), 21 deletions(-) diff --git a/.gitignore b/.gitignore index 7568db7..d1c36b7 100644 --- a/.gitignore +++ b/.gitignore @@ -45,4 +45,7 @@ dependency-reduced-pom.xml .idea ## This is for our app, cause it likes to store stuff ## -network_cameras.json \ No newline at end of file +network_cameras.json + +## exec launch4j config ## +execfg.xml \ No newline at end of file diff --git a/src/main/java/io/swtc/proccessing/CameraPanel.java b/src/main/java/io/swtc/proccessing/CameraPanel.java index e27851b..1657e8e 100644 --- a/src/main/java/io/swtc/proccessing/CameraPanel.java +++ b/src/main/java/io/swtc/proccessing/CameraPanel.java @@ -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 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 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 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(); + } +} \ No newline at end of file