check_annotations.cpp 4.44 KB
Newer Older
Tobias Deiminger's avatar
Tobias Deiminger committed
1
#include <cmath>
2
#include <memory>
Tobias Deiminger's avatar
Tobias Deiminger committed
3
#include <sstream>
4 5 6 7 8 9

#include <QtTest/QtTest>
#include <QTemporaryFile>

#include <poppler-qt5.h>

Tobias Deiminger's avatar
Tobias Deiminger committed
10 11 12
#include "goo/GooString.h"
#include "goo/gstrtod.h"

13 14 15
class TestAnnotations : public QObject
{
  Q_OBJECT
16 17
public:
    TestAnnotations(QObject *parent = nullptr) : QObject(parent) { }
18
private slots:
Tobias Deiminger's avatar
Tobias Deiminger committed
19 20
  void checkQColorPrecision();
  void checkFontSizeAndColor();
21
  void checkHighlightFromAndToQuads();
22 23
};

Tobias Deiminger's avatar
Tobias Deiminger committed
24 25 26 27 28 29
/* Is .5f sufficient for 16 bit color channel roundtrip trough save and load on all architectures? */
void TestAnnotations::checkQColorPrecision() {
  bool precisionOk = true;
  for (int i = std::numeric_limits<uint16_t>::min(); i <= std::numeric_limits<uint16_t>::max(); i++) {
    double normalized = static_cast<uint16_t>(i) / static_cast<double>(std::numeric_limits<uint16_t>::max());
    GooString* serialized = GooString::format("{0:.5f}", normalized);
30
    double deserialized = gatof( serialized->c_str() );
31
    delete serialized;
Tobias Deiminger's avatar
Tobias Deiminger committed
32 33 34 35 36 37 38 39 40 41
    uint16_t denormalized = std::round(deserialized * std::numeric_limits<uint16_t>::max());
    if (static_cast<uint16_t>(i) != denormalized) {
      precisionOk = false;
      break;
    }
  }
  QVERIFY(precisionOk);
}

void TestAnnotations::checkFontSizeAndColor()
42
{
43
  const QString contents = QStringLiteral("foobar");
Tobias Deiminger's avatar
Tobias Deiminger committed
44 45
  const std::vector<QColor> testColors{QColor::fromRgb(0xAB, 0xCD, 0xEF),
                                       QColor::fromCmyk(0xAB, 0xBC, 0xCD, 0xDE)};
46
  const QFont testFont(QStringLiteral("Helvetica"), 20);
47 48 49 50 51 52 53 54 55

  QTemporaryFile tempFile;
  QVERIFY(tempFile.open());
  tempFile.close();

  {
    std::unique_ptr<Poppler::Document> doc{
      Poppler::Document::load(TESTDATADIR "/unittestcases/UseNone.pdf")
    };
56
    QVERIFY(doc.get());
57 58 59 60

    std::unique_ptr<Poppler::Page> page{
      doc->page(0)
    };
61
    QVERIFY(page.get());
62

Tobias Deiminger's avatar
Tobias Deiminger committed
63 64 65 66 67 68 69 70
    for (const auto& color : testColors) {
      auto annot = std::make_unique<Poppler::TextAnnotation>(Poppler::TextAnnotation::InPlace);
      annot->setBoundary(QRectF(0.0, 0.0, 1.0, 1.0));
      annot->setContents(contents);
      annot->setTextFont(testFont);
      annot->setTextColor(color);
      page->addAnnotation(annot.get());
    }
71 72

    std::unique_ptr<Poppler::PDFConverter> conv(doc->pdfConverter());
73
    QVERIFY(conv.get());
74 75 76 77 78 79 80 81 82
    conv->setOutputFileName(tempFile.fileName());
    conv->setPDFOptions(Poppler::PDFConverter::WithChanges);
    QVERIFY(conv->convert());
  }

  {
    std::unique_ptr<Poppler::Document> doc{
      Poppler::Document::load(tempFile.fileName())
    };
83
    QVERIFY(doc.get());
84 85 86 87

    std::unique_ptr<Poppler::Page> page{
      doc->page(0)
    };
88
    QVERIFY(page.get());
89 90

    auto annots = page->annotations();
Tobias Deiminger's avatar
Tobias Deiminger committed
91 92 93 94 95 96 97 98 99 100
    QCOMPARE(annots.size(), static_cast<int>(testColors.size()));

    auto &&annot = annots.constBegin();
    for (const auto& color : testColors) {
      QCOMPARE((*annot)->subType(), Poppler::Annotation::AText);
      auto textAnnot = static_cast<Poppler::TextAnnotation*>(*annot);
      QCOMPARE(textAnnot->contents(), contents);
      QCOMPARE(textAnnot->textFont().pointSize(), testFont.pointSize());
      QCOMPARE(static_cast<int>(textAnnot->textColor().spec()), static_cast<int>(color.spec()));
      QCOMPARE(textAnnot->textColor(), color);
101
      if (annot != annots.constEnd())
Tobias Deiminger's avatar
Tobias Deiminger committed
102 103
          ++annot;
    }
104
    qDeleteAll(annots);
105 106 107
  }
}

108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
namespace Poppler {
    static bool operator==(const Poppler::HighlightAnnotation::Quad &a, const Poppler::HighlightAnnotation::Quad &b)
    {
        // FIXME We do not compare capStart, capEnd and feather since AnnotQuadrilaterals doesn't contain that info and thus
        //       HighlightAnnotationPrivate::fromQuadrilaterals uses default values
        return a.points[0] == b.points[0] && a.points[1] == b.points[1] && a.points[2] == b.points[2] && a.points[3] == b.points[3];
    }
}

void TestAnnotations::checkHighlightFromAndToQuads()
{
    std::unique_ptr<Poppler::Document> doc{
      Poppler::Document::load(TESTDATADIR "/unittestcases/UseNone.pdf")
    };

    std::unique_ptr<Poppler::Page> page{
      doc->page(0)
    };

    auto ha = std::make_unique<Poppler::HighlightAnnotation>();
    page->addAnnotation(ha.get());

    const QList<Poppler::HighlightAnnotation::Quad> quads = {
        { {{0, 0.1}, {0.2, 0.3}, {0.4, 0.5}, {0.6, 0.7}}, false, false, 0 },
        { {{0.8, 0.9}, {0.1, 0.2}, {0.3, 0.4}, {0.5, 0.6}}, true, false, 0.4 }
    };
    ha->setHighlightQuads(quads);
    QCOMPARE(ha->highlightQuads(), quads);
}

138 139 140
QTEST_GUILESS_MAIN(TestAnnotations)

#include "check_annotations.moc"