// Copyright (C) 2021-2024 Jakub Melka // // This file is part of PDF4QT. // // PDF4QT is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // with the written consent of the copyright owner, any later version. // // PDF4QT is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with PDF4QT. If not, see . #include "pdfpainterutils.h" #include "pdfpagecontentprocessor.h" #include #include #include "pdfdbgheap.h" namespace pdf { QRect PDFPainterHelper::drawBubble(QPainter* painter, QPoint point, QColor color, QString text, Qt::Alignment alignment) { QFontMetrics fontMetrics = painter->fontMetrics(); const int lineSpacing = fontMetrics.lineSpacing(); const int bubbleHeight = lineSpacing* 2; const int bubbleWidth = lineSpacing + fontMetrics.horizontalAdvance(text); QRect rectangle(point, QSize(bubbleWidth, bubbleHeight)); if (alignment.testFlag(Qt::AlignVCenter)) { rectangle.translate(0, -rectangle.height() / 2); } else if (alignment.testFlag(Qt::AlignTop)) { rectangle.translate(0, -rectangle.height()); } if (alignment.testFlag(Qt::AlignHCenter)) { rectangle.translate(-rectangle.width() / 2, 0); } else if (alignment.testFlag(Qt::AlignLeft)) { rectangle.translate(-rectangle.width(), 0); } PDFPainterStateGuard guard(painter); painter->setRenderHint(QPainter::Antialiasing); painter->setPen(Qt::NoPen); painter->setBrush(QBrush(color)); painter->drawRoundedRect(rectangle, rectangle.height() / 2, rectangle.height() / 2, Qt::AbsoluteSize); painter->setPen(Qt::black); painter->drawText(rectangle, Qt::AlignCenter, text); return rectangle; } QPen PDFPainterHelper::createPenFromState(const PDFPageContentProcessorState* graphicState, double alpha) { QColor color = graphicState->getStrokeColor(); if (color.isValid()) { color.setAlphaF(alpha); const PDFReal lineWidth = graphicState->getLineWidth(); Qt::PenCapStyle penCapStyle = graphicState->getLineCapStyle(); Qt::PenJoinStyle penJoinStyle = graphicState->getLineJoinStyle(); const PDFLineDashPattern& lineDashPattern = graphicState->getLineDashPattern(); const PDFReal mitterLimit = graphicState->getMitterLimit(); QPen pen(color); pen.setWidthF(lineWidth); pen.setCapStyle(penCapStyle); pen.setJoinStyle(penJoinStyle); pen.setMiterLimit(mitterLimit); if (lineDashPattern.isSolid()) { pen.setStyle(Qt::SolidLine); } else { pen.setStyle(Qt::CustomDashLine); pen.setDashPattern(lineDashPattern.createForQPen(pen.widthF())); pen.setDashOffset(lineDashPattern.getDashOffset()); } return pen; } else { return QPen(Qt::NoPen); } } QBrush PDFPainterHelper::createBrushFromState(const PDFPageContentProcessorState* graphicState, double alpha) { QColor color = graphicState->getFillColor(); if (color.isValid()) { color.setAlphaF(alpha); return QBrush(color, Qt::SolidPattern); } else { return QBrush(Qt::NoBrush); } } PDFTransformationDecomposition PDFPainterHelper::decomposeTransform(const QTransform& transform) { PDFTransformationDecomposition result; const qreal m11 = transform.m11(); const qreal m12 = transform.m12(); const qreal m21 = transform.m21(); const qreal m22 = transform.m22(); const qreal dx = transform.dx(); const qreal dy = transform.dy(); const qreal sx = std::sqrt(m11 * m11 + m21 * m21); const qreal phi = std::atan2(m21, m11); const qreal msy = m12 * std::cos(phi) + m22 * std::sin(phi); const qreal sy = -m12 * std::sin(phi) + m22 * std::cos(phi); result.rotationAngle = phi; result.scaleX = sx; result.scaleY = sy; if (!qFuzzyIsNull(sy)) { result.shearFactor = msy / sy; } else { result.shearFactor = 0.0; } result.translateX = dx; result.translateY = dy; return result; } QTransform PDFPainterHelper::composeTransform(const PDFTransformationDecomposition& decomposition) { const qreal s = std::sin(decomposition.rotationAngle); const qreal c = std::cos(decomposition.rotationAngle); const qreal m = decomposition.shearFactor; const qreal sx = decomposition.scaleX; const qreal sy = decomposition.scaleY; const qreal dx = decomposition.translateX; const qreal dy = decomposition.translateY; const qreal m11 = sx * c; const qreal m12 = sy * m * c - sy * s; const qreal m21 = sx * s; const qreal m22 = sy * m * s + sy * c; return QTransform(m11, m12, m21, m22, dx, dy); } } // namespace pdf