31static void safeWriteBytes(
const std::shared_ptr<core::ports::diagnostics::IDiagnostics>& debugger,
const std::string& path,
const std::vector<uint8_t>& data) {
32 if (!debugger || !debugger->enabled())
return;
34 debugger->writeBytes(path, data);
42 double pageWidthPts = 0.0, pageHeightPts = 0.0;
44 auto rect = page->page_rect();
45 pageWidthPts = rect.width();
46 pageHeightPts = rect.height();
48 pageWidthPts = 595.2; pageHeightPts = 841.8;
56 auto tbl = page->text_list();
57 for (
const auto& tb : tbl) {
61 auto ba = u.to_utf8();
62 if (ba.size() > 0 && ba.data() !=
nullptr)
63 te.
text.assign(
reinterpret_cast<const char*
>(ba.data()), ba.size());
64 }
catch (...) { te.
text.clear(); }
68 try { te.
x = b.x(); te.
y = b.y(); te.
width = b.width(); te.
height = b.height(); }
70 try { te.
x = b.left(); te.
y = b.top(); te.
width = b.right() - b.left(); te.
height = b.bottom() - b.top(); }
80 j[
"dpi_x"] = dpi; j[
"dpi_y"] = dpi;
81 j[
"page_width_pts"] = pageWidthPts; j[
"page_height_pts"] = pageHeightPts;
82 double scaleX = dpi / 72.0;
double scaleY = dpi / 72.0;
83 json tj = json::array();
87 it[
"bbox_pts"] = { te.x, te.y, te.width, te.height };
88 it[
"bbox_px"] = {
static_cast<int>(std::round(te.x * scaleX)),
static_cast<int>(std::round(te.y * scaleY)),
static_cast<int>(std::round(te.width * scaleX)),
static_cast<int>(std::round(te.height * scaleY)) };
91 j[
"text_elements"] = tj;
92 j[
"embedded_images"] = json::array();
95 if (debugger && debugger->enabled()) {
96 std::string stem = std::to_string(pageIndex + 1);
110 std::vector<uint8_t> out;
111 if (!img.is_valid())
return out;
113 const int w = img.width();
114 const int h = img.height();
115 if (w <= 0 || h <= 0)
return out;
117 const int stride = img.bytes_per_row();
118 unsigned char* data =
reinterpret_cast<unsigned char*
>(img.data());
119 if (!data)
return out;
121 cv::Mat rgb(h, w, CV_8UC3, data,
static_cast<size_t>(stride));
123 cv::cvtColor(rgb, bgr, cv::COLOR_RGB2BGR);
125 std::vector<int> params;
126 params.push_back(cv::IMWRITE_PNG_COMPRESSION);
129 cv::imencode(
".png", bgr, out, params);
143 const std::filesystem::path& outputDir,
144 const std::string& uniqIdPrefix,
145 const std::string& filePrefix,
146 std::shared_ptr<core::ports::diagnostics::IDiagnostics> debugger,
147 std::shared_ptr<std::atomic<bool>> cancelFlag) {
148 std::vector<ports::RenderedPage> result;
149 if (!std::filesystem::exists(pdfPath))
throw std::runtime_error(
"PDF file does not exist: " + pdfPath);
151 std::unique_ptr<poppler::document> doc(poppler::document::load_from_file(pdfPath));
152 if (!doc)
throw std::runtime_error(
"Failed to open PDF: " + pdfPath);
157 int numPages = doc->pages();
158 for (
int i = 0; i < numPages; ++i) {
159 if (cancelFlag && cancelFlag->load())
break;
160 std::unique_ptr<poppler::page> page(doc->create_page(i));
169 const std::filesystem::path& outputDir,
170 const std::string& uniqIdPrefix,
171 const std::string& filePrefix,
172 std::shared_ptr<core::ports::diagnostics::IDiagnostics> debugger,
173 std::shared_ptr<std::atomic<bool>> cancelFlag) {
174 std::vector<ports::RenderedPage> result;
175 if (!std::filesystem::exists(pdfPath))
throw std::runtime_error(
"PDF file does not exist: " + pdfPath);
177 std::unique_ptr<poppler::document> doc(poppler::document::load_from_file(pdfPath));
178 if (!doc)
throw std::runtime_error(
"Failed to open PDF: " + pdfPath);
180 poppler::page_renderer renderer;
181 renderer.set_render_hint(poppler::page_renderer::antialiasing,
true);
182 renderer.set_render_hint(poppler::page_renderer::text_antialiasing,
true);
183 renderer.set_image_format(poppler::image::format_enum::format_rgb24);
185 int numPages = doc->pages();
188 const bool writeFiles = !outDir.empty();
189 const std::string base =
prefix_base(uniqIdPrefix, filePrefix.empty() ? std::string(
"poppler_render") : filePrefix);
191 for (
int i = 0; i < numPages; ++i) {
192 if (cancelFlag && cancelFlag->load())
break;
193 std::unique_ptr<poppler::page> page(doc->create_page(i));
196 poppler::image img = renderer.render_page(page.get(), dpi, dpi);
197 if (!img.is_valid())
continue;
207 std::ostringstream fname;
208 fname << outDir.string() <<
"/" << base <<
"_page" << (i + 1) <<
".png";
210 if (!img.save(rp.
imagePath,
"png"))
throw std::runtime_error(
"Failed to save image: " + rp.
imagePath);
213 if (debugger && debugger->enabled() && !rp.
imageBytes.empty()) {
214 std::string stem = base + std::string(
"_page") + std::to_string(i + 1);
218 result.push_back(std::move(rp));
static std::vector< core::ports::pdf_rendering::RenderedPage > renderDocument(const std::string &path, double dpi, const std::filesystem::path &outputDir=std::filesystem::path(), const std::string &uniqIdPrefix="", const std::string &filePrefix="", std::shared_ptr< core::ports::diagnostics::IDiagnostics > dbg=nullptr, std::shared_ptr< std::atomic< bool > > cancelFlag=nullptr)
Extracts document metadata and page text elements from a PDF file.
static std::vector< core::ports::pdf_rendering::RenderedPage > extractDocumentMeta(const std::string &path, double dpi, const std::filesystem::path &outputDir=std::filesystem::path(), const std::string &uniqIdPrefix="", const std::string &filePrefix="", std::shared_ptr< core::ports::diagnostics::IDiagnostics > dbg=nullptr, std::shared_ptr< std::atomic< bool > > cancelFlag=nullptr)
Extracts page metadata without rendering the page bitmap.
std::vector< uint8_t > imageBytes
std::vector< TextElement > textElements