jfjoch_viewer: Add context menu to images to allow copy/clear ROI/fit to view
This commit is contained in:
@@ -8,6 +8,13 @@
|
||||
#include <QWheelEvent>
|
||||
#include <QMouseEvent>
|
||||
#include <QTimer>
|
||||
#include <QMenu>
|
||||
#include <QContextMenuEvent>
|
||||
#include <QClipboard>
|
||||
#include <QGuiApplication>
|
||||
#include <QMimeData>
|
||||
#include <QBuffer>
|
||||
#include <QPainter>
|
||||
|
||||
JFJochImage::JFJochImage(QWidget *parent) : QGraphicsView(parent) {
|
||||
setDragMode(QGraphicsView::NoDrag); // Disable default drag mode
|
||||
@@ -265,6 +272,81 @@ void JFJochImage::mouseReleaseEvent(QMouseEvent *event) {
|
||||
|
||||
}
|
||||
|
||||
void JFJochImage::contextMenuEvent(QContextMenuEvent *event) {
|
||||
QMenu menu(this);
|
||||
|
||||
QAction *copyImageAct = menu.addAction(tr("Copy image"));
|
||||
QAction *copyWithOverlayAct = menu.addAction(tr("Copy image with overlay"));
|
||||
menu.addSeparator();
|
||||
QAction *fitAct = menu.addAction(tr("Fit image to view"));
|
||||
QAction *clearRoiAct = menu.addAction(tr("Clear ROI"));
|
||||
|
||||
const bool hasImage = (W > 0 && H > 0 && !pixmap.isNull());
|
||||
copyImageAct->setEnabled(hasImage);
|
||||
copyWithOverlayAct->setEnabled(hasImage && scene());
|
||||
|
||||
QAction *chosen = menu.exec(event->globalPos());
|
||||
if (!chosen) return;
|
||||
|
||||
if (chosen == copyImageAct) {
|
||||
copyImageToClipboard();
|
||||
} else if (chosen == copyWithOverlayAct) {
|
||||
copyImageWithOverlayToClipboard();
|
||||
} else if (chosen == fitAct) {
|
||||
fitToView();
|
||||
} else if (chosen == clearRoiAct) {
|
||||
clearROIInternal();
|
||||
}
|
||||
}
|
||||
|
||||
static void setClipboardAsJpegAndImage(const QImage &img, int quality = 95) {
|
||||
// Provide both "image/jpeg" and generic image flavors for better compatibility
|
||||
QByteArray ba;
|
||||
ba.reserve(img.width() * img.height() * 3 / 2);
|
||||
QBuffer buf(&ba);
|
||||
buf.open(QIODevice::WriteOnly);
|
||||
img.convertToFormat(QImage::Format_ARGB32); // ensure a known format for encoding
|
||||
img.save(&buf, "JPEG", quality);
|
||||
|
||||
auto *mime = new QMimeData();
|
||||
mime->setData("image/jpeg", ba);
|
||||
mime->setImageData(img); // also set as generic bitmap
|
||||
QGuiApplication::clipboard()->setMimeData(mime);
|
||||
}
|
||||
|
||||
void JFJochImage::copyImageToClipboard() {
|
||||
if (W == 0 || H == 0 || pixmap.isNull()) return;
|
||||
|
||||
// Use the underlying rendered image (no overlay)
|
||||
QImage img = pixmap.toImage();
|
||||
setClipboardAsJpegAndImage(img, 95);
|
||||
emit writeStatusBar(tr("Image copied to clipboard"), 2000);
|
||||
}
|
||||
|
||||
void JFJochImage::copyImageWithOverlayToClipboard() {
|
||||
if (W == 0 || H == 0 || !scene()) return;
|
||||
|
||||
// Render the entire scene (image + overlay) at native image resolution
|
||||
QImage img(int(W), int(H), QImage::Format_ARGB32_Premultiplied);
|
||||
img.fill(Qt::transparent);
|
||||
QPainter p(&img);
|
||||
// Ensure we render the same logical rect as the scene/image coordinates
|
||||
const QRectF sourceRect(0, 0, qreal(W), qreal(H));
|
||||
scene()->render(&p, QRectF(0, 0, qreal(W), qreal(H)), sourceRect);
|
||||
p.end();
|
||||
|
||||
setClipboardAsJpegAndImage(img, 95);
|
||||
emit writeStatusBar(tr("Image with overlay copied to clipboard"), 2000);
|
||||
}
|
||||
|
||||
void JFJochImage::clearROIInternal() {
|
||||
roiBox = QRectF(); // clear any ROI
|
||||
// Keep current roi_type; ROI simply becomes empty
|
||||
CalcROI(); // will emit a zeroed ROI message
|
||||
updateOverlay();
|
||||
emit writeStatusBar(tr("ROI cleared"), 1500);
|
||||
}
|
||||
|
||||
JFJochImage::ResizeHandle
|
||||
JFJochImage::hitTestROIHandle(const QPointF& scenePos, qreal tol) const {
|
||||
if (roiBox.isNull() || roiBox.width() <= 0 || roiBox.height() <= 0)
|
||||
|
||||
@@ -19,6 +19,7 @@ class JFJochImage : public QGraphicsView {
|
||||
void writePixelLabels();
|
||||
void wheelEvent(QWheelEvent* event) override;
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
void contextMenuEvent(QContextMenuEvent *event) override;
|
||||
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
@@ -76,6 +77,10 @@ protected:
|
||||
// Perform initial fit-to-view (shorter direction), once per image size
|
||||
void fitToViewShorterSideOnce();
|
||||
QSize last_fit_viewport_ = {};
|
||||
|
||||
void copyImageToClipboard();
|
||||
void copyImageWithOverlayToClipboard();
|
||||
void clearROIInternal();
|
||||
signals:
|
||||
void foregroundChanged(float v);
|
||||
void backgroundChanged(float v);
|
||||
|
||||
Reference in New Issue
Block a user