qtdoc/examples/demos/documentviewer/plugins/imageviewer/imageviewer.cpp

208 lines
5.9 KiB
C++

// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "imageviewer.h"
#include <QFileDialog>
#include <QLabel>
#include <QMainWindow>
#include <QToolBar>
#include <QColorSpace>
#include <QGuiApplication>
#include <QIcon>
#include <QImageReader>
#include <QKeySequence>
#include <QPainter>
#include <QPixmap>
#include <QScreen>
#include <QDir>
#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT
# include <QPrinter>
#endif
using namespace Qt::StringLiterals;
static QStringList imageFormats()
{
QStringList result;
const QByteArrayList &allFormats = QImageReader::supportedImageFormats();
for (const auto &format : allFormats) {
if (format != "tif" && format != "cur") // duplicate/non-existent
result.append("image/"_L1 + QLatin1StringView(format));
}
return result;
}
static QString msgOpen(const QString &name, const QImage &image)
{
const QString description = image.colorSpace().isValid()
? image.colorSpace().description() : ImageViewer::tr("unknown");
return ImageViewer::tr("Opened \"%1\", %2x%3, Depth: %4 (%5)")
.arg(QDir::toNativeSeparators(name))
.arg(image.width()).arg(image.height())
.arg(image.depth()).arg(description);
}
//! [init]
ImageViewer::ImageViewer() : m_formats(imageFormats())
{
connect(this, &AbstractViewer::uiInitialized, this, &ImageViewer::setupImageUi);
QImageReader::setAllocationLimit(1024); // MB
}
//! [init]
ImageViewer::~ImageViewer() = default;
void ImageViewer::init(QFile *file, QWidget *parent, QMainWindow *mainWindow)
{
m_imageLabel = new QLabel(parent);
m_imageLabel->setFrameShape(QFrame::Box);
m_imageLabel->setAlignment(Qt::AlignCenter);
m_imageLabel->setScaledContents(true);
AbstractViewer::init(file, m_imageLabel, mainWindow);
m_toolBar = addToolBar(tr("Images"));
m_zoomInAct = m_toolBar->addAction(tr("Zoom &In"), this, &ImageViewer::zoomIn);
m_zoomInAct->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::ZoomIn));
m_zoomInAct->setShortcut(QKeySequence::ZoomIn);
m_zoomOutAct = m_toolBar->addAction(tr("Zoom &Out"), this, &ImageViewer::zoomOut);
m_zoomOutAct->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::ZoomOut));
m_zoomOutAct->setShortcut(QKeySequence::ZoomOut);
m_resetZoomAct = m_toolBar->addAction(tr("Reset Zoom"), this, &ImageViewer::resetZoom);
m_resetZoomAct->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::ZoomFitBest));
m_resetZoomAct->setShortcut(QKeySequence(Qt::ControlModifier | Qt::Key_0));
}
QStringList ImageViewer::supportedMimeTypes() const
{
return m_formats;
}
void ImageViewer::clear()
{
m_imageLabel->setPixmap({});
m_maxScaleFactor = m_minScaleFactor = m_initialScaleFactor = m_scaleFactor = 1;
}
void ImageViewer::setupImageUi()
{
openFile();
}
//! [open]
void ImageViewer::openFile()
{
#if QT_CONFIG(cursor)
QGuiApplication::setOverrideCursor(Qt::WaitCursor);
#endif
const QString name = m_file->fileName();
QImageReader reader(name);
const QImage origImage = reader.read();
if (origImage.isNull()) {
statusMessage(tr("Cannot read file %1:\n%2.")
.arg(QDir::toNativeSeparators(name),
reader.errorString()), tr("open"));
disablePrinting();
#if QT_CONFIG(cursor)
QGuiApplication::restoreOverrideCursor();
#endif
return;
}
clear();
QImage image = origImage.colorSpace().isValid()
? origImage.convertedToColorSpace(QColorSpace::SRgb)
: origImage;
const auto devicePixelRatio = m_imageLabel->devicePixelRatioF();
m_imageSize = QSizeF(image.size()) / devicePixelRatio;
QPixmap pixmap = QPixmap::fromImage(image);
pixmap.setDevicePixelRatio(devicePixelRatio);
m_imageLabel->setPixmap(pixmap);
const QSizeF targetSize = m_imageLabel->parentWidget()->size();
if (m_imageSize.width() > targetSize.width()
|| m_imageSize.height() > targetSize.height()) {
m_initialScaleFactor = qMin(targetSize.width() / m_imageSize.width(),
targetSize.height() / m_imageSize.height());
}
m_maxScaleFactor = 3 * m_initialScaleFactor;
m_minScaleFactor = m_initialScaleFactor / 3;
doSetScaleFactor(m_initialScaleFactor);
statusMessage(msgOpen(name, origImage));
#if QT_CONFIG(cursor)
QGuiApplication::restoreOverrideCursor();
#endif
maybeEnablePrinting();
}
//! [open]
void ImageViewer::setScaleFactor(qreal scaleFactor)
{
if (!qFuzzyCompare(m_scaleFactor, scaleFactor))
doSetScaleFactor(scaleFactor);
}
void ImageViewer::doSetScaleFactor(qreal scaleFactor)
{
m_scaleFactor = scaleFactor;
const QSize labelSize = (m_imageSize * m_scaleFactor).toSize();
m_imageLabel->setFixedSize(labelSize);
enableZoomActions();
}
void ImageViewer::zoomIn()
{
setScaleFactor(m_scaleFactor * 1.25);
}
void ImageViewer::zoomOut()
{
setScaleFactor(m_scaleFactor * 0.8);
}
void ImageViewer::resetZoom()
{
setScaleFactor(m_initialScaleFactor);
}
bool ImageViewer::hasContent() const
{
return !m_imageLabel->pixmap().isNull();
}
void ImageViewer::enableZoomActions()
{
m_resetZoomAct->setEnabled(!qFuzzyCompare(m_scaleFactor, m_initialScaleFactor));
m_zoomInAct->setEnabled(m_scaleFactor < m_maxScaleFactor);
m_zoomOutAct->setEnabled(m_scaleFactor > m_minScaleFactor);
}
#ifdef QT_DOCUMENTVIEWER_PRINTSUPPORT
void ImageViewer::printDocument(QPrinter *printer) const
{
if (!hasContent())
return;
QPainter painter(printer);
QPixmap pixmap = m_imageLabel->pixmap();
QRect rect = painter.viewport();
QSize size = pixmap.size();
size.scale(rect.size(), Qt::KeepAspectRatio);
painter.setViewport(rect.x(), rect.y(), size.width(), size.height());
painter.setWindow(pixmap.rect());
painter.drawPixmap(0, 0, pixmap);
}
#endif // QT_DOCUMENTVIEWER_PRINTSUPPORT