From 4f5f0705bc161ff95899fdb2c5fcdb4581bf15bb Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 23 Dec 2019 07:34:16 +0100 Subject: QPdfDocument and QPdfIOHandler: add scale and clip features Like some other image plugins, the PDF plugin now supports ImageOption::ScaledClipRect and ScaledSize. Change-Id: Ie7278752e49c885cc4580f30af1ec5e6310f8334 Reviewed-by: Michal Klocek --- src/pdf/api/qpdfdocumentrenderoptions.h | 12 ++++++++- src/pdf/qpdfdocument.cpp | 34 ++++++++++++++++++++++++-- src/plugins/imageformats/pdf/qpdfiohandler.cpp | 10 ++++++-- 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/pdf/api/qpdfdocumentrenderoptions.h b/src/pdf/api/qpdfdocumentrenderoptions.h index 99a5db2e3..873be0085 100644 --- a/src/pdf/api/qpdfdocumentrenderoptions.h +++ b/src/pdf/api/qpdfdocumentrenderoptions.h @@ -39,6 +39,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -53,6 +54,12 @@ public: Q_DECL_CONSTEXPR QPdf::RenderFlags renderFlags() const Q_DECL_NOTHROW { return static_cast(bits.renderFlags); } Q_DECL_RELAXED_CONSTEXPR void setRenderFlags(QPdf::RenderFlags _renderFlags) Q_DECL_NOTHROW { bits.renderFlags = _renderFlags; } + Q_DECL_CONSTEXPR QRect scaledClipRect() const Q_DECL_NOTHROW { return m_clipRect; } + Q_DECL_RELAXED_CONSTEXPR void setScaledClipRect(const QRect &r) Q_DECL_NOTHROW { m_clipRect = r; } + + Q_DECL_CONSTEXPR QSize scaledSize() const Q_DECL_NOTHROW { return m_scaledSize; } + Q_DECL_RELAXED_CONSTEXPR void setScaledSize(const QSize &s) Q_DECL_NOTHROW { m_scaledSize = s; } + private: friend Q_DECL_CONSTEXPR inline bool operator==(QPdfDocumentRenderOptions lhs, QPdfDocumentRenderOptions rhs) Q_DECL_NOTHROW; @@ -68,13 +75,16 @@ private: Bits bits; quint64 data; }; + + QRect m_clipRect; + QSize m_scaledSize; }; Q_DECLARE_TYPEINFO(QPdfDocumentRenderOptions, Q_PRIMITIVE_TYPE); Q_DECL_CONSTEXPR inline bool operator==(QPdfDocumentRenderOptions lhs, QPdfDocumentRenderOptions rhs) Q_DECL_NOTHROW { - return lhs.data == rhs.data; + return lhs.data == rhs.data && lhs.m_clipRect == rhs.m_clipRect && lhs.m_scaledSize == rhs.m_scaledSize; } Q_DECL_CONSTEXPR inline bool operator!=(QPdfDocumentRenderOptions lhs, QPdfDocumentRenderOptions rhs) Q_DECL_NOTHROW diff --git a/src/pdf/qpdfdocument.cpp b/src/pdf/qpdfdocument.cpp index 4c4f8f24e..728bf1245 100644 --- a/src/pdf/qpdfdocument.cpp +++ b/src/pdf/qpdfdocument.cpp @@ -46,6 +46,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -675,12 +676,41 @@ QImage QPdfDocument::render(int page, QSize imageSize, QPdfDocumentRenderOptions if (renderFlags & QPdf::RenderPathAliased) flags |= FPDF_RENDER_NO_SMOOTHPATH; - FPDF_RenderPageBitmap(bitmap, pdfPage, 0, 0, result.width(), result.height(), rotation, flags); + if (renderOptions.scaledClipRect().isValid()) { + const QRect &clipRect = renderOptions.scaledClipRect(); + + // TODO take rotation into account, like cpdf_page.cpp lines 145-178 + float x0 = clipRect.left(); + float y0 = clipRect.top(); + float x1 = clipRect.left(); + float y1 = clipRect.bottom(); + float x2 = clipRect.right(); + float y2 = clipRect.top(); + QSizeF origSize = pageSize(page); + QVector2D pageScale(1, 1); + if (!renderOptions.scaledSize().isNull()) { + pageScale = QVector2D(renderOptions.scaledSize().width() / float(origSize.width()), + renderOptions.scaledSize().height() / float(origSize.height())); + } + FS_MATRIX matrix {(x2 - x0) / result.width() * pageScale.x(), + (y2 - y0) / result.width() * pageScale.x(), + (x1 - x0) / result.height() * pageScale.y(), + (y1 - y0) / result.height() * pageScale.y(), -x0, -y0}; + + FS_RECTF clipRectF { 0, 0, float(imageSize.width()), float(imageSize.height()) }; + + FPDF_RenderPageBitmapWithMatrix(bitmap, pdfPage, &matrix, &clipRectF, flags); + qCDebug(qLcDoc) << "matrix" << matrix.a << matrix.b << matrix.c << matrix.d << matrix.e << matrix.f; + qCDebug(qLcDoc) << "page" << page << "region" << renderOptions.scaledClipRect() + << "size" << imageSize << "took" << timer.elapsed() << "ms"; + } else { + FPDF_RenderPageBitmap(bitmap, pdfPage, 0, 0, result.width(), result.height(), rotation, flags); + qCDebug(qLcDoc) << "page" << page << "size" << imageSize << "took" << timer.elapsed() << "ms"; + } FPDFBitmap_Destroy(bitmap); FPDF_ClosePage(pdfPage); - qCDebug(qLcDoc) << "page" << page << imageSize << "took" << timer.elapsed() << "ms"; return result; } diff --git a/src/plugins/imageformats/pdf/qpdfiohandler.cpp b/src/plugins/imageformats/pdf/qpdfiohandler.cpp index 9df85cf08..739e8b34c 100644 --- a/src/plugins/imageformats/pdf/qpdfiohandler.cpp +++ b/src/plugins/imageformats/pdf/qpdfiohandler.cpp @@ -98,7 +98,8 @@ bool QPdfIOHandler::read(QImage *image) if (m_page < 0) m_page = 0; const bool xform = (m_clipRect.isValid() || m_scaledSize.isValid() || m_scaledClipRect.isValid()); - QSize finalSize = m_doc.pageSize(m_page).toSize(); + QSize pageSize = m_doc.pageSize(m_page).toSize(); + QSize finalSize = pageSize; QRectF bounds; if (xform && !finalSize.isEmpty()) { bounds = QRectF(QPointF(0,0), QSizeF(finalSize)); @@ -112,6 +113,7 @@ bool QPdfIOHandler::read(QImage *image) sc = QSizeF(qreal(m_scaledSize.width()) / finalSize.width(), qreal(m_scaledSize.height()) / finalSize.height()); finalSize = m_scaledSize; + pageSize = m_scaledSize; } if (m_scaledClipRect.isValid()) { tr2 = -m_scaledClipRect.topLeft(); @@ -133,9 +135,13 @@ bool QPdfIOHandler::read(QImage *image) } } if (!finalSize.isEmpty()) { + QPdfDocumentRenderOptions options; + if (m_scaledClipRect.isValid()) + options.setScaledClipRect(m_scaledClipRect); + options.setScaledSize(pageSize); image->fill(m_backColor.rgba()); QPainter p(image); - QImage pageImage = m_doc.render(m_page, finalSize); + QImage pageImage = m_doc.render(m_page, finalSize, options); p.drawImage(0, 0, pageImage); p.end(); } -- cgit v1.2.3