#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 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(ptWidth * scale); int expectedH = static_cast(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 rotations = {0, 90, 180, 270}; std::vector 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); } }