diff options
Diffstat (limited to 'src/pdf/qpdfdocument.cpp')
-rw-r--r-- | src/pdf/qpdfdocument.cpp | 133 |
1 files changed, 114 insertions, 19 deletions
diff --git a/src/pdf/qpdfdocument.cpp b/src/pdf/qpdfdocument.cpp index 89b27da8b..e4ec363ce 100644 --- a/src/pdf/qpdfdocument.cpp +++ b/src/pdf/qpdfdocument.cpp @@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE // The library is not thread-safe at all, it has a lot of global variables. Q_GLOBAL_STATIC_WITH_ARGS(QMutex, pdfMutex, (QMutex::Recursive)); static int libraryRefCount; -static const double CharacterHitTolerance = 6.0; +static const double CharacterHitTolerance = 16.0; Q_LOGGING_CATEGORY(qLcDoc, "qt.pdf.document") QPdfMutexLocker::QPdfMutexLocker() @@ -402,6 +402,50 @@ QString QPdfDocumentPrivate::getText(FPDF_TEXTPAGE textPage, int startIndex, int return QString::fromUtf16(buf.constData(), len - 1); } +QPointF QPdfDocumentPrivate::getCharPosition(FPDF_TEXTPAGE textPage, double pageHeight, int charIndex) +{ + double x, y; + int count = FPDFText_CountChars(textPage); + bool ok = FPDFText_GetCharOrigin(textPage, qMin(count - 1, charIndex), &x, &y); + if (!ok) + return QPointF(); + return QPointF(x, pageHeight - y); +} + +QRectF QPdfDocumentPrivate::getCharBox(FPDF_TEXTPAGE textPage, double pageHeight, int charIndex) +{ + double l, t, r, b; + bool ok = FPDFText_GetCharBox(textPage, charIndex, &l, &r, &b, &t); + if (!ok) + return QRectF(); + return QRectF(l, pageHeight - t, r - l, t - b); +} + +QPdfDocumentPrivate::TextPosition QPdfDocumentPrivate::hitTest(int page, QPointF position) +{ + const QPdfMutexLocker lock; + FPDF_PAGE pdfPage = FPDF_LoadPage(doc, page); + double pageHeight = FPDF_GetPageHeight(pdfPage); + FPDF_TEXTPAGE textPage = FPDFText_LoadPage(pdfPage); + int hitIndex = FPDFText_GetCharIndexAtPos(textPage, position.x(), pageHeight - position.y(), + CharacterHitTolerance, CharacterHitTolerance); + if (hitIndex >= 0) { + QPointF charPos = getCharPosition(textPage, pageHeight, hitIndex); + if (!charPos.isNull()) { + QRectF charBox = getCharBox(textPage, pageHeight, hitIndex); + // If the given position is past the end of the line, i.e. if the right edge of the found character's + // bounding box is closer to it than the left edge is, we say that we "hit" the next character index after + if (qAbs(charBox.right() - position.x()) < qAbs(charPos.x() - position.x())) { + charPos.setX(charBox.right()); + ++hitIndex; + } + qCDebug(qLcDoc) << "on page" << page << "@" << position << "got char position" << charPos << "index" << hitIndex; + return { charPos, charBox.height(), hitIndex }; + } + } + return {}; +} + /*! \class QPdfDocument \since 5.10 @@ -748,29 +792,80 @@ QPdfSelection QPdfDocument::getSelection(int page, QPointF start, QPointF end) if (startIndex >= 0 && endIndex != startIndex) { if (startIndex > endIndex) qSwap(startIndex, endIndex); - int count = endIndex - startIndex + 1; + + // If the given end position is past the end of the line, i.e. if the right edge of the last character's + // bounding box is closer to it than the left edge is, then extend the char range by one + QRectF endCharBox = d->getCharBox(textPage, pageHeight, endIndex); + if (qAbs(endCharBox.right() - end.x()) < qAbs(endCharBox.x() - end.x())) + ++endIndex; + + int count = endIndex - startIndex; QString text = d->getText(textPage, startIndex, count); QVector<QPolygonF> bounds; + QRectF hull; int rectCount = FPDFText_CountRects(textPage, startIndex, endIndex - startIndex); for (int i = 0; i < rectCount; ++i) { double l, r, b, t; FPDFText_GetRect(textPage, i, &l, &t, &r, &b); - QPolygonF poly; - poly << QPointF(l, pageHeight - t); - poly << QPointF(r, pageHeight - t); - poly << QPointF(r, pageHeight - b); - poly << QPointF(l, pageHeight - b); - poly << QPointF(l, pageHeight - t); - bounds << poly; + QRectF rect(l, pageHeight - t, r - l, t - b); + if (hull.isNull()) + hull = rect; + else + hull = hull.united(rect); + bounds << QPolygonF(rect); } qCDebug(qLcDoc) << page << start << "->" << end << "found" << startIndex << "->" << endIndex << text; - return QPdfSelection(text, bounds); + return QPdfSelection(text, bounds, hull, startIndex, endIndex); } qCDebug(qLcDoc) << page << start << "->" << end << "nothing found"; return QPdfSelection(); } +/*! + Returns information about the text on the given \a page that can be found + beginning at the given \a startIndex with at most \l maxLength characters. +*/ +QPdfSelection QPdfDocument::getSelectionAtIndex(int page, int startIndex, int maxLength) +{ + + if (page < 0 || startIndex < 0 || maxLength < 0) + return {}; + const QPdfMutexLocker lock; + FPDF_PAGE pdfPage = FPDF_LoadPage(d->doc, page); + double pageHeight = FPDF_GetPageHeight(pdfPage); + FPDF_TEXTPAGE textPage = FPDFText_LoadPage(pdfPage); + int pageCount = FPDFText_CountChars(textPage); + if (startIndex >= pageCount) + return QPdfSelection(); + QVector<QPolygonF> bounds; + QRectF hull; + int rectCount = 0; + QString text; + if (maxLength > 0) { + text = d->getText(textPage, startIndex, maxLength); + rectCount = FPDFText_CountRects(textPage, startIndex, text.length()); + for (int i = 0; i < rectCount; ++i) { + double l, r, b, t; + FPDFText_GetRect(textPage, i, &l, &t, &r, &b); + QRectF rect(l, pageHeight - t, r - l, t - b); + if (hull.isNull()) + hull = rect; + else + hull = hull.united(rect); + bounds << QPolygonF(rect); + } + } + if (bounds.isEmpty()) + hull = QRectF(d->getCharPosition(textPage, pageHeight, startIndex), QSizeF()); + qCDebug(qLcDoc) << "on page" << page << "at index" << startIndex << "maxLength" << maxLength + << "got" << text.length() << "chars," << rectCount << "rects within" << hull; + return QPdfSelection(text, bounds, hull, startIndex, startIndex + text.length()); +} + +/*! + Returns all the text and its bounds on the given \a page. +*/ QPdfSelection QPdfDocument::getAllText(int page) { const QPdfMutexLocker lock; @@ -782,20 +877,20 @@ QPdfSelection QPdfDocument::getAllText(int page) return QPdfSelection(); QString text = d->getText(textPage, 0, count); QVector<QPolygonF> bounds; + QRectF hull; int rectCount = FPDFText_CountRects(textPage, 0, count); for (int i = 0; i < rectCount; ++i) { double l, r, b, t; FPDFText_GetRect(textPage, i, &l, &t, &r, &b); - QPolygonF poly; - poly << QPointF(l, pageHeight - t); - poly << QPointF(r, pageHeight - t); - poly << QPointF(r, pageHeight - b); - poly << QPointF(l, pageHeight - b); - poly << QPointF(l, pageHeight - t); - bounds << poly; + QRectF rect(l, pageHeight - t, r - l, t - b); + if (hull.isNull()) + hull = rect; + else + hull = hull.united(rect); + bounds << QPolygonF(rect); } - qCDebug(qLcDoc) << "on page" << page << "got" << count << "chars" << rectCount << "rects"; - return QPdfSelection(text, bounds); + qCDebug(qLcDoc) << "on page" << page << "got" << count << "chars," << rectCount << "rects within" << hull; + return QPdfSelection(text, bounds, hull, 0, count); } QT_END_NAMESPACE |