175 lines
5.6 KiB
C++
175 lines
5.6 KiB
C++
#include "document_test_helpers.hpp"
|
|||
|
|
|
||
|
|
namespace pdfengine {
|
||
|
|
|
||
|
|
TEST(PageRenderTest, RenderAtDifferentDPI) {
|
||
|
|
SKIP_IF_NO_PDFIUM();
|
||
|
|
auto path = getCorpusPath("basic", "hello_world.pdf");
|
||
|
|
if (!std::filesystem::exists(path)) {
|
||
|
|
GTEST_SKIP() << "hello_world.pdf not found in corpus.";
|
||
|
|
}
|
||
|
|
|
||
|
|
auto docRes = PdfDocument::loadFromFile(path.string());
|
||
|
|
ASSERT_TRUE(docRes.has_value());
|
||
|
|
auto pageRes = (*docRes)->getPage(0);
|
||
|
|
ASSERT_TRUE(pageRes.has_value());
|
||
|
|
|
||
|
|
auto page = *pageRes;
|
||
|
|
double ptWidth = page->width();
|
||
|
|
double ptHeight = page->height();
|
||
|
|
EXPECT_GT(ptWidth, 0.0);
|
||
|
|
EXPECT_GT(ptHeight, 0.0);
|
||
|
|
|
||
|
|
std::vector<int> dpis = {72, 144, 288};
|
||
|
|
for (int dpi : dpis) {
|
||
|
|
auto imgRes = page->render(dpi);
|
||
|
|
ASSERT_TRUE(imgRes.has_value()) << "Failed to render at DPI " << dpi;
|
||
|
|
|
||
|
|
double scale = dpi / 72.0;
|
||
|
|
int expectedW = static_cast<int>(ptWidth * scale);
|
||
|
|
int expectedH = static_cast<int>(ptHeight * scale);
|
||
|
|
|
||
|
|
EXPECT_EQ(imgRes->width, expectedW);
|
||
|
|
EXPECT_EQ(imgRes->height, expectedH);
|
||
|
|
|
||
|
|
ASSERT_GE(imgRes->data.size(), 8U);
|
||
|
|
EXPECT_EQ(imgRes->data[0], 0x89);
|
||
|
|
EXPECT_EQ(imgRes->data[1], 'P');
|
||
|
|
EXPECT_EQ(imgRes->data[2], 'N');
|
||
|
|
EXPECT_EQ(imgRes->data[3], 'G');
|
||
|
|
EXPECT_EQ(imgRes->data[4], 0x0D);
|
||
|
|
EXPECT_EQ(imgRes->data[5], 0x0A);
|
||
|
|
EXPECT_EQ(imgRes->data[6], 0x1A);
|
||
|
|
EXPECT_EQ(imgRes->data[7], 0x0A);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(PageRenderTest, InvalidPageIndexReturnsPageOutOfBounds) {
|
||
|
|
SKIP_IF_NO_PDFIUM();
|
||
|
|
auto path = getCorpusPath("basic", "hello_world.pdf");
|
||
|
|
if (!std::filesystem::exists(path)) {
|
||
|
|
GTEST_SKIP() << "hello_world.pdf not found in corpus.";
|
||
|
|
}
|
||
|
|
|
||
|
|
auto docRes = PdfDocument::loadFromFile(path.string());
|
||
|
|
ASSERT_TRUE(docRes.has_value());
|
||
|
|
|
||
|
|
auto pageRes = (*docRes)->getPage(1);
|
||
|
|
ASSERT_FALSE(pageRes.has_value());
|
||
|
|
EXPECT_EQ(pageRes.error(), EngineError::PageOutOfBounds);
|
||
|
|
|
||
|
|
auto pageResNeg = (*docRes)->getPage(-1);
|
||
|
|
ASSERT_FALSE(pageResNeg.has_value());
|
||
|
|
EXPECT_EQ(pageResNeg.error(), EngineError::PageOutOfBounds);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(CoordinateTransformTest, PageToDeviceAndBackRoundtrip) {
|
||
|
|
SKIP_IF_NO_PDFIUM();
|
||
|
|
auto path = getCorpusPath("basic", "hello_world.pdf");
|
||
|
|
if (!std::filesystem::exists(path)) {
|
||
|
|
GTEST_SKIP() << "hello_world.pdf not found in corpus.";
|
||
|
|
}
|
||
|
|
|
||
|
|
auto docRes = PdfDocument::loadFromFile(path.string());
|
||
|
|
ASSERT_TRUE(docRes.has_value());
|
||
|
|
auto pageRes = (*docRes)->getPage(0);
|
||
|
|
ASSERT_TRUE(pageRes.has_value());
|
||
|
|
|
||
|
|
auto page = *pageRes;
|
||
|
|
|
||
|
|
int deviceW = 1024;
|
||
|
|
int deviceH = 768;
|
||
|
|
std::vector<int> rotations = {0, 90, 180, 270};
|
||
|
|
|
||
|
|
std::vector<Point2D> testPoints = {
|
||
|
|
{0.0, 0.0},
|
||
|
|
{50.0, 50.0},
|
||
|
|
{100.0, 200.0},
|
||
|
|
{page->width() / 2.0, page->height() / 2.0},
|
||
|
|
{page->width() - 10.0, page->height() - 10.0}
|
||
|
|
};
|
||
|
|
|
||
|
|
for (int rotation : rotations) {
|
||
|
|
for (const auto& pt : testPoints) {
|
||
|
|
auto devPt = page->pageToDevice(pt, deviceW, deviceH, rotation);
|
||
|
|
auto pagePt = page->deviceToPage(devPt, deviceW, deviceH, rotation);
|
||
|
|
|
||
|
|
EXPECT_NEAR(pt.x, pagePt.x, 2.0) << "Failed roundtrip for x at rotation " << rotation;
|
||
|
|
EXPECT_NEAR(pt.y, pagePt.y, 2.0) << "Failed roundtrip for y at rotation " << rotation;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(TextExtractionTest, ExtractSimpleText) {
|
||
|
|
SKIP_IF_NO_PDFIUM();
|
||
|
|
auto path = getCorpusPath("basic", "hello_world.pdf");
|
||
|
|
if (!std::filesystem::exists(path)) {
|
||
|
|
GTEST_SKIP() << "hello_world.pdf not found in corpus.";
|
||
|
|
}
|
||
|
|
|
||
|
|
auto docRes = PdfDocument::loadFromFile(path.string());
|
||
|
|
ASSERT_TRUE(docRes.has_value());
|
||
|
|
auto pageRes = (*docRes)->getPage(0);
|
||
|
|
ASSERT_TRUE(pageRes.has_value());
|
||
|
|
|
||
|
|
auto textRes = (*pageRes)->extractText();
|
||
|
|
ASSERT_TRUE(textRes.has_value());
|
||
|
|
|
||
|
|
std::string text = *textRes;
|
||
|
|
EXPECT_NE(text.find("Hello"), std::string::npos);
|
||
|
|
EXPECT_NE(text.find("world"), std::string::npos);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(TextExtractionTest, ExtractUtf8ExtendedText) {
|
||
|
|
SKIP_IF_NO_PDFIUM();
|
||
|
|
auto path = getCorpusPath("fonts", "latin_extended.pdf");
|
||
|
|
if (!std::filesystem::exists(path)) {
|
||
|
|
GTEST_SKIP() << "latin_extended.pdf not found in corpus.";
|
||
|
|
}
|
||
|
|
|
||
|
|
auto docRes = PdfDocument::loadFromFile(path.string());
|
||
|
|
ASSERT_TRUE(docRes.has_value());
|
||
|
|
auto pageRes = (*docRes)->getPage(0);
|
||
|
|
ASSERT_TRUE(pageRes.has_value());
|
||
|
|
|
||
|
|
auto textRes = (*pageRes)->extractText();
|
||
|
|
ASSERT_TRUE(textRes.has_value());
|
||
|
|
|
||
|
|
std::string text = *textRes;
|
||
|
|
EXPECT_FALSE(text.empty());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(TextExtractionTest, ExtractTextWithBounds) {
|
||
|
|
SKIP_IF_NO_PDFIUM();
|
||
|
|
auto path = getCorpusPath("basic", "hello_world.pdf");
|
||
|
|
if (!std::filesystem::exists(path)) {
|
||
|
|
GTEST_SKIP() << "hello_world.pdf not found in corpus.";
|
||
|
|
}
|
||
|
|
|
||
|
|
auto docRes = PdfDocument::loadFromFile(path.string());
|
||
|
|
ASSERT_TRUE(docRes.has_value());
|
||
|
|
auto pageRes = (*docRes)->getPage(0);
|
||
|
|
ASSERT_TRUE(pageRes.has_value());
|
||
|
|
|
||
|
|
auto boundsRes = (*pageRes)->extractTextWithBounds();
|
||
|
|
ASSERT_TRUE(boundsRes.has_value());
|
||
|
|
|
||
|
|
const auto& glyphs = *boundsRes;
|
||
|
|
ASSERT_FALSE(glyphs.empty());
|
||
|
|
|
||
|
|
bool found_hello = false;
|
||
|
|
for (const auto& glyph : glyphs) {
|
||
|
|
EXPECT_FALSE(glyph.text.empty());
|
||
|
|
if (glyph.text != " " && glyph.text != "\r" && glyph.text != "\n" && glyph.text != "\t") {
|
||
|
|
EXPECT_GT(glyph.w, 0.0);
|
||
|
|
EXPECT_GT(glyph.h, 0.0);
|
||
|
|
}
|
||
|
|
EXPECT_GT(glyph.fontSize, 0.0);
|
||
|
|
if (glyph.text == "H" || glyph.text == "e" || glyph.text == "l" || glyph.text == "o") {
|
||
|
|
found_hello = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
EXPECT_TRUE(found_hello);
|
||
|
|
}
|
||
|
|
}
|