#include "nglpdfpage.h" #include #include #include #include #include #include namespace NGL { template static inline T getRotatedSize(const T &in, Poppler::Page::Rotation rot) { switch (rot) { case Poppler::Page::Rotate0: case Poppler::Page::Rotate180: return in; case Poppler::Page::Rotate90: case Poppler::Page::Rotate270: return in.transposed(); } Q_ASSERT(false); return in; } PDFPage::PDFPage(QWidget *parent) : QWidget(parent) , m_page(nullptr) , m_scaleFactor(1.0) , m_rotation(Poppler::Page::Rotate0) { setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); setMouseTracking(true); } PDFPage::~PDFPage() { delete m_page; } void PDFPage::setPopplerPage(Poppler::Page *page) { if (m_page == page) return; delete m_page; m_page = page; m_links.clear(); m_linkRects.clear(); if (!m_page) return; // Poppler::Page::links() returns std::vector> in Poppler Qt6 auto links = m_page->links(); for (auto &linkUp : links) { Poppler::Link *link = linkUp.get(); if (!link) continue; if (link->linkType() == Poppler::Link::Browse || link->linkType() == Poppler::Link::Goto) m_links.emplace_back(std::move(linkUp)); else std::cerr << "linktype: " << link->linkType() << std::endl; } rebuildInternalData(); } void PDFPage::setZoomFactor(double zoom) { if (qFuzzyCompare(m_scaleFactor, zoom)) return; m_scaleFactor = zoom; rebuildInternalData(); } void PDFPage::setRotation(Poppler::Page::Rotation rot) { if (m_rotation == rot) return; m_rotation = rot; rebuildInternalData(); } void PDFPage::clearPixmap() { m_pdfPixmap = QPixmap(); } QImage PDFPage::getPrintableImage(int resolution) const { if (!m_page) return QImage(); Poppler::Page::Rotation rot = Poppler::Page::Rotate0; if (m_page->orientation() == Poppler::Page::Landscape) rot = Poppler::Page::Rotate270; else if (m_page->orientation() == Poppler::Page::Seascape) rot = Poppler::Page::Rotate90; else if (m_page->orientation() == Poppler::Page::UpsideDown) rot = Poppler::Page::Rotate180; Q_UNUSED(rot) return m_page->renderToImage(resolution, resolution, -1, -1, -1, -1, m_rotation); } QSize PDFPage::sizeHint() const { if (!m_page) return QSize(); return getRotatedSize(m_page->pageSize(), m_rotation); } void PDFPage::paintEvent(QPaintEvent *event) { Q_UNUSED(event) if (!m_page) return; if (m_pdfPixmap.isNull()) { const QImage img = m_page->renderToImage(m_scaleFactor * 72, m_scaleFactor * 72, -1, -1, -1, -1, m_rotation); m_pdfPixmap = QPixmap::fromImage(img); emit pageRendered(); } QPainter p(this); p.drawPixmap(0, 0, m_pdfPixmap); p.end(); } void PDFPage::mouseMoveEvent(QMouseEvent *event) { const QPointF pos = event->position(); for (const auto &linkRect : std::as_const(m_linkRects)) { if (linkRect.contains(pos)) { setCursor(Qt::PointingHandCursor); return; } } setCursor(Qt::ArrowCursor); QWidget::mouseMoveEvent(event); } void PDFPage::mouseReleaseEvent(QMouseEvent *event) { const QPointF pos = event->position(); for (int i = 0; i < m_linkRects.size(); ++i) { if (m_linkRects.at(i).contains(pos)) { const Poppler::Link *link = m_links.at(i).get(); if (!link) continue; if (link->linkType() == Poppler::Link::Browse) { const Poppler::LinkBrowse *linkBrowse = static_cast(link); emit externalLinkClicked(linkBrowse->url()); return; } else if (link->linkType() == Poppler::Link::Goto) { const Poppler::LinkGoto *linkGoto = static_cast(link); if (linkGoto->isExternal()) { const QUrl url = QUrl::fromLocalFile(linkGoto->fileName()); emit externalLinkClicked(url.toString()); return; } emit linkClicked(linkGoto->destination()); return; } } } QWidget::mouseReleaseEvent(event); } void PDFPage::rebuildInternalData() { clearPixmap(); if (!m_page) return; const QSizeF s(rotatedPageSize()); const int w = qRound(s.width() * m_scaleFactor); const int h = qRound(s.height() * m_scaleFactor); setMinimumSize(w, h); resize(sizeHint()); m_linkRects.clear(); m_linkRects.reserve(static_cast(m_links.size())); for (const auto &linkUp : m_links) { const Poppler::Link *link = linkUp.get(); if (!link) continue; const QRectF r = link->linkArea(); m_linkRects += QRectF(r.x() * w, r.y() * h, r.width() * w, r.height() * h); } } QSizeF PDFPage::rotatedPageSize() const { return m_page ? getRotatedSize(m_page->pageSizeF(), m_rotation) : QSizeF(); } }