File indexing completed on 2024-04-28 04:33:06

0001 /*
0002     SPDX-FileCopyrightText: 2005 Enrico Ros <eros.kde@email.it>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #ifndef _OKULAR_PAGEPAINTER_H_
0008 #define _OKULAR_PAGEPAINTER_H_
0009 
0010 #include <QBrush>
0011 #include <QImage>
0012 #include <QPen>
0013 
0014 #include "core/annotations.h"
0015 #include "core/area.h" // for NormalizedPoint
0016 
0017 class QPainter;
0018 class QRect;
0019 namespace Okular
0020 {
0021 class DocumentObserver;
0022 class Page;
0023 }
0024 
0025 /**
0026  * @short Paints a Okular::Page to an open painter using given flags.
0027  */
0028 class Q_DECL_EXPORT PagePainter
0029 {
0030 public:
0031     // list of flags passed to the painting function. by OR-ing those flags
0032     // you can decide whether or not to permit drawing of a certain feature.
0033     enum PagePainterFlags { Accessibility = 1, EnhanceLinks = 2, EnhanceImages = 4, Highlights = 8, TextSelection = 16, Annotations = 32 };
0034 
0035     /**
0036      * Draw @p page on @p destPainter.
0037      *
0038      * @param destPainter Page will be drawn on this painter.
0039      * @param page Which page do draw.
0040      * @param observer Request pixmaps generated for this DocumentObserver.
0041      * @param flags PagePainterFlags, which features to draw.
0042      * @param scaledWidth The requested width of uncropped page in @p destPainter coordinates.
0043      * @param scaledHeight The requested height of uncropped page in @p destPainter coordinates.
0044      * @param pageLimits Where to paint in @p destPainter coordinates. (I. e. painter crop.) Should begin at (0, 0).
0045      */
0046     static void paintPageOnPainter(QPainter *destPainter, const Okular::Page *page, Okular::DocumentObserver *observer, int flags, int scaledWidth, int scaledHeight, const QRect pageLimits);
0047 
0048     /**
0049      * Draw @p page on @p destPainter.
0050      *
0051      * @param destPainter Page will be drawn on this painter.
0052      * @param page Which page do draw.
0053      * @param observer Request pixmaps generated for this DocumentObserver.
0054      * @param flags PagePainterFlags, which features to draw.
0055      * @param scaledWidth The requested width of uncropped page in @p destPainter coordinates.
0056      * @param scaledHeight The requested height of uncropped page in @p destPainter coordinates.
0057      * @param pageLimits Where to paint in @p destPainter coordinates. (I. e. painter crop.) Should begin at (0, 0).
0058      * @param crop Which area of the page to paint in @p pageLimits.
0059      * @param viewPortPoint Which point of the page to highlight, e. g. a source location. @c nullptr to disable.
0060      */
0061     static void paintCroppedPageOnPainter(QPainter *destPainter,
0062                                           const Okular::Page *page,
0063                                           Okular::DocumentObserver *observer,
0064                                           int flags,
0065                                           int scaledWidth,
0066                                           int scaledHeight,
0067                                           const QRect pageLimits,
0068                                           const Okular::NormalizedRect &crop,
0069                                           Okular::NormalizedPoint *viewPortPoint);
0070 
0071 private:
0072     // BEGIN Change Colors feature
0073     /**
0074      * Collapse color space (from white to black) to a line from @p foreground to @p background.
0075      */
0076     static void recolor(QImage *image, const QColor &foreground, const QColor &background);
0077     /**
0078      * Collapse color space to a line from white to black,
0079      * then move from @p threshold to 128 and stretch the line by @p contrast.
0080      */
0081     static void blackWhite(QImage *image, int contrast, int threshold);
0082     /**
0083      * Invert the lightness axis of the HSL color cone.
0084      */
0085     static void invertLightness(QImage *image);
0086     /**
0087      * Inverts luma of @p image using the luma coefficients @p Y_R, @p Y_G, @p Y_B (should sum up to 1),
0088      * and assuming linear 8bit RGB color space.
0089      */
0090     static void invertLuma(QImage *image, float Y_R, float Y_G, float Y_B);
0091     /**
0092      * Inverts luma of a pixel given in @p R, @p G, @p B,
0093      * using the luma coefficients @p Y_R, @p Y_G, @p Y_B (should sum up to 1),
0094      * and assuming linear 8bit RGB color space.
0095      */
0096     static void invertLumaPixel(uchar &R, uchar &G, uchar &B, float Y_R, float Y_G, float Y_B);
0097     /**
0098      * Shifts hue of each pixel by 120 degrees, by simply swapping channels.
0099      */
0100     static void hueShiftPositive(QImage *image);
0101     /**
0102      * Shifts hue of each pixel by 240 degrees, by simply swapping channels.
0103      */
0104     static void hueShiftNegative(QImage *image);
0105     // END Change Colors feature
0106 
0107     // my pretty dear raster function
0108     typedef QList<Okular::NormalizedPoint> NormalizedPath;
0109     enum RasterOperation { Normal, Multiply };
0110 
0111     /**
0112      * Draw @p normPath on @p image.
0113      *
0114      * @note @p normPath needs to be normalized in respect to @p image, not to the actual page.
0115      */
0116     static void drawShapeOnImage(QImage &image, const NormalizedPath &normPath, bool closeShape, const QPen &pen, const QBrush &brush = QBrush(), double penWidthMultiplier = 1.0, RasterOperation op = Normal);
0117 
0118     /**
0119      * Draw an ellipse described by @p rect on @p image.
0120      *
0121      * @param rect Two NormalizedPoints describing the bounding rect. Need to be normalized in respect to @p image, not to the actual page.
0122      */
0123     static void drawEllipseOnImage(QImage &image, const NormalizedPath &rect, const QPen &pen, const QBrush &brush, double penWidthMultiplier, RasterOperation op = Normal);
0124 
0125     friend class LineAnnotPainter;
0126 };
0127 
0128 /**
0129  * @short Painting helper for a single Okular::LineAnnotation.
0130  */
0131 class LineAnnotPainter
0132 {
0133 public:
0134     /**
0135      * @param a The annotation to paint. Accessed by draw().
0136      * @param pageSizeA The full size of the page on which to paint.
0137      * @param pageScale The scale of the page when you call draw().
0138      * @param toNormalizedImage How to transform normalized coordinates of @p a to normalized coordinates of your paint device. (If your paint device represents the whole page, use the unit matrix QTransform().)
0139      */
0140     LineAnnotPainter(const Okular::LineAnnotation *a, QSizeF pageSizeA, double pageScale, const QTransform &toNormalizedImage);
0141 
0142     /**
0143      * Draw the annotation on @p image.
0144      */
0145     void draw(QImage &image) const;
0146 
0147 private:
0148     void drawMainLine(QImage &image) const;
0149     void drawShortenedLine(double mainSegmentLength, double size, QImage &image, const QTransform &toNormalizedPage) const;
0150     void drawLineEnds(double mainSegmentLength, double size, QImage &image, const QTransform &transform) const;
0151     void drawLineEndArrow(double xEndPos, double size, double flipX, bool close, const QTransform &toNormalizedPage, QImage &image) const;
0152     void drawLineEndButt(double xEndPos, double size, const QTransform &toNormalizedPage, QImage &image) const;
0153     void drawLineEndCircle(double xEndPos, double size, const QTransform &toNormalizedPage, QImage &image) const;
0154     void drawLineEndSquare(double xEndPos, double size, const QTransform &toNormalizedPage, QImage &image) const;
0155     void drawLineEndDiamond(double xEndPos, double size, const QTransform &toNormalizedPage, QImage &image) const;
0156     void drawLineEndSlash(double xEndPos, double size, const QTransform &toNormalizedPage, QImage &image) const;
0157     void drawLeaderLine(double xEndPos, QImage &image, const QTransform &toNormalizedPage) const;
0158     template<typename T> QList<Okular::NormalizedPoint> transformPath(const T &path, const QTransform &transform) const
0159     {
0160         QList<Okular::NormalizedPoint> transformedPath;
0161         for (const Okular::NormalizedPoint &item : path) {
0162             Okular::NormalizedPoint p;
0163             transform.map(item.x, item.y, &p.x, &p.y);
0164             transformedPath.append(p);
0165         }
0166         return transformedPath;
0167     }
0168 
0169     static double shortenForArrow(double size, Okular::LineAnnotation::TermStyle endStyle);
0170 
0171 private:
0172     const Okular::LineAnnotation *la;
0173     QSizeF pageSize;
0174     double pageScale;
0175     QTransform toNormalizedImage;
0176     double aspectRatio;
0177     const QPen linePen;
0178     QBrush fillBrush;
0179 };
0180 
0181 #endif